CfP の提出は 2021-08-31 が締め切りであり、そして本日は 2021-08-31 である。出すつもりであるのに、どうしていつもギリギリになってしまうのか。
最近の GoCon にはいつも CfP を出すようにしているのであるが、いつも締め切り当日の締め切り間際の時間 (23:50 くらい) に提出しては落選するという展開を繰り返している。いくらか早く (締め切りより一週間くらい前?) に提出すると、運営の方にレビューしてもらえるという話もある。なので、ぜひともギリギリじゃなく提出したいのである。が、今回も今回とてこの体たらくである。すまぬ…。すまぬ…。
CfP 提出を諦めそうな気持ちになりつつ、とはいえこの手のイベントは登壇者なくして成り立たない。Go のコミュニティを盛り上げていくことにちょろっとでも協力できるならば、ぜひとも、微力ながら賑やかしていきたいと思う所存である。なので出すぞ。一個でも出すぞ。
さて、本当は GoCon で過去に採択されたトークの傾向から鑑みて、採択されそうなネタを考えていていきたいところである。しかし残念ながらもう時間がない (現在 2021-08-31 22:55)。話せそうなネタをとにかくぶっぱしていくしかない。話ができそうなネタは、
このへんだろうか。面白いかどうかは自分で決めない。とりあえず出しておいて需要があると判断してもらえたら話そう、という考えで行く。
いまだかつてないギリギリ (2021-08-31 23:58 提出ボタン押下) でなんとか一本だけ提出した…。いい大人がいったい何をやっているのか。夏休みの宿題じゃあるまいし…?(ちなみに papercall のページをよく見てみたら、「お一人様の提出は一本まで」だった。以前は 3 本くらい出せたような?レビューが大変だからっていうことなのかな。とにかく一本が上限なので、別に少ないわけではないことが分かった)
ちなみに暫時悩んで “hashira” の話題で CfP を書いてみた。そういう自作アプリの話みたいのが一個くらいあるのもいいんじゃない、なんて思うがどうかね。ひとまず果報を寝て待つぞ。
2020-07-22 に行われた「社内ゆるい Ruby LT 会」にて、「Ruby から Go を呼ぶ」というネタで話をした。
資料を用意しないで、実際にコードを書いて実行する様を見てもらうという感じの発表形式をとったもので「残るもの」がない。だので、資料の代わりと言ってはあれだが何をどう話したかというのを記念に本記事に記しておく。
Ruby から Go を呼ぶと言っても色々やり方があり、たとえば、
system
的なもので呼び出すみたいなのも広い意味では Ruby から Go を呼ぶのに該当しそうな気がする。
が、今回はもうちょっと泥っぽく、「Go で書いたソースコードを共有ライブラリ化したものを用いて、Ruby からそのライブラリに含まれている関数を呼び出す」という形式を披露した。役に立つかはさておき、一番映えそうだったからである。うふふ。
Ruby にはこういう「共有ライブラリを読み込むための機能」が標準で用意されていて、それが fiddle
と呼ばれているやつである。
同じような機能を提供するライブラリとして ffi
とかそういうのもあるけど、まあ「標準」という言葉に弱い僕であるので、とりあえず fiddle
を試していくことにした。
まずは呼び出される側の共有ライブラリを作る作業を行った。
ソースコードは以下。lib.go
というファイル名で保存した。
package main
import "C"
//export Add
func Add(a, b int) int {
return a + b
}
func main() {}
何かのチュートリアルに出てきそうな至極シンプルな足し算をする関数。
一応、普通の Go と違う点としては cgo のための諸々 (import "C"
しているところと export Add
というコメントを付与しているところ) が追記されていることかしら。
これを以下のコマンドでビルドする。
$ go build -buildmode=c-shared -o lib.so lib.go
すると、lib.h
と lib.so
が出力される (今回、ヘッダーは使わない)。
$ ls
go.mod lib.go lib.h lib.so
出力された lib.so
を、Ruby のコード内から読み込む。
このような感じで lib.so
をロードし、その中の Add
関数を extern
を使って呼び出せる状態にしている。
require 'fiddle/import'
module M
extend Fiddle::Importer
dlload 'lib.so'
extern 'int Add(int, int)'
end
p M.Add(1, 3) # 実際に呼び出しているのはココ
実行結果は以下のようになる。期待通り。
$ ruby ./main.rb
4
晴れて Ruby から Go を呼び出すことができた。便利!
ライトニングトークでは、時間の都合上、上記の部分までの話しかしなかった (5 分という縛りだった) のだが、本手法は便利な話ばかりでもなくて不都合だとかやりにくいところだとかが色々ある。そもそも Ruby と Go に限らず、言語間バインディングなんて問題の巣窟になること請け合いであるというのが僕の印象であってだな。
上記のように int
を使っている間は特に問題がないのだけれども、もう少し便利に使おうと思ったら他の型 (特に byte array みたいなものとか string) を使いたくなるのが人情かと思う。
実はこのへんを扱うのは割と面倒で、何が面倒って「メモリの確保と解放」をそれなりに意識してやる必要が出てくる。
例えば、Go から文字列を返してやろうと思ったら以下のようなコードになる。
package main
import "C"
//export Fullname
func Fullname(firstname, lastname *C.char) *C.char {
fullname := C.GoString(firstname) + " " + C.GoString(lastname)
p := C.CString(fullname)
return C.CString(firstname + lastname)
}
func main() {}
このコードをざっくり解説すると、
Fullname
関数は、lastname
と firstname
を受け取って、連結したもの (つまり fullname
) を返す関数。string
を使うようなところでは、代わりに *C.char
を使うようにしている。string
を扱おうと思うと Ruby 側では構造体を扱う必要が出てきて少し面倒になってしまうので、生々しいが単なる *char
を扱うほうが簡単になる (と思う)。*C.char
はそのままでは Go の string
として扱えないので、いったん C.GoString
に食わせて string
に変換している。string
に対して一通りやりたい処理をやったあとに、string
を戻り値の型である *C.char
に変換する必要がある。C.CString
に string
を食わせると *C.char
型になって出てきてくれるのだが、C.CString
を使って生成した文字列は「メモリ解放」をしなければならない。しないとメモリリークになってしまう。そこまでケアすると以下のような感じになる。
Go の側。メモリ解放のための関数を追加した。
package main
import "C"
//export Fullname
func Fullname(firstname, lastname *C.char) *C.char {
fullname := C.GoString(firstname) + " " + C.GoString(lastname)
p := C.CString(fullname)
return p
}
//export Free
func Free(p *C.char) {
C.free(unsafe.Pointer(p))
}
func main() {}
Ruby の側。メモリ解放のための関数を呼び出すように変更。
require 'fiddle/import'
module M
extend Fiddle::Importer
dlload 'lib.so'
extern 'char* Fullname(char* p0, char* p1)'
extern 'void Free(char* p0)'
end
ptr = M.Fullname('pan', 'kona')
p ptr.to_s
M.Free(p)
実行結果は以下。
$ ruby ./main.rb
"pan kona"
おそらくこれでメモリリークはしない状態になっている、はず。
言語間バインディングは用法と用量を守って使うのだ。
gomobile という Go 言語で Android/iOS のアプリを作ろうというプロジェクト (準公式) が存在する。
ページはココ → gomobile の公式 wiki ページ - https://github.com/golang/go/wiki/Mobile
gomobile build
コマンド一発で Go のソースから APK が生成されるというなかなか豪快なコマンドなのであるが、
いかんせん色々制限があって、いざ何か作ってみようとするとまあまあハマる。
どんな苦行があるかは 手前味噌だが Qiita の記事 に何となく記しておいた。
上記記事には書いてなかったハマりポイントとして、**「ファイルを永続領域に保存する API がない」**というのがある。
ファイルを保存できないということは、ゲーム作ってて何かセーブデータでも保存しよう、とかそういうことができないってことである。
割と致命的である。
ただ、実は gomobile はパッケージ内に JNI を触る実装を持っていて (何故か internal パッケージなので外から触れないが) 、
それを参考にすれば、cgo 経由で JNI に触ることができる。
JNI に触れるということは、Java の API に触れるということで、それはすなわち Android SDK の API に触れるということである。
Go から Android SDK の API に触れるのである。
ググればさっさと出てくるが、Android アプリを作る際には以下のようなコードを書くと、
ファイルを永続保存できる領域へのディレクトリパスを取得できる (アプリアンインストールと共に削除される) 。
public class MyActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
String dir = this.getCacheDir().getAbsolutePath();
// dir にはファイル保存可能領域 (internal storage) への絶対パスが入る
}
}
つまりは上記と同様の処理を JNI で書いてやれば良い。
以下のようになる。
指定した関数を JNI 上で実行する関数 RunOnJVM
を定義しているパッケージ。
// +build android
package jni
/*
#cgo LDFLAGS: -landroid
#include <jni.h>
#include <stdlib.h>
JavaVM* current_vm;
jobject current_ctx;
static char *
_lockJNI(uintptr_t* envp, int* attachedp) {
JNIEnv* env;
if (current_vm == NULL) {
return "no current JVM";
}
*attachedp = 0;
switch ((*current_vm)->GetEnv(current_vm, (void**)&env, JNI_VERSION_1_6)) {
case JNI_OK:
break;
case JNI_EDETACHED:
if ((*current_vm)->AttachCurrentThread(current_vm, &env, 0) != 0) {
return "cannot attach to JVM";
}
*attachedp = 1;
break;
case JNI_EVERSION:
return "bad JNI version";
default:
return "unknown JNI error from GetEnv";
}
*envp = (uintptr_t)env;
return NULL;
}
static char *
_checkException(uintptr_t jnienv) {
jthrowable exc;
JNIEnv* env = (JNIEnv*)jnienv;
if (!(*env)->ExceptionCheck(env)) {
return NULL;
}
exc = (*env)->ExceptionOccurred(env);
(*env)->ExceptionClear(env);
jclass clazz = (*env)->FindClass(env, "java/lang/Throwable");
jmethodID toString = (*env)->GetMethodID(env, clazz, "toString", "()Ljava/lang/String;");
jobject msgStr = (*env)->CallObjectMethod(env, exc, toString);
return (char*)(*env)->GetStringUTFChars(env, msgStr, 0);
}
void
_unlockJNI() {
(*current_vm)->DetachCurrentThread(current_vm);
}
*/
import "C"
import (
"errors"
"runtime"
"unsafe"
)
func RunOnJVM(fn func(vm, env, ctx uintptr) error) error {
errch := make(chan error)
go func() {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
env := C.uintptr_t(0)
attached := C.int(0)
if errStr := C._lockJNI(&env, &attached); errStr != nil {
errch <- errors.New(C.GoString(errStr))
return
}
if attached != 0 {
defer C._unlockJNI()
}
vm := uintptr(unsafe.Pointer(C.current_vm)) // #nosec
if err := fn(vm, uintptr(env), uintptr(C.current_ctx)); err != nil {
errch <- err
return
}
if exc := C._checkException(env); exc != nil {
errch <- errors.New(C.GoString(exc))
C.free(unsafe.Pointer(exc)) // #nosec
return
}
errch <- nil
}()
return <-errch
}
上記 jni パッケージを使って、ファイル保存領域を取得するための関数を jni 上で実行する。
// +build android
package storage
/*
#include <jni.h>
#include <stdlib.h>
static const char *
getFilesDir(uintptr_t java_vm, uintptr_t jni_env, uintptr_t jni_ctx) {
JNIEnv* env = (JNIEnv*)jni_env;
jobject ctx = (jobject)jni_ctx;
jclass context = (*env)->FindClass(env, "android/content/Context");
if(context == NULL) {
return NULL;
}
jmethodID getFilesDir = (*env)->GetMethodID(env, context, "getFilesDir", "()Ljava/io/File;");
if(getFilesDir == NULL){
return NULL;
}
jobject f = (*env)->CallObjectMethod(env, ctx, getFilesDir);
if (f == NULL) {
return NULL;
}
jclass file = (*env)->FindClass(env, "java/io/File");
if (file == NULL) {
return NULL;
}
jmethodID getAbsolutePath = (*env)->GetMethodID(env, file, "getAbsolutePath", "()Ljava/lang/String;");
if (getAbsolutePath == NULL) {
return NULL;
}
jstring path = (jstring)(*env)->CallObjectMethod(env, f, getAbsolutePath);
return (*env)->GetStringUTFChars(env, path, 0);
}
*/
import "C"
import (
"unsafe"
"github.com/pankona/gomo-simra/simra/internal/jni"
"github.com/pankona/gomo-simra/simra/simlog"
)
type storageAndroid struct{}
func NewStorage() Storager {
return &storageAndroid{}
}
var path string
func (s *storageAndroid) DirectoryPath() string {
if path != "" {
return path
}
jni.RunOnJVM(
func(vm, env, ctx uintptr) error {
cpath := C.getFilesDir(C.uintptr_t(vm), C.uintptr_t(env), C.uintptr_t(ctx))
if cpath == nil {
simlog.Errorf("failed to get FilesDir!")
}
path = C.GoString(cpath)
C.free(unsafe.Pointer(cpath)) // #nosec
return nil
})
return path
}
上記で準備した関数を呼び出す部分。
func f() {
dir := storage.NewStorage().DirectoryPath()
fmt.Printf("path to internal storage: %s", dir)
}
これで、ファイル保存領域へのディレクトリパスを取得できる。
あとは、取得したディレクトリパス配下に保存したいものを保存する。
上記のコードで永続保存が可能な領域へのパスが取得できるので、それはそれで良いのであるが、
実はもっと手軽にファイル保存が可能な領域へのパスを取得できる方法があり、
それは環境変数 TMPDIR
を参照することである。
ただし、本値は Android SDK の API で言うところの Context.getCacheDir
に相当し、
Android 端末の状況によっては削除され得る領域であることに気をつける必要がある。
が、ちょっと保存したいくらいの用途であれば耐えうるような気がする。
以下のようにして取得する。
func f() {
dir := os.Getenv("TMPDIR")
fmt.Printf("path to internal storage (for cache): %s", dir)
}
2017.06.01 に DeNA さんにて、golang.tokyo #6 が行われました。
開幕は DeNA の方のお話だったんですが、何やら DeNA では Go エンジニアを色々募集しているようです!
サーバーのみならず、色んなフィールドで Go を使っているとのことです。
今日も大勢の方が参加されております。
出遅れて私はありつけなかったですが、開幕前からお寿司が振る舞われていました!
私はおビールいただきました。
今日は参加レポートをしてくれました。
主に 2017年8月上旬あたりにリリースされそうな Go 1.9 の話。
スライドはこちら。
https://www.slideshare.net/takuyaueda967/gopher-fest-2017
以下、話の中で気になって点のピックアップ。
型にエイリアスが張れるようになるとのこと。
以下のような書き方ができるようになる。
type Applicant = http.Client
この場合、Applicant と http.Client は等価。
いつこれが役立つかというと、型をリネームするようなリファクタリングを行うとき。
以下の手法だとうまく行かない。
(パターン1) 新しい型を作って順次移行する場合
type Applicant Client
(パターン2) 埋め込みを使う場合
type Applicant struct { Client }
型エイリアスを用いると、
http://tip.golang.org/pkg/math/bits/
各種ビット演算用の某がそろっております。
スレッドセーフなマップが追加に。
しかも make しないで 0 値のまま使えるらしく便利。
環境変数で指定されている値をコード上で上書きできなかった。
Go 1.9 からは後勝ち。より直感的な動作になる。コードで上書きできるように!
などなど。
スライドには出ていませんでしたが、個人的には mips32 向けの softfloat サポートがどうなったか気になります。Go 1.9 でサポートされるんだったような。
次は DeNA の方。
DeNA の方です。
AndApp を作ったときに得られた教訓の話。
Gin と Echo をさまよった話でさまざま苦労なさったそうな。
失敗談をメインに話してくださったので、そういうのは割と貴重と思います。
スライドはこちら。
https://www.slideshare.net/yuichi1004/golangtokyo-6-in-japanese
というようなことで、聞いているだけでしんどい気持ちでいっぱいでしたが、
結論としては、フレームワークに頼らずに net/http 使っとくのが一番や、という話でした。
ツールに振り回されるとツライですね。納得。
独自エラー型と error インターフェースを混在させると起こり得る罠。
独自 error は nil 扱いされない問題。
素直に error インターフェースの利用に統一するべきだという結論。
エラーの種類によって分岐したいとき等、結構ひとによってやり方がまちまちだという気がするので、
なにがしかデファクトスタンダードなやり方が示されていると良い気がしますね。
ちなみに、自分が書くときの「エラーで分岐」については、
deeeet さんの Golangのエラー処理とpkg/errors で記載されているやり方に従っている。
JSON Schema でバリデーション。
OSS として扱った二種の速度の話。
regex / reflection 等の処理は遅いので、使うときは意識しないといけない
以下、LT。
カヤックの方。
スライドはこちら
データの形によっては非常に見にくいCSV。
いい感じに整形してくれるツールを作った!
csvviewer
スターしておきました。
KLabの方。スライドはこちら。
https://speakerdeck.com/knsh14/go-code-review-comment-wofan-yi-sitahua
こういう記事があって、Effective Go 簡易版というか、Go のお作法初級編みたく書かれている。
Go Code review comments
それを日本語訳した!
初学者のみならず、ある程度経験がある人でも読んで損はないと思いました。
認識を改めるというかね。ちなみに社内勉強会で使わせていただきました、感謝!
エウレカの方。
スライドは発見できませんでした…。
Scala が好きということは分かりました。
悲しいアリクイかわいい。
マネーフォワードの方。
資料はこちら。アライさんですね。
https://paper.dropbox.com/doc/Crypto-in-Go-cWLX9XxHQm6bAPqrZYkjt
難しい。
ということで今回も参加させていただきました、ありがとうございました。
失敗談というかアンチパターンというか、そういう話が聞けたのは大きな収穫でした。
2017.06.15 現在、既に次の golang.tokyo が企画されています。
golang.tokyo #7
気になる方は要チェックです!
2017.03.01 に eureka さんにて、golang.tokyo #4 が行われました。
今回もまた大盛況で一般参加枠は倍率3倍くらいの抽選となっていましたが、
たまたまブログ枠が空いているところに遭遇してしまったため、またしてもブログ枠として
参加させていただきました。内容をレポートしていきます。
発表内容の詳細は、実際発表に用いられたスライド (上記 connpass のページから辿れます) を参照いただくのが一番良いと思いますので、
本記事ではその他、イベントの雰囲気や私の感想を主にお伝えしていくような体になります。
それではいきます。今回のテーマは 「concurrency」 。
Concurrency for distributed Web crawlers
(↑のカードをクリックでスライドに飛びます。)
クロール対象はシングルドメイン。だが対象となるアプリが多い (100k以上) 。
Commander と Crawler
1 アプリあたりのクロール時間が見積もれないと困る。
落とし穴シリーズ
Goroutine の内部実装について。
runtime を読む。
M、G、P という文字が頻繁に出てくる。それらの意味は、
Ridge - A framework like GAE/Go on AWS
Go で書いた HTTP Server を AWS Lambda で動かす…!
実質、GAE/Go みたいなことを AWS Lambda で実現できる
裏で goroutine を延々動かしておくみたいなことはできない。Lambda はレスポンス返し終わると寝てしまう。
頻繁にアクセスがなく、レイテンシ要求がシビアでないようなものに向く
EC2 使わず、それでいてリクエスト数が多ければスケールする、ということで用途が合えば非常にリーズナブルにできる印象。
写真1. ライブコーディング直前の kaneshin さん
「嫁のため」という免罪符を得て開発していくスタイル
写真2. Gogland の開発者 Sergey Ignatov さん
JetBrains から Sergey Ignatov さんが来てくれて、Gogland の紹介をしてくれたぞ!
ざっくりですが、かいつまんで golang.tokyo 4 回目の様子を紹介いたしました。
休憩時間にはビールも振る舞われたりして、無料でいいんですかという気持ちになります。
いつもありがとうございます。
次回もまた 4 月くらいに実施されるようなので、都合が合えば参加させていただこうかと思います。
2016.12.12 に表参道のはてなさんにて、golang.tokyo #2 が行われました。
今回もまたブログ枠にて参加させていただきましたので、
その内容をレポートしていきます。
発表内容の詳細はスライド (上記 connpass のページから辿れます) を参照いただくのが一番良いと思います。
本記事ではその他、イベントの雰囲気や私の感想を主にお伝えできればいいかなと思っています。
それでは行きます。
今回の golang.tokyo は 2 回目の開催。
今後も色々目論まれているようです。楽しみ。
図1. golang.tokyo について
golang.tokyo 2 回目のテーマは 「テスト」 について。
(↑のカードをクリックでスライドに飛びます。)
図2. 発表中の deeeet さん。
以下、印象に残ったところを抜粋。
テストのフレームワークは使わず、testing パッケージだけで十分であろうとの意見。
これは、フレームワークは「ミニDSL」であって、導入するひとはまだしも、
あとからプロジェクトに入ってくる人は学習する部分が増えてしんどくなってしまう、という一面があるからとのこと。
納得。
「Table Driven Test」 がおすすめ。
テストしにくくなるというのは「Table Driven Test」がやりにくくなる状況を指す。
→ 入力以外の要素が出力影響を及ぼしてしまう状況。
(↑のカードをクリックでスライドに飛びます。)
図3. 発表中の songmu さん
deeeet さん、songmu さんの発表のあと、いったん休憩に。
休憩ではピザとビールが振る舞われまして、はてなさんにスポンサーしていただいたとのこと。
ありがたくいただきました。
図4. ピザとビールをはてなさんから振る舞っていただく。
図5. 会場遠景。芝生です。
図6. deeeet さんにむらがる Gophers (私もこのあとむらがりました) 。
勉強会の真ん中にこういう親睦会的なノリの時間が設けられるのは珍しいかな?
なんだか新鮮でした。参加者の方とも少しだけお話できたりしました。
勉強会終わってからの親睦会だと参加できないケースが多い私のようなものにとっては、会の真ん中にこういうのやってもらうのもいいかもしれない。
ピザとビールで温まってきたところで LT 開始。
Continuous Deployment with Go on AWS ECS
以上の内容でした。せめて雰囲気くらい伝わればいいですが。
いずれの発表もとても内容が濃くて、勉強になりっぱなしでした。感謝。
ひとまず Table Driven Test ですかね。取り入れてなかったのでやってみようか等と思い。
感謝といえば、運営サイドのこと。
ほぼトラブルなしでスムーズに進んだのは、十分に準備してくれていたということだと思います。
だいたいマイクの電池が切れたりスライドがうまく映らなかったり、そういうの対策しようがなくてしょうがないところもあるんですが、
今回に関してはそういうのほぼほぼなくて、というかマイクの音量とか超ちょうど良くて、本当に細かい配慮を感じました。多謝。
他にも、アンケートを集めて次回のネタにしたりしていて (今回のテーマも、前回のアンケートでテストに関することを聞きたいという要望が多かったから、という理由で選んだとのこと)、golang.tokyo 運営すげーなという印象です。すげーな!
次回もまた来年に予定されているようです。楽しみにしています!
2016.10.25 に六本木の森タワーメルカリさんにて、golang.tokyo #1 が行われました。
以下に togetter まとまってます。
メルカリ本社で開催されたGo言語勉強会 golang.tokyo #1 #golangtokyo - Togetterまとめ
参加者の方のまとめです。きれいにまとまっていて読み応えあります。
Hello Gophers, Hello Golang.tokyo #1 - 365 simple life - g.o.a.t
本イベントにブログ枠にして参加させていただきましたので、
その内容をレポートしていきます。
図1. 入り口にていただいたステッカー。にゃってとごっふぁーくん。かわゆし。
いわゆる一般的な勉強会(?)でやるような、「数人の発表者が順繰りにスライドを用いて発表を行っていく」という体ではなく、パネルディスカッション形式。
事前に収集された質問に対して、パネラーの方々が体験談を踏まえて回答をしていく、というのが主な内容。
名だたる5名のパネラーさん達の詳細については、connpass のイベントページを参照いただきたい。
図2. 司会の tenntenn さん。
図3. 向かって左正面。Songmu さん、大谷さん、kaneshin さん。
図4. 向かって右正面。y_matsuwitter さん、辻さん。
写真遠いし真っ黒やんけ。しかし顔で勉強会するわけじゃないということでご容赦いただければと思います。
ちなみに開始当初から軽食、おビールなんかも振る舞われており、20時前開始という、
おそらく夕飯食べてないであろう我々には、とても良い環境を提供いただいておりました。
メルカリさん、いつもありがとうございます。
Google Apps のどの機能なのかちょっと失念してしまったのですが、
本番中も質問を次々ポストできる形式になっていて+既存の質問に対してイイねが可能になっていて、
みんなが聞きたい質問が優先的に採用されてディスカッションされるというスキームでした。
あんまり見かけないやり方だなぁと思いつつ、視聴者参加型で面白い仕組みだと思いましたので、
今後もやってくれたらいいなー、と感想を残しておきます。
前置きが長くなってしまいましたが、
ここからは実際どのような質問がされ、どのように回答がなされたのかを載せていきます。
※ 全部載せるとだだ長くなってしまうので、独断と偏見で端折りつつ、お送ります。
Go に馴染みのないメンバーにどうやって Go を学んでもらうか?というトピック。
図5. そしてディスカッションが始まった
Go でデバッガといえば delve かと思ったが、思ったより使われていないのかなという印象。
ちょこちょこテスト書いて動かしていけば、それほど難儀なデバッグが必要になることも少ないっていうことかしら?
個人的には、従うと腹を決めて一度クリーンな状態になれば、あとはさほど苦ではないと思うが、はたして。
図6.songmu さん回答中。
みな口々に「Go のテンプレートはツライ」と言っていたのが印象的でした…。
sync.ErrorGroup の使い方について、
ちょうど近頃類似トピックの記事 - sync.ErrGroupで複数のgoroutineを制御するをポストされていた deeeet さん (※ e は 4つ) からのコメント。
図7. deeeet さん (一番奥)。
ロガーは logrus が定番といった空気でした。
パッケージ分けは割と悩むポイントかと思いますが、はたして。
あとは、以下のような意見も。
Go のビルドは一般的には早いと言われているが、遅いとしたらそれは何故かと言うと…?
これは例えば、A が B に依存していて、B が C に依存している、なんていうシチュエーションのとき、C を変更したら依存を遡って B も A もビルドが走ってしまう、ということが起こる模様。
ちょうど C言語の include と同じような感じかな。ヘッダー変えたら全ビルド走っちゃうみたいな。
個人的には Go でビルド速度にそれほど苦を感じたことはないが、とはいえ、留意されたしである。
概ね、以上のトピックスでディスカッションが行われました。
他にも、回答は得られませんでしたが、
図8. Go言語プログラマの給料はいかほどか…
なんていう質問も出たり。
ネタも挟みつつ、終始知見に溢れた有意義なディスカッションでありました。
運営の方々、登壇の方々、お疲れ様でした!
golang.tokyo #2 も計画されていると噂を聞きますので、
興味を持たれた方、チェックしてみてはいかがでしょうか。
Go 言語に興味さえあれば、参加して楽しいかと思います。
図9. 戦利品としてTシャツいただきました!