Goの勉強 ゴルーチンとチャネル

Goの勉強をやり始めたのでメモ。
プログラミング言語 Go」を読んでる。

ゴルーチン

  • とりあえずスレッドみたいなもの(厳密には違うらしい)
  • main関数を呼び出すゴルーチンはメインゴルーチンと呼ぶ
  • 新たなゴルーチンは go 文で生成できる
  • main関数が終了するとすべてのゴルーチンも終了する
  • mainから戻ることとプログラムを終了させること以外に他のゴルーチンを終了させる方法はない
    • ゴルーチンの停止をリクエストするために他のゴルーチンと通信する方法はある

チャネル

  • チャネルはゴルーチン間の接続
    • ひとつのゴルーチンから他のゴルーチンへ値を送ることができる
  • チャネルはマップと同様に make で作成する。
    • つまり参照になる。
  • 同じ型のチャネルは == で比較可能である。
  • チャネルは「送信」と「受信」の操作を持ち、まとめて「通信」と呼ばれる。
  • 他に、クローズという操作もある。
ch <- x // 送信  
x = <-ch // 受信  
close(ch) // クローズ  

バッファなしチャネル

  • バッファなしチャネルは送信と受信を同期させるために使用する。
  • チャネルに送信されるメッセージのことをイベントと呼ぶ。
  • 同期のみが目的の場合、チャネルの型は struct{} にすることが一般的である。

パイプライン

  • チャネルを使って複数のゴルーチンを接続することをパイプラインと呼ぶ。
  • チャネルは使用した後にすべて閉じる必要はない。
    • 到達不能なチャネルはガベージコレクタがその資源を回収する。

一方向チャネル

  • 送信用、受信用のチャネルを型で宣言することができる。
  • 引数でチャネルを渡すと暗黙的に送信用、受信用に型変換される。
  • 双方向チャネルから一方向チャネルに型変換することはできるが、逆はできない。
chan<- int // 送信用  
<-chan int // 受信用  

バッファありチャネル

ch = make(chan string, 3)  

とすることで容量が3のバッファありチャネルを作成することができる。

  • チャネルがいっぱいになるまで受信を待たずに送信することができる。
  • チャネルが空になるまで送信を待たずに受信することができる。
  • チャネルが空でもいっぱいでもなければ、送信・受信ともにすることができる。

select での多重化

受け取ったチャネルによって処理を変更したいときに select を使う。

select {  
case <-ch1:  
        // ....  
case x := <-ch2:  
        // ....  
case ch3 <- y:  
        // ....  
default:  
        // ....  
}  
  • select{} は永久に待ち続ける。
  • 複数のチャネルから受信可能であれば、どのチャネルが選ばれるかはランダムに選択される。

以下のような処理はポーリングと呼ばれる。

for {  
        select {  
                case <- abort:  
                        return  
                default:  
                        // 何もしない  
        }  
}  

「開発速度が遅い」は誰にとっての問題なのか?

3連休も終わりですね。
連休だったので帰省していたのですが、なんと実家にあの有名な古典の「ライト、ついてますか」があり、思わず一気読みしてしまいました。
この本は問題解決の本で、「エンジニアにきいたオススメの1冊」みたいなのにも取り上げられるような本です。

www.kyoritsu-pub.co.jp

さて、この本いわく、問題を解決する際(または問題について考える際)に、「それは誰にとって問題なのか?」を考えるべきだと書かれています。(つまり、誰がその問題で困っているのか、誰にとっての問題を解決したいのか、ということ。)
例えば本の冒頭では、ビルのエレベーターが遅いという問題に対して、入居者にとっての問題であると見たときと、ビルオーナーにとっての問題であると見たときでは、問題の解決方法が変わってくるよね、ということが書いてあります。

「たしかになぁ・・・」と思いつつ、ふと身近な問題で考えてみようと思い、このブログ記事を書いてます。
僕らエンジニアでよくある問題といえば、「開発速度が遅い」というやつでしょう。

