今日の業務の振り返り(2021/12/23)
今日の業務での学び
今やっているタスクの進捗が思ったより遅い
タスクをこなす上で遅くなってしまう原因をbreak downしてみる
- 技術の知識不足(単純にnext.jsとかの知識)
- 公式のドキュメントを見てできることを把握しておく
- 手っ取り早くは似たような実装をしているものを探してくる
- 実際の現場の運用の理解不足(plexjob特有の書き方などの知識)
- 自分で書いていない部分を見て、さっと全体像を把握しておく
- 要件を正しく把握できていない
- あいまいなところは聞く
- 曖昧表現を避ける(いい感じにとか、〜のサイトみたいにとか)
- 不確実性が高いタスクの状態で実装に移ってしまっている
- 最初にタスクが来た時に不確実性が高い状態でタスクの分解・設計をしているが、実装していき解像度が上がってきたらその都度タスクの再分解・再設計を行う
- PRを細かくすることで、レビュワーも楽になる
今回の原因
まずタスクはnext×typescript×graphql×rubyで書かれているアプリの検索機能の拡張(複数検索(掛け合わせ検索)をできるようにする。) 今回は4の部分が大きかった。 複数検索の実装はある程度やること頭に浮かんでいたが、やったことなかったので不確実性が高い状態での設計となっていた。 そのため、最初は複数検索(2つ、3つ)みたいな分割しかできていなく、かなりあやふやな設計になってしまっていた。
複数検索(2つ、3つ)だと検索条件が一つ増えただけで似た実装をするように見えるが、実際は2つの複数検索の場合、都道府県×市区町村or特徴と2つ目に入ってくるものがどちらかわからず、ビューもクエリも動的に対応する必要があった。 反対に3つの場合は確実に都道府県、市区町村、特徴が入ってくるので動的に実装する必要はない。 このように2つと3つの場合で実装が大きく変わるのだが、今回のように単純な複数検索(2つ、3つ)みたいな分解の仕方だと、似たような処理を実装するから共通化できるかなという考えのもと実装するため誤った前提で考えてしまい、そうにか共通化しようと無駄に時間がかかってしまった。
対策
今回の問題は、『もうコード書いているのにもう一度設計考えるのはめんどくさいなと』という思いから再設計をせずに進めてたことに起因した。 最初の設計なんて一回やったことある実装じゃない限り間違っていたり曖昧な部分が多いわけで、少しでも何かわかれば再度設計を考え直す必要がある。 とりあえず、次回出勤からはその日の終わりに、今日実装していてわかったことの列挙と再設計が必要かの検討を行うようにする。
pythonで多次元配列の要素に対して四則演算した時の意図せぬ挙動
numpyを使わずに多次元配列を作って、その要素に対して四則演算してみたら
a = [[0] * 5] * 5 a[0][0] += 1 print(a) # out:[[1, 0, 0, 0, 0], [1, 0, 0, 0, 0], [1, 0, 0, 0, 0], [1, 0, 0, 0, 0], [1, 0, 0, 0, 0]]
みたいになった
想定としてはこんな感じ↓
# out:[[1, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
どうやらpythonで初期化をする時に*
を使うとポインタを複製してしまうらしい。
なので、こんな感じで一つ一つ初期化したらうまくいったよというメモ
b = [ [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], ] b[0][0] += 1 print(b) # out:[[1, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
MVPを勘違いしていた話
最優秀選手ではなくMinimum Viable Productの略でした。
というわけではなく、最近アルバイト先で新規事業開発に携わっているのですが、そこでMVPの考え方がすごく狭い視点で捉えていたなという気づきがありました。 MVPについての解説記事でないので悪しからず。
そもそもMVPという言葉の定義はwikipediaによると
実用最小限の製品(じつようさいしょうげんのせいひん、Minimum Viable Product、MVP)は、初期の顧客を満足させ、将来の製品開発に役立つ有効なフィードバックや実証を得られる機能を備えた製品のバージョンを指す。
サービス初期にそのプロダクトに需要があるのかを検証するための手法です。
どこを狭い視点で捉えていたのかというと、そもそもプロダクトの価値を提供できればいいのであって、裏がどうなっていても関係ないという点です。 自分は「最低限のメインとなる機能の実装は行い、それ以外の副次的な機能は後から実装していく」ことがMVPだと考えていました。
実際はそうではなく、最低限のメインとなる機能が実装されていようが、その部分すら人力であろうがユーザーに価値を提供することができれば良く、むしろプロダクトマーケットフィットの検証が行われていない段階で開発を行うのは無駄なコストをかけてしまうリスクがあり、避けるべきだと感じました。
そもそも人力では行えなかったりすることもあるので、MVPの定義はプロダクトによって変わるとは思いますが、自分はエンジニアというすごく狭い視点でMVPを捉えていたんだなと改めて勉強になりました。
goでクイックソート
ソートの勉強をしていたら、クイックソートがかなり早いらしいのでgoで実装してみた。
ソースコード⬇︎
package main import "fmt" func quickSort(array []int) []int { var right []int var left []int // 分割できなくなった時([1]みたいな)はそのまま返す if len(array) <= 1 { return array } // 基準値を設定、今回はとりあえず先頭の値。中央値にするのが正しいやり方だと思う。 baseValue := array[0] // 基準値と同じになった値の数も数える baseValueCount := 0 // forで一つずつ取り出す。 for _, value := range array { // 基準値と比較して大きかったらrightに、小さかったらleftに、一緒だったらbaseValueCountを増やす。 if value < baseValue { left = append(left, value) } else if value > baseValue { right = append(right, value) } else { baseValueCount++ } // 再帰的に呼び出していく分割できなくなるまで呼び出す left = quickSort(left) right = quickSort(right) } // バラバラになってる配列をくっつける。 //基準値の配列を作る var baseValueArray []int for i := 0; i < baseValueCount; i++ { baseValueArray = append(baseValueArray, baseValue) } //展開して繋げる returnArray := append(left, baseValueArray...) returnArray = append(returnArray, right...) return returnArray } func main() { inputArray := []int{5, 3, 1, 8, 6, 2, 4, 9, 7} fmt.Println(inputArray) outputArray := quickSort(inputArray) fmt.Println(outputArray) }
結果⬇︎
% go run quickSort.go [5 3 1 8 6 2 4 9 7] [1 2 3 4 5 6 7 8 9] % go run quickSort.go [2 1 3 4 2 6 1 7 1 4 5] [1 1 1 2 2 3 4 4 5 6 7]
goで書くと最後結合する部分が汚いのでもう少し綺麗に書きたい。 クイックソートは早いけど再帰で処理するため、メモリ消費が大きいらしい。 次はベンチマークとって他のソートとの速度の違いを比べてみたい。
2020年の振り返り
twitterの方々が2020年の振り返りをしているのを見て、また履歴書書く時にどうせ振り返る必要があるのでこの機会に文字に残しておこうと考え書きました。
1月
- スタートアップでのLP制作
- 専門学校の卒業制作
- インターンの面接
この時はスタートアップでのバイトを始めてから半年くらいで、色々提案とかも好きにやらしてもらってました。 もともとcv率は高かったのでそれをキープしたまま、取る情報量を増やすという方針で他サービスのLPを参考にしながらいいところだけ組み込んでいくみたいなことをしていました。
学校の方は卒業制作を作ってました。前年の夏頃から自然言語処理の勉強も少ししており、自然言語処理を使った検索エンジンの開発を行なっていました。 すごそうに聞こえますが、今考えてみると事前学習済みのモデルにデータを突っ込むだけで特にすごいことはしていませんね。当時はわからないながら期限に間に合わせようと必死に頑張ってました。
実際に作ったもの⬇︎ github.com
2月
- 初インターンに参加
この時は卒業制作とインターンが被ってしまったので、資料だけ作って発表は他のメンバーにお任せしてインターンに行ってました。 サイバーさんのインターンでは初めて同期のエンジニアにあったり、レビューをもらったりと色々経験できました。 詳細はブログに書いているので興味あればどうぞ。⬇︎ na7110.hatenablog.com
3月
- 逆求人に参加
- サマーインターンの早期選考
3月末に初めて逆求人に参加しました。 あんまりよく考えずに2日連続で参加したら、17社くらいと面談することになってヘトヘトになったのを覚えています。 面談する中で自分の強みとか弱みとか見えてきて、サマーインターンに向けての対策がうてたのでこの時期に参加したのはよかったです。
このタイミングでシェアハウスも始めました。 インターン先の社長+コンサルやってる人+専門学生という謎メンバーでのシェアハウスでした(現在も継続中) 共有スペースであった時にビジネスの話なども聞けるのでかなりいい福利厚生になっています_φ( ̄ー ̄ )
4月
- 大学入学
- 新規事業開発
大学に入学しました。 ただコロナで実際に授業が始まったのは5月とかからだったので、予習とかしてました。
アルバイト先では、新規事業開発が始まり立候補してそのプロジェクトでのリーダを任せてもらいました。
その後、マネジメント部分だけ他の人にお願いすることになったのですが、当時は自分の不甲斐なさがとても悔しかったです。 そこから学ぶことも多くあったので結果としてこの経験はよかったなと思います。
5月・6月・7月
- 大学の授業開始
- サマーインターンの選考
大学の授業が難しくてついていくのに必死でした。 これまで専門学校でやってきたことがいかに簡単で、大学生すげえってなりました。
アルバイト先はエンジニアリーダーみたいな人がいなくなってしまい、自分がエンジニアリーダーになりました。 相変わらず新規事業をやっていたのですが、エンジニアは開発以外の能力が必要なことをひどく感じました。 これまではチーム開発と行っても指示される側が基本だったので、これもまたいい経験になりました。
ちなみにこの時期は授業が終わってからアルバイト先の開発を行なっており、 朝〜夕:学校 夜〜朝方:バイト先の開発 みたいなことをしていました。 こんなに頑張っているのに時給が500円くらいということで精神的にかなり追い詰められ、お金は精神を安定させる上で超重要だということを実感しました。(後からこのことを話したら、別の月で調整してくれました。)
8月
- ボヤージグループさんのサマーインターンに参加
新規事業開発も落ち着いて、学校も夏休み前でテストのみでだいぶ楽になりました。
ボヤージグループさんのサマーインターンにも参加してました。
その時のブログ⬇︎ https://na7110.hatenablog.com/entry/2020/12/24/024623?_ga=2.229996314.765368622.1609850807-643877763.1608745389na7110.hatenablog.com
ちょうどこの時期、サマーインターンの選考や新規事業開発の中で自分は技術力が足りていないと感じ、新しいバイトの面接も受けていました。
9月
- ブレインパッドさん ・ヤフーさん・メドレーさんのサマーインターンに参加
- 新しいバイト開始
色々な会社さんの短期インターンに参加してました。 どれくらい書いていいのかわからないので端折りますが、普段体験できないことが多くいい経験になりました。 9月の後半からは新しいところでのアルバイトも始めました。 技術力を伸ばしたかったので、エンジニアが多くレビューなどもしっかりと行なってもらえるところでアルバイトをし始めました。
10月
- 本選考開始
本選考が始まったり、お姉ちゃんの結婚式に行ったり。 毎週面接していた気がします。
11月・12月
- インフラ系の秋インターン
- バイト先のスタートアップで色々
sunriseというボヤージさんの秋インターンに参加しました。 バイト先では新規事業くらい大きなことを提案からやらしてもらっているので終わったら何か記事とかにできたらと思っています。
というような1年でした。 学びの環境を作るという点ではうまく回せていたと思いますし、サマーインターンで出会った友達もいっぱいできたのでいい一年だったと思います。
if文のORについて。
javascriptでif文を書いてた時の動作でORを使った時に前が条件で結果が確定している際は後ろの判定が行われなかった。
追記:Pythonでも試したら同じだったのでJSとかに関係なくプログラミング言語全般に言えそう。
const function1 = () => { console.log('function1') return true } const funtion2 = () => { console.log('function2') return true } if (function1() || funtion2()) { console.log('pass') }
この場合function1は出力されるが、その際にtrueを返してそれ以上の判定は不要なのでfunction2は出力されずにpassが出力される。
ちなみにANDの場合はもちろん両方判定する。
よく考えれば当たり前だけど、実際に遭遇したら 🤔 となったのでφ(・・