いっきのblog

技術とか色々

2023年振り返り

ひっさびさにかく。

Stockr開発メンバーと一緒にふりかえり Advent Calendar 2023の24日目!だいぶ遅くなってしまってすみません。

話すトピック

  • 6年間CTOやっていた会社をやめて、フリーランスになった
  • コーチングを学び始めた
  • 自分のやりたいことを見つけられ始めてきた

会社辞めた

会社にジョインしてからは、プロダクトがない状態からプロダクトを作って、どうグロースさせるか考えたり、採用やチーム作り、技術負債とのバランスを向き合い続けてきたりと思い返すと色々な経験をしていたなーと。もっともっと会社を成長できなかったのは残念だし、土台の一部分でも貢献できたのかなーなんては当時思っていたが、まだまだできたことありすぎたなと自分の不甲斐なさに最近思うことはたくさんあるけどまたどこかでまとめる。

フリーランスになった

会社を辞めてからは、フリーランスになって色々なお手伝いをしてみている。

  • PM
  • データ基盤/CRMの開発
  • 組織開発、プロダクトチーム作り、 育成
  • 生成AIを使ったプロダクト開発

この中だと特に組織開発はCTOしていた時に一番好きだった領域で、どういうチームにして、どういうふうに育成しようか・・は自分のWant to(やりたいこと)にやんわりと近くて、もっとやっていきたいなと思う。

コーチングを学び始めた

組織開発の支援をしている会社の方から誘われたコーチングスクールをきっかけに本格的にコーチングを学び始めている。 その時までに印象にあったコーチングは、コーチ側の言葉でゴール設定したり、目標管理したりするものが多く、あとは少しカウンセリングっぽいと思っていたが、今習い始めたところは本当にやりたいことを見つける手伝いをし、現状の外へゴール設定をしていくやり方を主にとっていて、自分がやってみたいなとおもうやり方ですごく楽しい。

何年前かによんだ、サピエンス全史に書かれている人間が優れているのは「虚構を信じる力」の能力と書かれていて、とても衝撃を受けてその後もずっと考えていた。ソーシャルメディアの生態系という本では、SNS全体を「ソーシャル・オーガニズム」という造語で、一つの有機体とみなし、ミームによって伝播し、どういう変貌を遂げていくかが書かれている。今なぜこの話をするかというと、自分が7年前くらいから「世界一のプロダクトを作る」ということを目標にやっていたが、「世界一のプロダクトを作る」ことというより、「世界一のプロダクトを作る環境」が好きで、その環境こそが皆が虚構を信じていていたり、一つの有機体のようなチームになっていて、そのプロセスにかなり興味が湧いていたからだ。実際、フリーランスになっても、スタートアップの会社と話をする時に、代表や役員がどれだけ自分たちがやっていることを信じているかをよく見ていて、その虚構を信じるプロセスやそれにかける情熱が自分の中でかなり高い優先度になっていた。

コーチングから話がだいぶ飛んだように思えるが、この虚構(見えない何かであり、信念も近しいものだと思っている)をどう見つけ出すか、信じさせるかにおいては似ているんじゃないかなーと思っている。 プロダクトや組織のリーダーシップを取る上で、自分で虚構を生み出し、信じるというプロセスを得ないと、うまく人を巻き込めないが、それを他の人にやってあげられるなんて本当にすごいことだ。似たようなことを言うけど、やらせるのではなくて、自分がやっているという感覚にさせることだ。

そんなこんなで、コーチングはまずは自分を変えれないと相手にも同じことができないので、自分が本当にやりたいことを見つけ、それを本気で信じるというプロセスを今やっているが、このプロセス自体が面白くて、今はこれがやりたいことに近い。

TensorFlow2.0とTensorFlowHubを使ってみる

TensorFlow2.0betaが出てたので、試してみる。

TensorFlowとは?

TensorFlow(テンソルフロー)とは、Googleが開発しているOSS機械学習のライブラリ。Googleはもちろんアルファ碁で有名になったDeepMindでも使われている。
対応言語は、Python, C, C++, Java, Goなどがある。
今回は使わないが、Mobileにも入れることができたりする。