問題定義

問題はもちろん「開発速度が遅い」です。
ここでウォーターフォールについて頭を巡らせるのも楽しそうではありますが、せっかくなので、ベンチャー企業でBtoCの自社サービスを開発していて、アジャイルを、何ならスクラムを採用しているイケイケなチームについて考えてみましょう。

このチームにとって、「開発速度が遅い」という問題は誰にとっての問題なのか、そしてその問題はどのように解決するべきなのかについて考えていきます。

先に結論

というよりも、この記事では結論を出しません。というか僕もよくわかりません。
解決方法を提案する記事ではなく、問題についてぼんやりと考えてみる記事なのです。
もしも結論や解決方法を知りたければ、スクラムフェス三河にでも行って、そこらへんのスクラムマスターに質問してみるのが一番早いと思います。
(質問する前に「『それはチームによって違います』なんて(役に立たない)回答はしないでくださいね」と付け加えておくと、あなたが欲しい結論が得やすいかもしれません。)

誰にとっての問題か?

さて、話を戻しましょう。「開発速度が遅い」のは誰にとっての問題なのでしょうか。
本に倣って候補を挙げてみましょう。

こんなものでしょうか。
候補を細かく見ていきましょう。

まず、この問題はスクラムマスターにとっての問題であると言って間違いないでしょう。
スクラムマスターはプロセスの権威であり、開発速度の遅さはプロセスの問題であることがほとんどだからです。
スクラムの有用性についての責任もあり、開発速度は有用性を測る指標のひとつにもなるでしょう。
開発速度が低いままだと「お前は仕事をしていないじゃないか」と減給されてしまうかもしれませんね。

逆に、開発者にとってこれは問題になりづらいでしょう。
開発者にとって、開発速度が遅いことは(目に見える範囲)で問題になりづらいので、問題として認識されないように思われます。
開発速度が遅いとどのような悪いことが起きるのでしょうか。遠い将来のことを除けば、悪いことは起きないですよね。
なぜならチームの(遅い)速度をベースに見積もりをし、計画を立てているからです。
どちらかというと開発者が問題として認識するのは、開発速度が遅いときではなく、遅くなったときでしょう。
速度が遅くなった場合はプロダクトオーナーと連携を取る必要が出てきますし、その結果スプリント中のトレードオフが発生する可能性もあります。スプリントレビューのシナリオを考え直さないといけないかもしれません。そしてレトロスペクティブでベロシティが下がったことが議題として挙がり、解決策が考えられるでしょう。
ただ、今回問題にしたいのは、「普段よりも遅くなった」ことではなく「普段から遅い」ことなのです。

一番候補から外れやすいのはユーザーでしょう。
「開発速度が遅いとユーザーに機能を届けるのが遅くなってしまう。そうするとユーザーは困ってしまうぞ。」と言う人がたまにいますが、そんなケースは非常にレアです。
なぜなら多くの機能は、ユーザーに事前告知なくリリースされるからです。
「俺はよく知らない機能がなかなかリリースされなくて困っているんだ!」なんて人はいないでしょう。 (そもそもリリースした機能がユーザーに認知されているのかも怪しいです。)
ユーザーにとって開発速度が問題になるときは、バグ修正のリリースや、すでにわかっている機能のリリースなどの場合(例えばそのユーザーが大口顧客で、機能の追加をしないと契約しないぞと言った場合など)に限られます。

ステークホルダーにとっては問題にはなり得ますが、あまり深刻な問題としては捉えていないかもしれません。
例えば営業の場合、既存の機能をもとに営業をかけることのほうが多いからです。
その企業が新たな機能がないと契約してくれない場合でも、他の代案を提案したり、契約を待ってもらうなど、回避策を用意することができる場合がほとんどです。
ただし、開発速度が遅いことによって自分たちの仕事が増えているので、解決できるなら解決したいと思うでしょう。

