Dockerコンテナで開発環境を構築しましたよ
2021/03/16
DevContainerを使ったGolangとReactの開発環境です。
golangのCLIツールで複数のオプションを受け取る
2020/07/28
golangでCLIツールを作る話です。
Go×ReactでWebsocket通信
2020/04/30
GoとReactでWebsocket通信の入門をしましたよ。
TOMLをGolangで読み込もうとして躓いた話
2020/02/03
GolangでTOMLファイルに書かれた設定を読み込もうした時に躓いたのでメモを残しておきます。 …
Golangのスコープについて
2019/02/09
はじめに Golangを書いてて詰まったことがあったのでメモです。 本文 こんな感じでカテゴリ、商品名、価格を持った構造体のスライスがあるとします。 type product struct { category string name string price uint64 } showcase := []product{ {"果物", "りんご", 120}, {"果物", "バナナ", 100}, {"果物", "みかん", 70}, {"肉", "鶏もも", 250}, {"肉", "豚バラ", 300}, {"肉", "カルビ", 450}, } で、このスライスから果物の価格だけ10円引きします。 for _, v := range showcase { if v.category == "果物" { v.price -= 10 } } こんな感じで書いたのですが、上のfor文だとshowcaseの中身は変更されません。 変数のスコープを考えてなかったのが原因です。 変数vはfor文の中でしか使えないので、いくらvの中身を変更してもshowcaseの中身は変わりません。 for i := 0; i < len(showcase); i++ { if showcase[i].category == "果物" { showcase[i].…
Golangでテストコードを書く少年のお話
2019/01/22
はじめに お仕事でGolangのテストコードを書くことになったのでお勉強しました。 テスト対象は以下のプログラムです。 毎朝のルーティンを明文化し、以下の処理をしています。 降水確率40%以上なら傘を装備する。 冬、もしくは最低気温が5度以下ならコートを装備する。 以下の通り、4つの命令と2つの条件分岐で構成されています。 項 種別 やってること ① 命令 持ち物を入れるカバンを用意 ② 条件分岐 降水確率による判定 ③ 命令 カバンに傘を入れる ④ 条件分岐 季節、最低気温による判定 ⑤ 命令 カバンにコートを入れる ⑥ 命令 カバンを持ち出す テストの種類 カバレッジとはテストの網羅率のことを指しています。 「どのパターンのテストを行えば、必要な範囲のテストが完了したのか?」の指標となります。 「必要な範囲」については、C0カバレッジ、C1カバレッジ、C2カバレッジ…とカバレッジの種類によって異なります。 それぞのカバレッジについて簡単に説明していきます。 ※C3以降もありますが、よく使われるのはC2までみたいなので、今回は省略します。 C0カバレッジ(命令網羅) すべての命令を最低1回は実行する、というテストケースを満たせばカバレッジが100%になります。 以下のパターンを実行すれば、すべての命令を実行することができるので、C0カバレッジ100%になります。 「降水確率が50%、季節は冬、最低気温12度。」 C1カバレッジ(分岐網羅) すべて条件分岐の組み合わせを通る、というテストケースを満たせばカバレッジが100%になります。 今回はTrue/Falseの分岐が2つあるので4パターンの組み合わせでテストを行う必要があります。 パターン ② ④ 具体例 パターン1 True True 降水確率が50%、季節は冬、最低気温12度。 パターン2 True False 降水確率が50%、季節は春、最低気温12度。 パターン3 False True 降水確率が20%、季節は冬、最低気温12度。 パターン4 False False 降水確率が20%、季節は春、最低気温12度。 具体的には以下のパラメータでテストをやればOKです。 C2カバレッジ(条件網羅率) すべての条件の組み合わせを通る、というテストケースを満たせばカバレッジが100%になります。 C1カバレッジと似ていますが、C1カバレッジは条件分岐の結果をすべて通ればOKですが、C2カバレッジではすべての条件の結果を通る必要があります。 今回のケースだと、「冬か?」と「最低気温が5度以下か?」という2つの条件のそれぞれに対してTrue/Falseの組み合わせを試す必要があります。 そのため、④の条件分岐を2つに分割し、以下のパターンのテストが必要になります。 パターン ② ④-1 ④-2 具体例 パターン1 True True True 降水確率が20%、季節は冬、最低気温2度。 パターン2 True True False 降水確率が20%、季節は冬、最低気温12度。 パターン3 True False True 降水確率が20%、季節は春、最低気温2度。 パターン4 True False False 降水確率が20%、季節は春、最低気温12度。 パターン5 False True True 降水確率が50%、季節は冬、最低気温2度。 パターン6 False True False 降水確率が50%、季節は冬、最低気温12度。 パターン7 False False False 降水確率が50%、季節は春、最低気温2度。 パターン8 False False True 降水確率が50%、季節は春、最低気温12度。 具体的には以下のパラメータでテストをやればOKです。…
Golangのpanicのお話
2018/11/21
はじめに Golangというと、クロスコンパイルが特徴の1つとして挙げられます。 クロスコンパイルにより、Macで書いたコードからLinuxやWindows向けの実行ファイルを簡単に生成することができます。そのため、業務で使う便利ツールを作ってチーム内に配る、といったことも容易に行えます。 今回は僕がGolangを書き始めたばかりのころ、他の環境で動かすツールを作ったときに驚いた思い出ばなしです。 サンプルコード 実際のコードとは違いますが、当時は以下のようにエラーが発生したらpanic()で処理を中断させるコードを書いていました。 で、このコードを以下のようなディレクトリ構成の中に配置していました。log_analysisが1つのプロジェクトというイメージです。 tmp └── tanaka └── azunyan_prpr └── tools └── log_analysis └── main.go このコードをmitchellh/goxを使ってクロスコンパイルすると、以下のように各プラットフォームに対応した実行ファイルが生成されます。 $ gox Number of parallel builds: 3 --> freebsd/amd64: _/tmp/tanaka/azunyan_prpr/tools/log_analysis --> netbsd/arm: _/tmp/tanaka/azunyan_prpr/tools/log_analysis --> linux/386: _/tmp/tanaka/azunyan_prpr/tools/log_analysis --> darwin/386: _/tmp/tanaka/azunyan_prpr/tools/log_analysis --> windows/amd64: _/tmp/tanaka/azunyan_prpr/tools/log_analysis --> openbsd/386: _/tmp/tanaka/azunyan_prpr/tools/log_analysis --> openbsd/amd64: _/tmp/tanaka/azunyan_prpr/tools/log_analysis --> windows/386: _/tmp/tanaka/azunyan_prpr/tools/log_analysis --> netbsd/386: _/tmp/tanaka/azunyan_prpr/tools/log_analysis --> freebsd/arm: _/tmp/tanaka/azunyan_prpr/tools/log_analysis --> darwin/amd64: _/tmp/tanaka/azunyan_prpr/tools/log_analysis --> linux/arm: _/tmp/tanaka/azunyan_prpr/tools/log_analysis --> linux/amd64: _/tmp/tanaka/azunyan_prpr/tools/log_analysis --> freebsd/386: _/tmp/tanaka/azunyan_prpr/tools/log_analysis --> netbsd/amd64: _/tmp/tanaka/azunyan_prpr/tools/log_analysis $ ls -1 log_analysis_darwin_386 log_analysis_darwin_amd64 log_analysis_freebsd_386 log_analysis_freebsd_amd64 log_analysis_freebsd_arm log_analysis_linux_386 log_analysis_linux_amd64 log_analysis_linux_arm log_analysis_netbsd_386 log_analysis_netbsd_amd64 log_analysis_netbsd_arm log_analysis_openbsd_386 log_analysis_openbsd_amd64 log_analysis_windows_386.…
GAEでバッチ処理
2018/11/07
はじめに Google App Engine(GAE)を使って、バッチ処理が実行できたのでメモです。 GAEではcron.yamlに設定を記載することで時間を指定した処理を行うことができます。 サンプル 今回は、slackにメッセージを送信するアプリを定期的に実行させてみます。 slackにメッセージを送る部分は以下のサイトに詳しく記載されているので省略します。 CrossBridge Lab | GolangでSlackの特定のチャンネルにメッセージを送る 今回はGAE上でGolangを動かしてみましたよの構成を元に、GAEのプロジェクトを構築します。 ルートディレクトリ(app.yamlと同じ階層)にcrom.yamlを作成します。 cron.yaml cron.yamlには、以下のように開始時刻や間隔で実行するタイミングを指定することが出来ます。 cron: - description: "毎朝7時(日本時間)に実行" url: /morning timezone: Asia/Tokyo schedule: every day 7:00 - description: "毎週日曜8時(日本時間)に実行" url: /morning timezone: Asia/Tokyo schedule: every sunday 8:00 - description: "毎日0時を起点とし、1時間単位で実行" url: /morning timezone: Asia/Tokyo schedule: every 1 hours その他のスケジュール指定方法や、HTTPリクエスト失敗時のリトライ回数は公式のドキュメントに詳しく記載されています。 注意点 GAEではdev_server.pyでローカルにサーバを立ち上げて、動作確認をすることができます。しかし、ローカル環境では、cron.yamlは動作しません。 localhost:8000 からGAEローカル環境の管理画面を開くことができます。 管理画面にcron.yamlで設定したスケジュールが一覧で表示されるので、Run nowをクリックすることで手動で実行することができます。 Cronの設定を本番環境にデプロイするときは、gcloud app deploy cron.yamlのようにcrom.yamlを指定します。 指定しないと、crom.yamlが読み込まれないため、いつまで待っても処理が実行されません。 Cronが設定されているかどうかは、コンソール画面のcronジョブから確認することが出来ます。 仮に他のユーザからHTTPでのリクエストがあった場合、想定していない時間に処理が実行される可能性があります。 そのため、GAEのcronサービスからのHTTPアクセス以外からのアクセスは除外する必要があります。 GAEのcronサービスからのHTTPアクセスにはHTTPヘッダにX-Appengine-Cron: trueが含まれているので、HTTPリクエストを受け取ったタイミングで、チェックする必要があります 例えば、GolangでGAEのcronサービス以外からのHTTPリクエストを弾くには、以下のように書きます。 (弾いた後の処理がお粗末ですが…) // cron以外からのアクセスは弾く if r.…
祝日のカウントダウンタイマー
2018/10/30
はじめに GoogleAppEngine(GAE)、Golangの勉強のために、祝日までのカウントダウンタイマーを表示するWebページを作ってみました。 https://shukujitsu.info 処理の内容 内閣府が祝日の情報をCSV形式で公開しているので、定期的に取得して、加工して、CloudStorageにアップロードしています。 GAEにアクセスがあると、CloudStorageから祝日情報を読み込んで、いい感じに加工して表示しています。 使ってる技術 GoogleAppEngine インフラとしてGAEを使いました。 GAEに対応していない関数とかもあるので、ドキュメントを見ながら覚えていくしかなさそうです。 たとえば、GolangでHTTPのリクエストを行うときにhttp.Get()を使いますが、GAEでは対応していないのでurlfetch.Clientを使う必要があります。 他にも、Javaでは時刻を扱うjava.time.LocalDateというライブラリがあるのですが、同様にGAEでは使うことができません。 GAE使うなら言語に依らず注意する必要があります。 Golang ネット上に公開されているCSVファイルを読み込んで、Cloud Storageにアップロードする部分をやってます。 もともと、Golangの勉強を兼ねたプロジェクトだったんですが、あまりGolangを使いませんでした。 Vue.js JavaScriptで変数を書き換えると、いい感じにHTMLで表示される内容も変更されます。 まだVue.jsを使いこなせてはいませんが、低い学習コストでさっくり使うことができます。 Scrollify マウススクロールでいい感じに画面を切り替える処理はScrollifyを使いました。 これを使うだけで今風な感じがでます。 今後の課題 データ保管場所 情報をCloudStorageに保存してるので、NoSQLを触ってみようかと考え中です。 日付と祝日名を格納するだけなのでRDBでも問題ないんですけど… 監視、ログ なんらかのエラーが起きた場合はソーリー画面を出し、StackDriver上にログを出すようにしていますが、能動的にチェックしないとエラーに気が付きません。 エラーを検知したら通知する仕組みがほしいですね、LINEかSlackに飛ばすのが今風でしょうか… パッケージ管理 使用しているライブラリのバージョン管理とかをしていないので、一般的に使われている(らしい)、depを使ってみようかと考え中。 次バージョンのGolangではmodulesという新たなパッケージ管理機能が正式リリース予定なので、最終的にはそっちに映る感じでしょうか。 リファクタリング ディレクトリ階層がぐちゃぐちゃで、1つ1つのファイルも肥大化しているのでキレイにしたいです。 ある程度キレイになったらリポジトリを公開するのもアリですね。 CIツール導入 現在、dev_appserver.pyでローカル環境を立ち上げて、動作チェックが済んだらgcloud app deployで本番環境を更新する、という雑な運用をしています。 雑すぎるので、CircleCIとかを使って、PR投げたらステージング環境でテストが実行されてー、というのを導入したいです。 AltJS 「素のJavaScriptを書くのがツラい」という話を聞くことが増えてきました。 この規模なら素のJavaScriptでも問題ないですが、今後のことを考えるとTypeScriptかCoffeeScriptあたりを勉強して置き換えることを考え中です。 WPA化 WPAであれば、オンライン状態でアクセスしておけば、オフライン状態でもそのWebサイトにアクセスができるようです。 地下鉄などの電波状況が悪い場所でも祝日カウンターが使えれば素敵ですね。 見た目 レイアウト気にし始めるとキリがないので一旦リリースしてしまいました。 運用しながら徐々に変更を加える予定です。 感想 本当はcoinhive仕込みたかったけど神奈川県警に捕まったらいやなので我慢しました。 認証も、DBへのアクセスもないページですが、1人でインフラ、サーバサイド、フロントエンドの構築を行ったのでいろいろと勉強になりました。 細々としたTipsはブログに残していきたいです。 課題もたくさん出てきたので、徐々に直していきます。 欲しい機能とか、気になる箇所があれば、お気軽に@foresukecomまでご連絡下さい。 その他 ここ数年、ウィルキンソンの炭酸水をAmazonで定期購入してます。炭酸水のおかげで、ビールを飲む量がだいぶ減りました。 でも、炭酸水はウイスキーのチェイサーに最適なんですよね…割れば簡単にハイボールも作れるし… 悩ましい飲み物です。
GAE上でGolangを動かしてみましたよ
2018/08/13
はじめに GoogleAppEngine上で動くwebサービスをgolangで作りはじめました。 作り始めでつまずくことが多いので自分用の最小構成メモです。 ここで説明するwebサービスは、Ajaxで非同期通信し、Golangが返した文字列を表示するだけのものです。 環境の準備 まずは、GCPの公式ドキュメントを参考にGolang、Cloud SDKをダウンロードします。 以下のようにバージョンが表示されればOKです。 $ goapp version go version 1.9.4 (appengine-1.9.74) darwin/amd64 ちなみに、開発にはmacOS High Sierra(10.13.6)を使用しています。 構成説明 ディレクトリ構成は以下の通りです。 ├── app.yaml ├── hello.go └── static ├── js │ └── main.js ├── css │ └── main.css └── index.html この中でGAE特有のファイルはapp.yamlになります。 app.yamlリファレンスに各パラメータの説明が載ってますが、最低限のパラメータだけ書いておきます。 runtime: go #Golangを使用する場合はgoを指定 api_version: go1 #最新のバージョンを使用する場合はgo1を指定 handlers: #リクエストと実行する処理をURLパターン毎に指定 - url: / static_files: static/index.html upload: static/index.html - url: /js static_dir: static/js - url: /css static_dir: static/css - url: /.* script: _go_app その他のファイルについては、特別なことはしていないので説明は省略します。…