TensorFlow - Wikipedia

また、Tensor(テンソル)については、以下の記事が参考になった。

mathcommunication.hatenablog.com

とはいっても難しくてあまり理解できなかったので、以下の記事がFlow(フロー)部分も含めて、ざっくりの理解ができた。

www.codexa.net

ようは、テンソルとは多次元配列のこといっているとの理解で一旦とどめて置く。

TensorFlow1.0と2.0の違い

以下の記事がいいまとめすぎて、理解しやすかった。

qiita.com

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

ニューラルネットワークチュートリアル

以下の記事を行なった。エラーなしで動くので、ここでは特に何もしない。

www.tensorflow.org

ただ、とりあえず具動かせるが、理解が足りてない部分を以下を参考とした。

www.sbbit.jp

ついでに、CNNも

lp-tech.net

softmax

qiita.com

TensorFlowHubのインストール

公式のチュートリアルを参考に動かしてみる

www.tensorflow.org

!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なので、コメントアウト

www.tensorflow.org

// 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など

www.tensorflow.org

基本はcompat.v1つければよさそう

終わりに

ざっくりと駆け足でTensorFlow2.xを使って見た。
2系らしい動きはまだできてないので、次は深掘りする。

GoでAtCoder(競技プログラミング)やってみる

最近Goを勉強して行く上で、アルゴリズムの勉強も同時にしながらできないかなーと思い、競技プログラミングというアルゴリズムのコンテストはどっちも満たせると信じ、始めて見た。

今回はAtCoderと言われる、日本製のコンテストサイトでやってみる。
以下の方が代表で、元々世界のプログラミングコンテストのランカーだったのか、すごい。
twitter.com

とりあえず読んでみるべき記事

どう進めたらいいのかはもうここで完結しそうなくらいよかった。 qiita.com

登録したら上記の問題をコンテスト形式で用意してくれるのでそれをやったほうがいい。

atcoder.jp

Goで書いてみる

https://github.com/kzkohashi/at_coder_practice

全然まだまだ途中だけど、自分なりの答えはgithubにあげている。
groutineとか使えば早くなるんだろうな。今はこなすことに集中。

テクニックみたいなやり方をまとめてくれていてすごく助かっている記事。
qiita.com

まだ爆速をもとめられていないが、参考になりそうな記事。@hama_duさんや。

qiita.com

感想

少ししかまだ始められてないが、すごく良さそうな印象だった。
採用とか社内のエンジニアのレベルアップに良いな〜とも思うので、継続してやっていこ。

GoroutineとChannelについて学ぶ

前回Goのインタフェースについて書いた。

kzkohashi.hatenablog.com (アイキャッチが更新されてない・・)

今回はGoの真髄とも言える、ゴルーチンとチャネルによる並行処理(Concurrent)について学んでいく。

並行(Concurrent)処理と並列(Parallel)処理

間違えやすいのだが、並行処理は並列処理と概念的に異なる。

こちらの記事がわかりやすかったので、引用させていただく。

Concurrent(並行)は「複数の動作が、論理的に、順不同もしくは同時に起こりうる」こと Parallel(並列)は、「複数の動作が、物理的に、同時に起こること」
引用: freak-da.hatenablog.com

並行は1人の人が複数の仕事をし、並列は複数の人が複数の仕事をしている状態だ。
とはいっても、並行処理は擬似並列ともいえるので、日本語的には「並列処理」を使っても問題ないと思う。

この辺りも面白かった。

興味がある人は以下を読むと良さそう。
自分は近々届くので、また別途まとめたい。

www.oreilly.co.jp

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(スレッド)間で値の受け渡しを安全にできるので、とても簡単に扱える。

qiita.com

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に値を入れ、<-quitgoroutineの処理を待つことができる。

終わりに

Goの勉強を駆け足でやってみた。
最初は意味がわからなかったが、毎日少しずつ見ていくと慣れていくもんだな。
次からはGoAPIサーバー作ることをしようかな。

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{}型はintboolなど全ての値を取りうる型とのこと。

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の別名として、新しい型として定義されたものだ。
言われてみると当たり前な気はするけど、忘れないようにと。以下の記事がとても参考になった。