経営者にとっては深刻な問題になる可能性があります。
例えばVCに「今季中にシングルサインオンと権限管理の機能をリリースする」などと約束している場合などです。
出資取り止めになることはどうしても避けたいので、何としてでもこの問題を解決しないといけません。

プロダクトオーナーにとっては少し複雑な問題です。
開発速度の遅さは直接的にはプロダクトオーナーの問題ではありません。
どんなに開発速度が遅くても責められるのは開発者やスクラムマスターであり、プロダクトオーナーは開発速度に責任を持たなくていいはずです。
一方で、開発速度は「どのような戦略をとるか」ということに関係してきます。
「もっと開発速度が速ければ、こういう戦略も取れたんだけどなぁ」と心の中で思うプロダクトオーナーは多いのではないでしょうか。
また、自分の考えたものがなかなか形にならず世に出ないということは、心にもやもやを抱えることになりそうです。
このもやもやを解消したいと思うのであれば、これはプロダクトオーナーにとっての問題なのかもしれません。

問題解決のむずかしさ

さて、「それは誰にとっての問題なのか?」を考えてみると、なぜこの「開発速度が遅い」という問題が多くの場所で起こり、そしてそれがなかなか解決されないかの一端が見えてくるように思います。

この問題を解決するのは誰なのか、それはきっと開発者でしょう。
開発者が今までのやり方を変えるなり、認識を改めるなり、残業をするなり、何かしらのアクションをしないと開発速度は上がらないでしょう。
一方で、前述したようにこれは開発者にとっての問題ではないのです。
この「問題の当事者と問題の解決者が一致しない」ということが、解決が難しい原因のように思います。

当事者と解決者が一致しない場合、問題を解決するためにはこの問題を開発者の問題にする必要があります。(「今年中にここまでリリースしないと給料を下げるぞ」といったように。)
アジャイル風に言うと「問題を売り込む」でしょうか。
この売り込み方が、非常に難しいように思います。
アジャイルなチームなのであれば、自己組織化をしなければいけません。
つまり、開発者の代わりに問題を解決したり、解決方法を押し付けるようなことは避けるべきです。
では、どんな方法で問題を売り込めばいいんでしょうか。

さて、ここからはまだ考えがまとまっていません。
たとえば

  • 「このままだとVCから投資されなくなってクビにしないといけない」と脅す
  • 「開発速度が速いほうがみんな幸せになるよ」と開発者の良心に訴える

みたいなのはすぐに思いつきますが、あまり良い方法ではなさそうですね。

もしこの問題に興味があって良い売り込み方法が思いついた方がいれば、スクラムフェス三河で登壇してみてはいかがでしょうか。
(7月末までプロポーザル出せるっぽいよ!)

(宣伝記事みたくなってしまいましたが、僕はスクラムフェス三河とは何ら関係はありません。)

Goでスペースっぽい文字を見つける

(空文字列ではない)

Golangでスペースっぽい文字を見つけようとすると、次の3つの方法がありそうです。

この3つについて、自分はいまいち使い分けがわかっていなかったので、調べてみました。
ずらっとリストにしてみます。(たいていは知らない文字だけど)

文字名 わかりやすく言うと unicode の番号 unicode.IsSpace \s \pZ
Character Tabulation タブ文字(\t) U+0009 o o x
End Of Line 改行文字(\n) U+000A o o x
Line Tabulation 垂直タブ(\v) U+000B o x x
Form Feed \f U+000C o o x
Carriage Return \r U+000D o o x
Space 半角スペース U+0020 o o o
Next Line U+0085 o x x
No-Break Space U+00A0 o x o
Ogham Space Mark U+1680 o x o
En Quad U+2000 o x o
Em Quad U+2001 o x o
En Space U+2002 o x o
Em Space U+2003 o x o
Three-Per-Em Space U+2004 o x o
Four-Per-Em Space U+2005 o x o
Six-Per-Em Space U+2006 o x o
Figure Space U+2007 o x o
Punctuation Space U+2008 o x o
Thin Space U+2009 o x o
Hair Space U+200A o x o
Line Separator U+2028 o x o
Paragraph Separator U+2029 o x o
Narrow No-Break Space U+202F o x o
Medium Mathematical Space U+205F o x o
Ideographic Space 全角スペース U+3000 o x o

