#goネットワークやディスクへの読み書き処理の際、帯域幅制御をしたい場合があります。低優先度の処理などによって主となるビジネスロジックが阻害されないよう制御するといった目的や、一つのサーバ資源で複数のサービスを提供するときに一つのサービスが資源を消費しすぎないようにしたいといった目的があります。Goでこのような処理を書きたいとき、ざっと調べてみたところgo-flowrateという実装が見つかりました。...}使い方もシンプルできっちり制御できるのでこれでいいのですが、制御できるのが一つのio.Readerまたはio.Writerのみに対してのみ可能で、複数のio.Readerやio.Writerに対しては制御することができません。並列処理が必要なプログラムを書いているとちょっとこれではそのまま使えそうにありません。ほかの選択肢を探してもよいのですが、ちょうどいいGoのプログラミング課題ということで新しく実装してみることにしました。出来上がりまずはでき上がったライブラリを紹介します。bwlimitとしてGithub上に公開してあります。利用例は次のようなイメージです。bwlimit.Wait()}まずは帯域幅制御を制御するオブジェクト(上図ではbwlimit)を作り、さらにそれぞれラッパーを作成します。NewBwlimitの第二引数は帯域幅制限しているときRead/Write処理を待たせるかどうかです。あとはラッパーを普通のio.Readerとして扱うだけです。並列処理をしていて、すべてのReaderまたはWriterについて処理が完了したかどうか知りたくなったので待機するWait()もつくりました。仕組みキューを作る方法などいくつか実装方法を検討しましたが最終的にはかなりシンプルな構造になりました。トヨタ生産方式の本を思い出してヒントを得ました。タクトタイムという一定時間のリズムを刻んで、各拍子のタイミングで利用可能な帯域を現在有効なReader/Writerで分割して利用するアイデアです。タクトタイムを1秒間に10回に設定したとします。帯域幅設定を1000バイト/秒にした場合、タクトタイム1回あたりに利用可能な帯域幅は100バイトです。有効なReaderが2つであればこの100バイトをわけあって、50バイトずつの読み取りを許可する枠を設定します。実際に、Reader側が読み取るかどうかはわかりませんが、読み取り可能な上限を制御することでこのような流量制御を行っています。50バイト分にはしないようにしました。流量はこれによってすこし減ってしまいますが、意図しない障害を防ぐためです。読み取り可能枠が溜まりにたまって一気に転送が行われてしまうと、他のサービスへ影響がでることはもちろん、場合によってはルーターなどのバッファサイズを超えるなどして障害が発生することも考えられます。利用例また別の記事として各予定ですが、Dropboxへのファイルアップローダーをいま作っています。このファイルアップローダーで並列してファイルのアップロードをする際に、帯域幅制御をつけたかったのがこのライブラリ作成のモチベーションです。#securityMacでたくさんのファイルをひとまとめにするのであればzipで圧縮するよりも、ディスクイメージファイルにしたほうが便利なこともあります。zipだと標準では中身を確認するのに毎回どこかに展開しないといけないですし、ファイルの内容を変更するのも面倒です。zip用のツールを使えばおそらくそれらも解決できると思いますが、個人的にはディスクイメージファイル(.dmg)を使うことの方が多いです。ディスクイメージファイルは外付けディスクのようなイメージでマウントして使えます。macOSに標準添付されている「ディスクユーティリティー」ツールを使えばこのイメージファイルを簡単に作ることができます。オプションを選ぶこともできます。終了したプロジェクトのファイル一式は.dmgファイルとしてまとめていますが、まとめたいプロジェクトファイルがたくさんあったり、ワークフローを自動化したいとなってくるとコマンドライン操作を覚えると便利です。ディスクイメージファイルの作成hdiutilコマンドを使うとディスクイメージファイルの作成や設定変更、ディスクイメージファイルのマウント、アンマウントなどさまざま操作可能です。hdiutilをご参照いただくとして手元での利用例をご紹介します。フォルダ以下にあるサブフォルダをそれぞれ.dmgとして一括変換したい場合に使っているスクリプトです。それぞれ一応暗号化しておこうということで、暗号化用のパスワードを$HOME/.dmg-passwordというファイルにあらかじめ格納してあります。パスワードファイルには最後に改行が入らないようにつくっておいてください。$HOME/.dmg-passwordなど他者から読み出せないようにしておきます。はいっても、後述しますが一連のプロセスはさほど安全性が高いわけではありませんので「添付ファイルはパスワードつきzipでパスワードは別メールですぐ送信!」とあまり変わらないセキュリティーレベルとお考えいただいていいかと思います。fidoneディスクイメージファイルのパスワードをKeyChainにプリセットしておく暗号化しておいたのはいいですが、作成したディスクイメージファイルを開く際にいちいちパスワードを入力するのは面倒です。Finderからダブルクリックしてマウントしようとしたときに聞かれるパスワードダイアログはコピー&ペーストを受け入れてくれないというのもさらに面倒さを増しています。パスワードをキーチェインに記憶させるというオプションがありますが、あらかじめコマンドラインから記憶させておけばいいという発想です。ディスクイメージファイルに対するパスワードは一般パスワードとして各ディスクイメージファイルのUUIDと対応して管理されています。ディスクイメージファイル.dmgというようにisencryptedオプションで知ることができます。(パスワード)というように実行すればよいでしょう。securityコマンドの大変残念な点はhdiutilの-stdinpassのように標準入力からパスワードを受け取る手段がどうやらなさそうな点です。コマンド引数として実行してしまうと、シェルの履歴に残ったり、psコマンドなどでパスワードが漏えいしてしまうケースがあります。このような点から上述のように「添付ファイルはパスワードつきzipでパスワードは別メールですぐ送信!」というセキュリティーレベルとたいして変わらないと思っています。上記を合わせて次のようなスクリプトにしてあります。$PWD)doneこのようにキーチェインにパスワードを設定したファイルを開こうとすると次のようにキーチェインからパスワードを取り出していいか確認されます。このダイアログをsecurityコマンドの-Aオプションでスキップする手段もありますがすべてのアプリケーションに対して許可を出してしまいます。面倒ですが、ここは一手間かけておいたほうがいいでしょう。#tumblr3年ほど前にWordPressからTumblrへ移行しました。大きな問題があったわけではないのですが、最近ソースコードを挿入した記事をいくつか書こうとしたところTumblrのMarkdownではうまく表現され切れない点にすこしストレスを感じていました。Markdown)で書けるようなサービスか、システムに移行しようと考え始めました。Pagesへ移行するのがスムーズそうだなと調べ始めて評価し、次の点で問題なさそうだったので移行することにしました。GFMで書ける既存のURL構成を引き継げるTumblrからの記事取り込みもできるシンプルなテーマがある逆に移行に当たってできなくなる機能もあります。ソーシャルメディア連携です。Tumblrでホストしてもらえば、Tumblr上のソーシャルメディアでリブログなど拡散手段があります。ほかには予約投稿やTwitter連携といった機能も使えなくなります。このあたりはトレードオフですが、ソーシャルメディアで拡散していただくよりも、そもそも記事が書きづらくて筆無精になるのであれば優先順位は明らかです。pushするよう何か構成を考えればいいだけです。移行中のあれこれは後述することにしてまずは、移行によってどういったメリットがあったかみてみます。WordPressから移行した際にはサイトの速度が劇的に改善しましたが、今回は比較的軽微な差に収まっています。TumblrでのPageSpeed結果まずはTumblrでのPageSpeed計測結果から。モバイル用のスコアは67点。画像サイズが大きいと警告がでているのと、キャッシュ設定などのところで最適化の余地があるとの判定です。デスクトップ用のスコアは77点。モバイルと同様に画像が大きいと警告が出ています。いずれにしても体感的にはもっさりした感覚は全くなく、表示速度などの不満は特にありませんでした。PagesでPageSpeed結果モバイル用のスコアは72点と少しだけTumblrでの表示より改善しています。これはTumblrのインフラスピードとの差というよりは、採用しているテーマのCSSやJavaScriptの差がほとんどだと考えられます。デスクトップ用のスコアは77点とTumblrでの結果と同じです。その他の違いTumblrではモバイル対応していないテーマを使っていたので、TumblrのUIが優先して表示されています。Feelでサイトを表示できるようになりました。移行作業はJekyllの使い方を覚えるところから全部でおおよそ5〜6時間かかったかと思います。Jekyllはかなり活発に開発されているようなのであまりここで細々と手順を書いてもすぐ使いもにならなくなってしまう気がするのでおおまかな流れだけご紹介しておきます。最近はこの手のツールを使うときはすべてDockerを使って独立した環境で実行するようにしています。再現性もありますし、手元の環境もシンプルに保てます。Jekyllを使うには既存のDockerイメージを使えば充分ですが、いくつかテーマを試したりしているうちに依存関係のあるライブラリをまとめてイメージとして持っていたほうが便利だったので次のような内容のDockerfileを作っています。jekyll-importjekyll-importは後述のTumblrから記事を取り込んだときに使ったものです。このDockerfileをビルドしておきます。siteディレクトリ以下につくっていくならこんな感じにコンテナを実行して、テンプレートを作ったりjekyll-importを実行したりできます。bash今回はあれこれテーマをダウンロードし、jekyll-importでTumblrから記事をざっくり取り込んで表示確認をしながらレイアウトを決定しました。Tumblrからのインポートjekyll-importのTumblrについての記事にコマンドが書かれていますのでこれを実行します。移行といっても今回はTumblrで書いた記事が12記事しかなかったので、ある程度の部分は詳しく調べずに手作業でファイルを修正していくというスタイルで解決しました。今回実行した際は次のように実行しました。})'最初formatはMarkdown(md)を指定していましたが、うまく記事が取りこめなかったのでhtmlで取り込み、あとで手動でMarkdownに変換しました。/post/(記事ID)/(記事タイトル)というフォーマットでしたが、Jekyllでは/(年)/(月)/(日)/(記事タイトル)となるので変換が必要です。rewrite_urlsで相当するアドレスにリダイレクトするファイルを作ってくれるので、リンクはそのまま維持できます。困ったことに生々されたリダイレクト用のindex.htmlでは/(年)-(月)-(日)-(記事タイトル)へのリダイレクトになっていてうまく動きません。あれこれ探すのも面倒だったのでここは手動で直してしまいました。grab_imagesという設定があり画像をもってきてくれそうな印象がありましたが、これもうまく動かなかったので手作業で画像をもってきたり、手元に保存してあったものを使ったりして再構成しました。テーマ選びいくつかサンプルを見ながら選びましたがシンプルなものがよかったのでLanyonにしました。ほかにもシンプルなデザインのものはありましたが、Lanyonは欲しい機能がおおむね入っていることと、CSSやJavaScriptを含めても全体の構成がシンプルで全体が見渡しやすいことが気に入りました。Pagesへプッシュし、あとはCloudFlareでDNSの切り替えをすれば終了です。Jekyllも開発スピードが速そうなので、開発についていくとしたらかなり大変そうです。でき上がったサイトはかなりシンプルなHTML、CSS、JavaScriptと画像ファイルだけで構成されているのでセキュリティー上の理由などで更新しなければいけないケースはかなり少ないと思います。いった意味では、一度環境ができ上がってしまえばTumblrでプレビューにあれこれ悩みながら記事を書くよりも手元の環境で確実なプレビューを見てから公開できるワークフローをつくったほうがより生産性が高そうだということで今は満足しています。画像を含めたオーサリングのワークフローをつくったり、プレビューから予定投稿などまでいろいろ作り込みたいところですがそのあたりはまた今度じっくり作り込んでみることにします。Business向けのツールをちょこちょこと開発しています。APIは一般的なOAuth2を使った認証と、HTTPでのAPIのためたいていのプログラミング言語で簡単に扱えます。DropboxからPython、Ruby、Java、JavaScript、.NET、Objective-C、SwiftなどSDKもリリースされているのでこれらを使えばより簡単です。ちなみにこれほど多くのSDKをメンテナンスするのはかなり手間ですが、それを解消するためにStoneというオープンソースが公開されています。StoneはAPI仕様記述からSDKを生成するツールで一度この仕様記述をメンテナンスしていけばSDKは自動生成できます。APIの仕様についても同様にStoneでの仕様記述があり、公開されているSDKは自動生成されたものをベースにしています。つくったツール作成したのは下記二つのツールです。Businessチームに関するメンバー一覧などをレポートとしてCSVで出力するいずれもCLIツールでシステム管理者が利用する想定のものです。昨今はシステム管理といってもWindowsだけでなくMacなど様々なシステム環境があります。このように利用用途からかんがえて複数プラットホームで利用できたほうが便利なので、個人的には初めてとなるGolangを採用してみました。Golang一番最近よく使っていたプログラミング言語はScalaだったので、カルチャーギャップというか、プログラミング言語がもつ信念のようなところに大きな差があって少し戸惑いました。Scalaのようなオブジェクト指向的にも関数型的にもかけるプログラミング言語の直後ということもあって、Golangの書き方はややまどろっこしく感じます。このまどろっこしさも次第に慣れていくことで、また考え方がわかってきたことでさほど気にならなくなってきました。O(n)のように変わるような書き方はあえてさせないことで、関数を使う側がどういうオーダーの計算量を常に意識させるようにしている」というような説明がありました。Golangのテストフレームワークがassertをあえて実装していない、といったこともそうですが、プログラミング言語やフレームワークで様々なヒューマンエラーを減らしていこうとする考え方とはまた違う思想を感じます。この考え方を真に受けてコードを書いていったので、でき上がったプログラムはにたようなforループやif分岐がたくさんでき上がりました。今回、コードをかくに当たってあまり他の方のコードを読んだりしなかったので本流とはだいぶ外れているかもしれません。パッケージ管理Golangで戸惑ったのがパッケージ管理です。GoのプログラムはGOPATH環境変数で指定したディレクトリ以下にすべての依存ファイル、そして自分のプロジェクトファイルも置いていくという方式です。GOPATH以下に置いていきます。getコマンドを経由して同様にGOPATH以下に配置します。dcfgひょっとすると、Goの考え方でAPIは一度公開したならば同じ名前で同じように使えるべき。いう信念があるのかもしれません。この方式で困るのは複数プロジェクトを進行しているときに、異なるバージョンのライブラリを利用したいや、ライブラリのバージョンをしばらく固定しておきたいときにはやっかいです。別の環境でビルドする際にも依存するライブラリの管理が煩雑になります。いった問題に対しRubyであればgem、Javaなどではmaven、gradle、sbtなどパッケージ管理は様々あり、これらで管理するのが当たり前という風なイメージを持っています。Golangでも同じようなものを探してみましたが、いまひとつこれといったものがどれなのかわかりませんでした。これも今回はあまり細かく調べずに、glideというツールを利用しました。glideをつかうと、依存するライブラリ郡を自分のプロジェクトフォルダ以下のvendorというフォルダにまとめてくれます。バージョン指定も可能ですし、一括してライブラリ郡をダウンロードするなど細々面倒を見てくれます。今回つかったdropbox-go-sdk-unofficialは名前の通りアンオフィシャルSDKで、まだ活発に大規模なリファクタリングがおこなわれていてバージョンを固定しないとまともに開発できない。いう現状もありglideによるパッケージ管理はもっとはやく導入しておけばと悔やまれました。他のツールでも同様によしなに準備してくれるのだと思います。ビルド本格的にコーディングを始める前に、ビルド環境だけは念入りに準備することにしました。ビルド環境のOSのバージョンが違うことで何か問題がでたりするとかなりの時間を浪費してしまいますし、いろんなところで新しくビルドしようとおもったときにも手間がかかります。今回はご多分に漏れずDockerを使っています。Dockerfileを用意しておいて、Dockerコンテナ上でビルドをしてそのバイナリを手元環境でテストするというワークフローを確立しました。CIでもテストが自動的に実行されるようにしておきました。テストカバレッジなども集計するという流れを自動化しておくこともできますが、これもなかなか情報が分散していて地味に手間のかかる作業でした。これから環境を用意されようと思われる方は下記の.travis.ymlをご参考にしていただければと思います。$COVERALLS_TOKENhttps://github.com/watermint/dcfg/blob/v1.3.9/.travis.ymlここで登場するcover、gover、goverallsはカバレッジを取得、集約するためのものです。見るとgoverは前職の同僚が作ったものですね。こんなところでお目にかかるとは誇らしいものです。ところでscript:のセクションはややトリッキーな書き方をしています。これもあれこれ情報を集めながら試行錯誤したものでこれでいいのか微妙なところですがひとまず動作しているのでこれで。testでは1つのソースファイルについてのみテストとカバレッジ測定となってプロジェクト全体ではとれません。testを実行してカバレッジデータのファイルを個別につくってあとで結合するという力技です。Retrospective今回はCLIツールを作りましたが、利用シーンを考えるとGUIツールもぜひ作ってみたいところです。GolangでのGUIライブラリはまだこれといった決定打がないようで、ひょっとしたらJavaでつくるか、SwiftをつかってiOSアプリにしてしまうほうがいいのかもしれません。今回CLIとは別にGinというライブラリを使ってWebサーバを立ち上げるパターンも試作してみました。framework等と比べればまだまだツールサポートなども弱いので生産性に課題を感じましたがしっかり作り込めばGUIでつくるよりも将来性がありそうです。このあたりはまた次回の研究課題です。