qiita.com

また、以下のように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でのインタフェースを書く注意点が書いてあるので参考になった。

qiita.com

次はGoルーチンとチャネルを書こうかな。

LaravelerがGoを初めてさわって見る

ここ最近LaravelPythonしか書いてないので、技術のアップデートをしよう思ったのがきっかけ。
なぜ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との組み合わせで静的型付けみたいなこともできるんじゃないかなと考えてる。
この記事が面白い。どっちもいいとこ取りはし始めてる。

jp.quora.com

関数とメソッドの違い

自分の頭の中で関数 = メソッドと勝手に認識してるせいで、途中こいつらは何を言っているんだ・・と思ってしまった。
関数

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インターフェースがあって、それを使ってエラーを通知するが、それとは別に例外処理が存在する。
どこまで深く勉強したいところだけど、以下の方の記事がすごく腑に落ちそう。

blog.amedama.jp

終わりに

インターフェースや、醍醐味の一つである並列処理などを書きたかったが、久々のブログで体力がないので次回。

Laravel ShiftでLaravelを簡単アップグレード!

Laravel #2 Advent Calendar 2018の11日目です!
今回は、Laravelのアップデートのやり方について書きたいと思います。

バージョンをあげる時の課題

僕らのチームは元々Laravelのバージョンを5.5を使っていて、そろそろあげたいよねって話をしてました。
ただ、「調査や変更による工数がかかる」という(多分心理的な)課題があり、そんな時にメンバーの一人が「Laravel Shift」使えば楽そうですよという話から今回に至りました。

Laravel Shiftとは

簡単にいうと、課金すればLaravelのアップグレードを自動でやってくれるというものです。

laravelshift.com

なかなか便利そうな感じが漂ってますが、いっきにバージョンアップすることはできないので一つずつバージョンをあげていきます。
今回は5.5から5.7にあげたいので、5.5から5.6($9)、5.6から5.7(7$)の計16$でバージョンアップをしたいと思います。

f:id:kzkohashi:20181210202747p:plain

5.5から5.6へのアップグレード

アップグレードは簡単で、GitHubと連携し、クレジットカードを入力すれば始まります。

f:id:kzkohashi:20181210203204p:plain

数分待つと、指定したブランチへプルリクが自動で作られます。
(自分が英語で話した気分になるので、すごくできた気分になれます)

f:id:kzkohashi:20181210203417p:plain

主なプルリクの内容は以下です。

  • PSR-2によるコードスタイルの変更のコミット(準拠してなかったのでいい機会なので変更)
  • アップグレードに伴う各種ファイルの修正コミット
  • 自動で直せない部分を、コメントで教えてくれる

自動で直せない部分もあるのかよっと思うかもしれませんが、コメントで教えてくれるのでそれの通り直すだけなので楽チンです。
修正後は、「ユニットテスト」と「E2Eテスト」をしてバグがないことを確認したらマージします。

5.6から5.7へのアップグレード

こちらも同じように行います。

f:id:kzkohashi:20181210204250p:plain

ユニットテストだと全てのテストを網羅できてないので、E2Eテストはかなり念入りに行い、無事マージ/リリースを行います。

アップグレードによるバグ

大きいバグは1ヶ月たった今もまだありません。
ただ、5.7にあるbootstrap/cacheservices.phppackages.phpのオーナー権限がおかしい問題のせいでデプロイのたびにすごく困ってます・・。
修正済みなので、composer updateすればもう大丈夫です。

github.com

と、おもったら今度はTestResponseJSON周りがおかしくてテストがこける。。。 マージはされたので早くreleaseしてほしいと願っております(12/11現在)

github.com

終わりに

最後はあまり関係ないバグの話になってしまいましたが、かかった工数は全部合わせても数時間です。 たった16$でエンジニアの工数をあまり使わずでき、新規開発にすぐ取り組めて、ビジネスサイドにもほぼ迷惑かからない最高のツールでした。ありがとうございます。