まとめると次のような感じなんでしょうか。

分類 文字
どれでも判定できる 半角スペース
unicode.IsSpace でしか判定できない 垂直タブ・Next Line
\pZ では判定できない 制御文字・Next Line
\s では判定できない いっぱいある

結論としては、 unicode.IsSpace を使えば良さそう という感じでしょうか。

Goの勉強 インターフェース

Goの勉強をやり始めたのでメモ。
プログラミング言語 Go」を読んでる。

契約としてのインターフェース

  • GoはStructualTypingを採用している。
    • インターフェースを明示的に宣言していなくても、シグネチャを満たしていればそのインターフェースだと見做せる。

インターフェース型

// インターフェースの宣言  
type InterfaceName interface {  
    MethodName(args int) bool  
}  

// 既存のインターフェースの流用  
type InterfaceName2 interface {  
    InterfaceName  
    io.Writer  
}  

インターフェースを満足する

interface{} は空インターフェースと呼ばれ、どんな値でも入れることができる。

var any interface{}  
any = 1  
any = 'r'  
any = "string"  
any = map[string]int{"one", 1}  
any = new(bytes.Buffer)  

以下のようにインターフェースとの関係性を明示的に示すことができる。

var _ io.Writer = (*bytes.Buffer)(nil)  

インターフェース値

インターフェース値は

  • 動的な型(具象型)
  • 動的な値(その型の値)

の2つを持っている。

コード
var w io.Writer nil nil
w = os.Stdout *os.File os.Stdoutのコピー
w = new(bytes.Buffer) *bytes.Buffer 新たな Buffer へのポインタ
w = nil nil nil
  • インターフェース値の動的な型が何であるかはコンパイル時にはわからない。
  • インターフェース値は動的な型が比較可能であれば比較できるし、比較不可能であれば比較できない
    • 他の型と違い、比較可能かどうかが型のみで判定できない
  • nil ポインタを含むインターフェースは nil ではない

アサーション

以下のように書くことで、型が別の型がどうか、あるいは満足するかを確認できる。

var w io.Writer = os.stdout  
f, ok := w.(*os.File)  

型switch

型による分岐を以下のように書くことができる。

switch x := x.(type) {  
case nil : //...  
case int, uint : //...  
case bool : //...  
case string : //...  
default : //...  
}  

ちょっとした助言

Goでは、インターフェースは2つ以上の具象型により満足されている場合にだけ使われる。

PHPerKaigi2023にいくと登壇しなくてもアウトプットが増える

PHPerKaigi2023 にいってきました。
PHPerKaigiは2,3年ぶりの参加です。
そして、初の一般参加です。
僕は登壇したわけではないですが、なぜかアウトプットが増えました。
不思議です。

🍺の力でアウトプットがはえ

PHPerKaigiといえば🍺です。
🍺しか飲んでいない気もします。
LTあたりから会場にバドワイザーが提供され2本くらいあけ、クロージングをした後は当然のように居酒屋にいって🍺を飲みます。
そんなに飲んでいれば他の人との会話は弾んで色々な話をきけるし、飲みすぎで寝付きが悪くなるわけです。

寝れないから暇なんで、飲みながら話した内容をなんとなくスライドにするわけです・・・

なぜか500以上ものViewが付き、自分の公開資料の中で3位になりました。
このスライドで発表してないんですけどね。

不具合によってアウトプットがはえ

blog.phperkaigi.jp

forteeからキャンペーンアイコンをダウンロードできたらしいです。
らしいです。

・・・自分は表示されなかったのですが。。。

調べてみると、どうやら500エラーになっているようです。

エラーログをいっぱい出したのが運営に届いたらしく、forteeからフレーム画像をダウンロードできるようになっていて、「自分で合成してね!」とのことでした。

