2023年振り返り
ひっさびさにかく。
Stockr開発メンバーと一緒にふりかえり Advent Calendar 2023の24日目!だいぶ遅くなってしまってすみません。
話すトピック
会社辞めた
会社にジョインしてからは、プロダクトがない状態からプロダクトを作って、どうグロースさせるか考えたり、採用やチーム作り、技術負債とのバランスを向き合い続けてきたりと思い返すと色々な経験をしていたなーと。もっともっと会社を成長できなかったのは残念だし、土台の一部分でも貢献できたのかなーなんては当時思っていたが、まだまだできたことありすぎたなと自分の不甲斐なさに最近思うことはたくさんあるけどまたどこかでまとめる。
フリーランスになった
会社を辞めてからは、フリーランスになって色々なお手伝いをしてみている。
- PM
- データ基盤/CRMの開発
- 組織開発、プロダクトチーム作り、 育成
- 生成AIを使ったプロダクト開発
この中だと特に組織開発はCTOしていた時に一番好きだった領域で、どういうチームにして、どういうふうに育成しようか・・は自分のWant to(やりたいこと)にやんわりと近くて、もっとやっていきたいなと思う。
コーチングを学び始めた
組織開発の支援をしている会社の方から誘われたコーチングスクールをきっかけに本格的にコーチングを学び始めている。 その時までに印象にあったコーチングは、コーチ側の言葉でゴール設定したり、目標管理したりするものが多く、あとは少しカウンセリングっぽいと思っていたが、今習い始めたところは本当にやりたいことを見つける手伝いをし、現状の外へゴール設定をしていくやり方を主にとっていて、自分がやってみたいなとおもうやり方ですごく楽しい。
何年前かによんだ、サピエンス全史に書かれている人間が優れているのは「虚構を信じる力」の能力と書かれていて、とても衝撃を受けてその後もずっと考えていた。ソーシャルメディアの生態系という本では、SNS全体を「ソーシャル・オーガニズム」という造語で、一つの有機体とみなし、ミームによって伝播し、どういう変貌を遂げていくかが書かれている。今なぜこの話をするかというと、自分が7年前くらいから「世界一のプロダクトを作る」ということを目標にやっていたが、「世界一のプロダクトを作る」ことというより、「世界一のプロダクトを作る環境」が好きで、その環境こそが皆が虚構を信じていていたり、一つの有機体のようなチームになっていて、そのプロセスにかなり興味が湧いていたからだ。実際、フリーランスになっても、スタートアップの会社と話をする時に、代表や役員がどれだけ自分たちがやっていることを信じているかをよく見ていて、その虚構を信じるプロセスやそれにかける情熱が自分の中でかなり高い優先度になっていた。
コーチングから話がだいぶ飛んだように思えるが、この虚構(見えない何かであり、信念も近しいものだと思っている)をどう見つけ出すか、信じさせるかにおいては似ているんじゃないかなーと思っている。 プロダクトや組織のリーダーシップを取る上で、自分で虚構を生み出し、信じるというプロセスを得ないと、うまく人を巻き込めないが、それを他の人にやってあげられるなんて本当にすごいことだ。似たようなことを言うけど、やらせるのではなくて、自分がやっているという感覚にさせることだ。
そんなこんなで、コーチングはまずは自分を変えれないと相手にも同じことができないので、自分が本当にやりたいことを見つけ、それを本気で信じるというプロセスを今やっているが、このプロセス自体が面白くて、今はこれがやりたいことに近い。
TensorFlow2.0とTensorFlowHubを使ってみる
TensorFlow2.0
のbeta
が出てたので、試してみる。
TensorFlowとは?
TensorFlow(テンソルフロー)
とは、Google
が開発しているOSSの機械学習のライブラリ。Googleはもちろんアルファ碁で有名になったDeepMind
でも使われている。
対応言語は、Python
, C
, C++
, Java
, Go
などがある。
今回は使わないが、Mobile
にも入れることができたりする。
また、Tensor(テンソル)
については、以下の記事が参考になった。
mathcommunication.hatenablog.com
とはいっても難しくてあまり理解できなかったので、以下の記事がFlow(フロー)
部分も含めて、ざっくりの理解ができた。
ようは、テンソルとは多次元配列のこといっているとの理解で一旦とどめて置く。
TensorFlow1.0と2.0の違い
以下の記事がいいまとめすぎて、理解しやすかった。
PyTrouch
をだいぶ意識したバージョンアップみたい
TensorFlow2.0のインストール方法
pip install tensorflow==2.0.0-beta0
さっそくエラー
ERROR: Cannot uninstall 'wrapt'. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall
wrapt
周りが怪しいので、uninstall
すると無事インストールできた。
pip install -U --ignore-installed wrapt enum34 simplejson netaddr
ニューラルネットワークのチュートリアル
以下の記事を行なった。エラーなしで動くので、ここでは特に何もしない。
ただ、とりあえず具動かせるが、理解が足りてない部分を以下を参考とした。
ついでに、CNNも
softmax
TensorFlowHubのインストール
公式のチュートリアルを参考に動かしてみる
!pip install "tensorflow_hub==0.4.0" !pip install "tf-nightly"
つづいて、
import tensorflow as tf import tensorflow_hub as hub tf.enable_eager_execution() module_url = "https://tfhub.dev/google/tf2-preview/nnlm-en-dim128/1" embed = hub.KerasLayer(module_url) embeddings = embed(["A long sentence.", "single-word", "http://example.com"]) print(embeddings.shape) #(3,128)
ここでエラー
AttributeError: module 'tensorflow' has no attribute 'enable_eager_execution'
TF2.0だとeager-modeがデフォルトtrueなので、コメントアウト
// tf.enable_eager_execution()
1.x => 2.x のマイグレーション
エラーの一つを紹介すると
AttributeError: module 'tensorflow' has no attribute 'logging'
TF2系なのでloggingがないっぽいので、
tf.logging => tf.compat.v1.loggingに変更で動く
tf.gfile => tf.io.gfileなど
基本はcompat.v1つければよさそう
終わりに
ざっくりと駆け足でTensorFlow2.x
を使って見た。
2系らしい動きはまだできてないので、次は深掘りする。
GoでAtCoder(競技プログラミング)やってみる
最近Go
を勉強して行く上で、アルゴリズムの勉強も同時にしながらできないかなーと思い、競技プログラミングというアルゴリズムのコンテストはどっちも満たせると信じ、始めて見た。
今回はAtCoderと言われる、日本製のコンテストサイトでやってみる。
以下の方が代表で、元々世界のプログラミングコンテストのランカーだったのか、すごい。
twitter.com
とりあえず読んでみるべき記事
どう進めたらいいのかはもうここで完結しそうなくらいよかった。 qiita.com
登録したら上記の問題をコンテスト形式で用意してくれるのでそれをやったほうがいい。
Goで書いてみる
https://github.com/kzkohashi/at_coder_practice
全然まだまだ途中だけど、自分なりの答えはgithub
にあげている。
groutine
とか使えば早くなるんだろうな。今はこなすことに集中。
テクニックみたいなやり方をまとめてくれていてすごく助かっている記事。
qiita.com
まだ爆速をもとめられていないが、参考になりそうな記事。@hama_duさんや。
感想
少ししかまだ始められてないが、すごく良さそうな印象だった。
採用とか社内のエンジニアのレベルアップに良いな〜とも思うので、継続してやっていこ。
GoroutineとChannelについて学ぶ
前回Go
のインタフェースについて書いた。
kzkohashi.hatenablog.com (アイキャッチが更新されてない・・)
今回はGo
の真髄とも言える、ゴルーチンとチャネルによる並行処理(Concurrent)について学んでいく。
並行(Concurrent)処理と並列(Parallel)処理
間違えやすいのだが、並行処理は並列処理と概念的に異なる。
こちらの記事がわかりやすかったので、引用させていただく。
Concurrent(並行)は「複数の動作が、論理的に、順不同もしくは同時に起こりうる」こと Parallel(並列)は、「複数の動作が、物理的に、同時に起こること」
引用: freak-da.hatenablog.com
並行は1人の人が複数の仕事をし、並列は複数の人が複数の仕事をしている状態だ。
とはいっても、並行処理は擬似並列ともいえるので、日本語的には「並列処理」を使っても問題ないと思う。
この辺りも面白かった。
興味がある人は以下を読むと良さそう。
自分は近々届くので、また別途まとめたい。
Goroutineで並行処理を行う。
Goroutine
の実装は簡単で、関数の前にgo
をつけるだけだ。
これだけで並行処理がとりあえずは実装できる。
func say(s string) { for i := 0; i < 5; i++ { time.Sleep(100 * time.Millisecond) fmt.Println(s) } } func main() { go say("world") say("hello") }
引用: https://go-tour-jp.appspot.com/concurrency/1
並行処理のプログラミングをする際は、main
での処理とは別に処理が走ってしまうので、Channel
をうまく使って制御したり、Sleep
で待つという方法もある。
Sleep
は処理が終わる終わらないに限らず、その時間しかまたないのでよくない。
Channelを使う
A Tour Go
をやってもあまり理解しなかったが、以下の記事がよかったのでこちらを見た方がいい。
channel
は値をやり取りをするためのキューみたいなもんだ。しかも、goroutine
(スレッド)間で値の受け渡しを安全にできるので、とても簡単に扱える。
func main() { // 容量2のchannel型で作成 c := make(chan string, 2) // データを入れる c <- "hello" // データを入れる c <- "hello2" // c <- "hello3" 容量2のため3個目をいれたらエラー // 最初に入れたデータをchannelから取り出す fmt.Println(<-c) fmt.Println(<-c) // fmt.Println(<-c) 3つ目はない c = make(chan string, 1) c <- "world" fmt.Println(<-c) }
Exercise: Web Crawler を解く
A Tour Go
の最後に、goroutine
の問題があったので解いて見た。
go-tour-jp.appspot.com
package main import ( "fmt" ) type Fetcher interface { // Fetch returns the body of URL and // a slice of URLs found on that page. Fetch(url string, resultUrl ResultUrl) (body string, urls []string, err error) } type ResultUrl struct { v map[string]int } // Value returns the current value of the counter for the given key. func checkUrl(c *ResultUrl, key string) bool { return c.v[key] == 1 } // Crawl uses fetcher to recursively crawl // pages starting with url, to a maximum of depth. func Crawl(url string, depth int, fetcher Fetcher, c ResultUrl, quit chan bool) { // TODO: Fetch URLs in parallel. // TODO: Don't fetch the same URL twice. // This implementation doesn't do either: if depth <= 0 { quit <- true return } if checkUrl(&c, url) { quit <- true return } body, urls, err := fetcher.Fetch(url, c) if err != nil { fmt.Println(err) quit <- true return } fmt.Printf("found: %s %q\n", url, body) quit2 := make(chan bool) for _, u := range urls { go Crawl(u, depth-1, fetcher, c, quit2) <-quit2 } quit <- true return } func main() { c := ResultUrl{v: make(map[string]int)} quit := make(chan bool) go Crawl("https://golang.org/", 4, fetcher, c, quit) <-quit } // fakeFetcher is Fetcher that returns canned results. type fakeFetcher map[string]*fakeResult type fakeResult struct { body string urls []string } func (f fakeFetcher) Fetch(url string, c ResultUrl) (string, []string, error) { c.v[url] = 1 if res, ok := f[url]; ok { return res.body, res.urls, nil } return "", nil, fmt.Errorf("not found: %s", url) } // fetcher is a populated fakeFetcher. var fetcher = fakeFetcher{ "https://golang.org/": &fakeResult{ "The Go Programming Language", []string{ "https://golang.org/pkg/", "https://golang.org/cmd/", }, }, "https://golang.org/pkg/": &fakeResult{ "Packages", []string{ "https://golang.org/", "https://golang.org/cmd/", "https://golang.org/pkg/fmt/", "https://golang.org/pkg/os/", }, }, "https://golang.org/pkg/fmt/": &fakeResult{ "Package fmt", []string{ "https://golang.org/", "https://golang.org/pkg/", }, }, "https://golang.org/pkg/os/": &fakeResult{ "Package os", []string{ "https://golang.org/", "https://golang.org/pkg/", }, }, }
すでにクロールしたURL
を判定する処理に、sync.Mutex
を最初入れてたが、入れなくてもできたのでちょっと怪しい。
キモとしては、channel
型のquit
に値を入れ、<-quit
でgoroutine
の処理を待つことができる。
終わりに
Go
の勉強を駆け足でやってみた。
最初は意味がわからなかったが、毎日少しずつ見ていくと慣れていくもんだな。
次からはGo
でAPI
サーバー作ることをしようかな。
Goのインタフェースについて学ぶ
以前初めてGo
に触った感想をまとめたが、インタフェースについては書いてなかったのでまとめる。
kzkohashi.hatenablog.com
インタフェースの定義
A Tour of Go
の内容をベースに話していく。
go-tour-jp.appspot.com
インターフェースの定義は以下のように、type xxx interface
で作成し、その中に実装するメソッドを定義する。
ここでは、Abser
インターフェースにAbs
関数を定義している。
type Abser interface { Abs() float64 }
ややこしいんだけど、interface{}
型とは全く違う概念みたいなので、注意しとく。
interface{}
型はint
やbool
など全ての値を取りうる型とのこと。
var a interface{} a = 1 // int a = 1.0 // float a = "あ" // string
こちらが参考になった。ただ、ゆるく使うにしてもどう使うんだろう。
初心者に送りたいinterfaceの使い方[Golang] – Since I want to start “blog” that looks like men do, I do start. – Medium
インタフェースの実装
次にインタフェースを実装する。
float
型のMyFloat
を定義し、先ほどインターフェスで定義したAbs
メソッドを実装する。
type MyFloat float64 func (f MyFloat) Abs() float64 { if f < 0 { return float64(-f) } return float64(f) }
ちゃんと理解していなかったんだが、type
は構造体で使うというより、指定した型を別名でつけれるようものとのこと。
上記のMyFloat
はリテラル型float
の別名として、新しい型として定義されたものだ。
言われてみると当たり前な気はするけど、忘れないようにと。以下の記事がとても参考になった。
また、以下のようにstruct
にもAbs
メソッドを実装している。
type Vertex struct { X, Y float64 } func (v *Vertex) Abs() float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) }
準備は整ったので、実際に使用してみる。
すこし変更させてもらって、実装したどちらのメソッドも実行している。
func main() { var a,b Abser f := MyFloat(-math.Sqrt2) v := Vertex{3, 4} a = f // a MyFloat implements Abser // a = &v b = &v // a *Vertex implements Abser fmt.Println(a.Abs()) fmt.Println(b.Abs()) }
終わりに
勉強っぽい感じの作りなんで、実際のインタフェースの使い所など学んで行きたい。
以下の記事ではGo
でのインタフェースを書く注意点が書いてあるので参考になった。
次はGoルーチンとチャネルを書こうかな。
LaravelerがGoを初めてさわって見る
ここ最近Laravel
かPython
しか書いてないので、技術のアップデートをしよう思ったのがきっかけ。
なぜGo
なのかと言われると、以下の理由で決めて見た。
Laravel(PHP)
が動的型付け言語なので、静的型付け言語を学び直したい- 流行っている風のものをやりたいため(流行る理由があると思うので)
Laravel(PHP)
はWeb
サービス用、Python
は分析用、Go
はちょっとしたツール用という立ち位置にしやすいので、継続しやすいと思っているため- 毎日お世話になっているpecoみたいなのを作って見たい
学び方の順序などは、こちらの記事を参考にさせてもらった。 qiita.com
Goの背景や網羅的な使い方などを学ぶ
こちらの記事が全体感を掴むにはちょうどいいと思う。 gihyo.jp
細かいところや、理解が深まらない箇所が必ずでてくるのでその場合はこちらから細かいやり方を学ぶ。 go-tour-jp.appspot.com
大体の理解なら技評の記事 <-> A Tour Go
を行き来すればできるけど、部分的にググったりして学んでいく。
忘れている箇所やつまった点をまとめる。
静的型付けと動的型付けの違い
Wikipedia
がわかりやすい。
動的型付け - Wikipedia
とても極端に分かれているが、PHP8
ではJITコンパイラの採用が可決されたみたいで、IDE
との組み合わせで静的型付けみたいなこともできるんじゃないかなと考えてる。
この記事が面白い。どっちもいいとこ取りはし始めてる。
関数とメソッドの違い
自分の頭の中で関数 = メソッド
と勝手に認識してるせいで、途中こいつらは何を言っているんだ・・と思ってしまった。
関数
func sum(i, j int) int { return i + j } func main() { fmt.Println(sum(1,2)) // 3 }
関数の方はPHP
とほぼ同じなのでわかりやすい。
メソッドの方は構造体(ここだとData)と言われる入れ物に、sum
という振る舞いが追加されてるかのように扱える。
Go
にはClass
がないため、ここらへんで色々工夫するのかな。
type Data struct { i int j int } func (d *Data) sum() int { return d.i + d.j } func main() { data := Data {1, 2} fmt.Println(data.sum()) // 3 }
エラー処理
Go
では、error
インターフェースがあって、それを使ってエラーを通知するが、それとは別に例外処理が存在する。
どこまで深く勉強したいところだけど、以下の方の記事がすごく腑に落ちそう。
終わりに
インターフェースや、醍醐味の一つである並列処理などを書きたかったが、久々のブログで体力がないので次回。
Laravel ShiftでLaravelを簡単アップグレード!
Laravel #2 Advent Calendar 2018の11日目です!
今回は、Laravel
のアップデートのやり方について書きたいと思います。
バージョンをあげる時の課題
僕らのチームは元々Laravel
のバージョンを5.5を使っていて、そろそろあげたいよねって話をしてました。
ただ、「調査や変更による工数がかかる」という(多分心理的な)課題があり、そんな時にメンバーの一人が「Laravel Shift」使えば楽そうですよという話から今回に至りました。
Laravel Shiftとは
簡単にいうと、課金すればLaravel
のアップグレードを自動でやってくれるというものです。
なかなか便利そうな感じが漂ってますが、いっきにバージョンアップすることはできないので一つずつバージョンをあげていきます。
今回は5.5から5.7にあげたいので、5.5から5.6($9)、5.6から5.7(7$)の計16$でバージョンアップをしたいと思います。
5.5から5.6へのアップグレード
アップグレードは簡単で、GitHubと連携し、クレジットカードを入力すれば始まります。
数分待つと、指定したブランチへプルリクが自動で作られます。
(自分が英語で話した気分になるので、すごくできた気分になれます)
主なプルリクの内容は以下です。
- PSR-2によるコードスタイルの変更のコミット(準拠してなかったのでいい機会なので変更)
- アップグレードに伴う各種ファイルの修正コミット
- 自動で直せない部分を、コメントで教えてくれる
自動で直せない部分もあるのかよっと思うかもしれませんが、コメントで教えてくれるのでそれの通り直すだけなので楽チンです。
修正後は、「ユニットテスト」と「E2Eテスト」をしてバグがないことを確認したらマージします。
5.6から5.7へのアップグレード
こちらも同じように行います。
ユニットテストだと全てのテストを網羅できてないので、E2Eテストはかなり念入りに行い、無事マージ/リリースを行います。
アップグレードによるバグ
大きいバグは1ヶ月たった今もまだありません。
ただ、5.7
にあるbootstrap/cache
のservices.php
とpackages.php
のオーナー権限がおかしい問題のせいでデプロイのたびにすごく困ってます・・。
修正済みなので、composer update
すればもう大丈夫です。
と、おもったら今度はTestResponse
のJSON
周りがおかしくてテストがこける。。。
マージはされたので早くrelease
してほしいと願っております(12/11現在)
終わりに
最後はあまり関係ないバグの話になってしまいましたが、かかった工数は全部合わせても数時間です。 たった16$でエンジニアの工数をあまり使わずでき、新規開発にすぐ取り組めて、ビジネスサイドにもほぼ迷惑かからない最高のツールでした。ありがとうございます。