でもそんな画像編集ソフトなんてないしなぁ・・・

ということで、フレームを合成するPHPのプログラムを作りました。ここはPHPerKaigiですからね。

github.com

最終日でしたが、僕も無事にフレームを付けることができました!

みんなもPHPerKaigiに参加してアウトプットを増やそう

PHPerKaigiは参加するだけでアウトプットが増える素敵なカンファレンスです!
ぜひみなさん来年もPHPerKaigiに参加してアウトプットを増やしましょう!

Goの勉強 メソッド

Goの勉強をやり始めたのでメモ。
プログラミング言語 Go」を読んでる。

メソッド宣言

type Point struct{ X, Y float64 }  
func (p Point) Distance(q Point) float64 {  
    // ...  
}  

は次と一緒

<?php  

class Point  
{  
    public float $x  
    public float $y  
    
    public function distance(self q)  
    {  
        //...  
    }  
}  
  • Go では thisself のような表現は使用しない。
  • フィールドと同じ名前のメソッドを宣言することはできない。

ポインタレシーバを持つメソッド

  • Go では引数はすべてコピーされるため、大きい引数や更新を行いたい場合はポインタを引数とする必要がある。
  • 慣習的に、ひとつでもポインタレシーバを持つメソッドがあるのであれば、その型のすべてのメソッドはポインタレシーバを持つようにする。

メソッド値とメソッド式

次はメソッド値

p := Point{1, 2}  
q := Point{4, 6}  

distanceFromP := p.Distance  
fmt.println(distanceFromP(q)) // 5  

次はメソッド式

p := Point{1, 2}  
q := Point{4, 6}  

distance := Point.Distance  
fmt.println(distance(p, q)) // 5  

カプセル化

  • 他の言語と違い、Goの可視性はパッケージ単位でしか行えない。
  • Getter を定義する場合、慣習的に Get プレフィックスは付けない。
    • Setter の場合は Set を付ける。

大学院選びQ&A

無事に大学院のPBLの最終成果発表が終わり、卒業できそうなことがわかりました。
学業も無事に終わりましたので、春休みは無職を全力で楽しみます!

さて、本題です。
「大学院で情報系を学びたい!」となると、東京都立産業技術大学院大学(以後AIIT)と北陸先端科学技術大学院大学(以後JAIST)がよく候補として挙がります。
僕はAIITの学生なので、AIITの学生から見た比較をQ&A方式で紹介していこうと思います。
ちなみにJAISTの学生である父さんという方が「働きながら情報系の大学院を修了した 」というnoteを書かれていて、そちらにJAISTの様子が書かれているので併せて読むことをオススメします。

note.com

Q. コンピュータサイエンス(以後CS)の勉強をしたいです

A. JAISTに行きましょう

AIITではCSの授業は(ほぼ)ありませんし、取れる学位もCSではありません。
よってCSの勉強をしたい場合はAIITはオススメできません。

これは余談ですが、CSというと「データ構造とアルゴリズム」ばかりが推されていて、CSについて勘違いされてる方もいらっしゃるのではと思います。
正確ではありませんが、わかりやすく言うとCSとは「コンピュータに応用できる数学」のことです。
もしCSを勉強したいと思われている方がいれば、「本当に数学を勉強したいの?」と自問してみるといいかもしれません。

Q. 数学がわかりません

A. AIITがオススメです

JAISTはCSなので、普通に大学生レベルの数学の知識が求められるようです。
一方でAIITはCSではないせいか、統計と機械学習以外の授業では数学はほぼ求められません。

ちなみにAIITの入試は「小論文」「プレゼンテーション」なので、入試でも数学は問われません。

Q. 週末しか時間がとれません

A. JAISTがいいかも

JAISTは主に週末の金土日に授業が開講されるようです。
一方で、AIITは月〜土まで授業が開講されます。
なので、仕事の都合で夕方までに仕事を切り上げられない場合はJAISTのほうが良いかもしれません。

ちなみに、「日曜日くらいゆっくりしたい」という要望はおそらくAIITに行ってもJAISTに行っても叶いません。
最近の大学や大学院は僕らが昔在籍していたときよりも真面目になっており、ほぼすべての授業で課題が出されます。
もちろん課題は授業時間外でやることが前提になっているので、勤務時間と授業時間以外の時間を確保して取り組む必要があります。
さらに、課題の中にはチームで取り組むものもあり、社会人がチームを組んで時間の都合がつきやすいのなんて、日曜ぐらいしかないわけです。(土曜日は授業)
サラリーマンは週5日だけサラリーマンしてればいいのですが、学生は週7日、毎日が学生なのです・・・

Q. 勉強はしたいのですが、研究はしたくありません

A. AIITがオススメです

AIITは専門職大学院です。
専門職大学院はアカデミック色が薄く、AIITでは研究は必須ではありません。
代わりに1年間プロジェクト活動を行うPBLがあります。
このPBLについては、情報系ではプロダクト作成を行うことが多いです。

逆に研究をしたい人はAIITをオススメしません。
PBLの中で研究をして学会発表をするチームもありますが、非常に少数です。
また、PBL活動はチームで行うので、個人的に研究したいテーマがあったとしてもそれを研究できるとは限りません。
他のチームメンバーがNOと言う可能性があるからですね。
どうしてもやりたい研究がある場合、他メンバーの協力を得られるように色々と戦略を練っておくと良いと思います。

ちなみに、AIITで取れる学位は「専門職修士」になります。
普通の修士との違いは無いようです。
アメックスとセゾンアメックスの違いみたいなものでしょうか。

Q. お金がありません

A. 勉強が得意ならJAIST、苦手ならAIITがいいかも

JAISTの場合

JAIST奨学金が非常に充実しています。
成績が上位10%であれば、授業料が免除されるようです。
なので、成績優秀者をキープできるのであれば、受験料と入学金だけで済みそうです。

AIITの場合

一方で、AIITの場合は雇用保険制度の「専門実践教育訓練給付金」が使えます。
詳細な条件は厚生労働省のサイトで確認していただきたいのですが、

  • 雇用保険に入っている(または直近入っていた)
  • 36歳未満

の2つを満たしていると費用の50%、また、卒業後に雇用保険に入るとさらにプラスで20%を受け取れます。
つまり、学費が3割で済むということですね。
また他にも、成績優秀者向けの給付型奨学金や、都民向けの入学料半額などの制度があります。

参考程度にAIITの場合の具体的な数字を。
まず、そのまますべての入学金・授業料を払うと、

入学料   ¥282,000  
授業料 ¥1,040,800  
計     ¥1,322,800  

かかります。
ざっと150万くらいですね。

ここに各種制度を適用すると、

都民の場合   -¥141,000  
給付型奨学金 -¥520,000  
訓練給付金   -¥463,260  
計        -¥1,124,260  

支払い        ¥198,540  

となり、実質2年間で20万円程度で済みます。
MacBook Pro より安い!

JAIST, AIITどちらも

もちろんこれらの他にも貸与型の奨学金はあるので、お金がない場合は検討してみるといいかもしれません。

自分の軸で選ぶ

大学院ごとに色々と特色があるわけですが、結局は自分の中で軸を組み立てて、それをもとに選んでいくしかないわけです。
僕は研究したいテーマが特に無かったので、「AIITいいじゃん」となってそのままAIITに行き、そして結果として間違ってなかったかなと思います。

こういう選ぶという行為をするときには、アジャイルが思い起こされますね。
結局はトレードオフの世界であり、何を優先して何を捨てるのかを決めるだけです。
有名な言葉でいうところの「荒ぶる四天王」や「鉄の三角形」を考える必要があるわけです。(もちろん、四天王や三角形の要素は自分で考える必要はあります。)

そんな軸選びのひとつの判断要素になれば幸いです。