THINKING MEGANE

『みんなのGo言語【現場で使える実践テクニック】』をいただきました。

著者のお一人、@songmuさんより、『みんなのGo言語【現場で使える実践テクニック】』をいただきました。ありがとうございます。

現場で使える実践テクニックのタイトル通り、Go言語界隈の有名人が様々なテクニックを紹介してくれています。自分もGo言語が好きでよく書いていますが、書き始めた当時に試行錯誤しながら身につけてきた知識、テクニックが簡潔にまとまっており、文法を一通り覚えた初学者にとって学習効率が非常に高い本ではないかと思います。

第1章 Goによるチーム開発のはじめ方とコードを書く上での心得

Go言語を快適に書くための開発環境の準備から、Goらしいコードを書くまでが簡潔にまとめられています。main.goだけのプロジェクトから卒業するときに悩むところが網羅されており、A Tour Of Goのあとに、みんなのGo言語 1章を読むまでを入門としてよさそうです。

また、この章で拙作の(dragon-imports)を紹介していただきました。ありがとうございます!

第2章 マルチプラットフォームで動作する社内ツールのつくり方

2章ではマルチプラットフォーム対応をするために気をつける点が説明されています。2.5 がんばるよりもまわりのツールに頼るや、2.8 設定ファイルの取り扱いなど、単一のプラットフォームだけでも役立つテクニックが掲載されています。

第3章 実用的なアプリケーションを作るために

実際に各所のプロダクション環境で動いているツール開発の経験が盛り込まれているまさに実践的な章です。自分自身も、独自シグナルによるメンテナンス性の向上やcontextパッケージなどまだ知らなかった知識を仕入れることができて満足度が高い章でした。

第4章 コマンドラインツールを作る

マルチプラットフォーム、シングルバイナリを実現するGo言語の華形と言えばCLIツールだと思います。CLIツールをつくるにあたり、本章を始め、筆者の方が今までブログや発表の中で一貫して述べてきた、使いやすくメンテナンスしやすいツールにするためのテクニックはとても役立つと思います。

特に4.5にある終了ステータスコードや入出力をmainとパッケージで分離する手法については自分のプロダクトでも採用させてもらっており、メンテナンスやテストによる堅牢性の向上などにつながっておりオススメです。

第5章 The Dark Arts Of Reflection

Go言語のリフレクションで何ができてどのような副作用があるかが説明されています。パフォーマンスについてもまとめられており、利用に関して自分自身で判断できるようになるためにも読んでおくとよいかと思います。

それにしても動的なSelect文の構築ができるとは思っていませんでした。Go言語初心者を脱した方にとっても新鮮な発見がある章かもしれません。

第6章 Goのテストに関するツールセット

Go言語でのテストの基礎とテクニックを紹介しています。Go言語もテスティングフレームワークが一時期乱立しましたが、最終的には言語標準の機能によるシンプルなテストに落ち着いたのではないかと思っています。この章を読むことでGo言語の提供する仕組みに沿いながらも必要十分なテストを書くための知識を得ることができると思います。

まとめ

全体を読みながら、自分もここでハマったなとか、最終的にこういう風に書いているなと納得しながら読み進めることができました。こういった知見は、普通は自分自身の試行錯誤や他のひとのコードを読んで少しづつためていくものですし、知見がたまったとしてもなかなか網羅的にひとに伝えることは難しいものだと思います。この本にある、現場で培われた実践的なテクニックを本というカタチで学習し、共有できるのは自分自身のスキルアップだけでなく、チームの拠り所として立ち上げや新規参入者を迎えるにあたって心強い一冊となるのではないでしょうか。

また、紹介されるテクニックについても様々なレベルがあり、自分のレベルややりたいことの変化に応じて、新しい発見のある本ではないかと思います。140ページほどで簡潔にまとめられているので、気軽に読み始めることができます。みんなのGo言語【現場で使える実践テクニック】 オススメです。

プログラマのための数学勉強会@福岡#5 で「Goによる勾配降下法 -理論と実践-」を発表してきた

8/6に開催されたプログラマのための数学勉強会@福岡#5で「Goによる勾配降下法 -理論と実践-」を発表してきました。

今回は勾配降下法にフォーカスした内容となっています。機械学習というブラックボックスが実は誤差を最小化するものであり、そのために勾配降下法というアプローチがある、という基本でもあり、数式に抵抗があると最初につまづく箇所でもあります。

今回は数式と図解に加え、Go言語によるサンプル実装も添えることでプログラマへも理解しやすくなるように資料を作ってみました。

また、勾配降下法の手法だけではなく収束速度の改善や学習率の自動調整といった最適化の手法も紹介しているので、基本を理解している人もよければ御覧ください。

サンプル実装

発表で使ったサンプル実装はこちらで公開しています。

正弦関数を元にしたトレーニングセットに対して多項式回帰を行うことができます。

このような感じで各種勾配降下法や最適化手法、ハイパーパラメーターの調整によってどのように学習が収束していくか、遊んでみてください。

$ go run cmd/gradient_descent/main.go -eta 0.075 -m 3 -epoch 40000 -algorithm sgd -momentum 0.9

こういうグラフが出力されます。

gradient_descent

プログラマのための数学勉強会@福岡

今回は発表に向けて自分で最適化手法について調べて実装して、検証してを繰り返すことで自分自身も理解が深まってよかったです。

発表内容も多様で、個人的には@hokutsさんの、意識の有無を統合情報量として数式に落としこむ統合情報理論の紹介が面白かったです。高度に複雑化した機械学習のモデルが意識を持つのか。色々妄想が進みそうです。

福岡で数学に興味ある方、お気軽に。発表者募集中とのことです。

静的データを扱うActiveHashでページングとライク検索するgem達をつくった

静的データをActiveRecord的に扱えて便利なActiveHashですが、ページングとライク検索が必要になったのでgemをつくりました。


ページングを行えるようにする active_hash-kaminari と、

ライク検索を行えるようにする active_hash-like です。

active_hash-kaminari

ページングを行いたいActiveHashのクラスにPaginatableモジュールをprependします。

class Country < ActiveHash::Base
  prepend ActiveHash::Paginatable
  ...
end

ページングにはKaminariを使っています。モジュールをprependすることにより、検索結果が Kaminari::PaginatableArray でラップされるようになり、ページングが可能になります。

Country.all.page(1).per(10)

もちろんViewでも使えます。

<%= paginate @counties %>

active_hash-like

gemをインストールすると、ActiveHashでlikeが使えるようになります。

class Country < ActiveHash::Base; end

Country.like(name: 'Cana%')

複数条件のうち、ひとつをlikeで検索する場合はwhere内ActiveHash::Match::Like マッチャーを使います。

Country.where(name: ActiveHash::Match::Like.new('Cana%'))

Custom Matcher

ActiveHash::Match::Likeはカスタムマッチャーのひとつで、マッチャーは独自でつくることが可能です。

マッチャーはcallメソッドを持つ必要があります。

class MyCustomMatcher
  attr_accessor :pattern

  def initialize(pattern)
    self.pattern = pattern
  end

  def call(value)
    # Case ignore matcher
    value.upcase == pattern.upcase
  end
end

Country.where(name: MyCustomMatcher.new('pattern'))

callメソッドを持つProcオブジェクトも使うことができます。

Country.where(name: ->(value){value == 'some value'})

OR 条件

あいまい検索という括りでOR検索も行うことができるようになります。

Country.where(name: 'Canada', or: {field1: 'foo', field2: 'bar'})
#=> name = 'Canada' and (field1 = 'foo' or field2 = 'bar')

OR条件の対象のカラムが同じ場合(IN相当)はまだ未実装なのでカスタムマッチャーを使ってください。

Country.where(name: ->(val){val == 'Canada' || val == 'US'})

まとめ

ActiveHash、静的データを扱うのにとても便利なので、active_hash-kaminariとactive_hash-likeと組み合わせて更に便利に使ってみてはどうでしょうか。

Treasure Dataのスケジュールジョブをコードで管理するPendulumというgemをつくった

Treasure Dataに収集したデータを集計・出力するためにジョブをスケジュール登録するにあたり、ブラウザコンソールやAPIから直接行うと履歴管理やレビューができないといった課題を解決するために Pendulum というgemをつくりました。

PendulumはDSLで記述された定義に従い、Treasure Dataのスケジュールジョブを管理します。 定義ファイルをGit管理することで、履歴管理やGitHubと連携したコードレビューが可能になります。

余談ですが、Pendulumは振り子という意味で、定期的な実行という意味と宝探しのダウジング的な意味から連想しています。ペンデュラム。響きがカッコイイ。

使い方

Schedfileという名前で定義ファイルを用意して、

schedule 'my-schedule-job' do
  database 'db_name'
  query    'select count(time) from access;'
  cron     '30 0 * * *'
  result   'td://@/db_name/count'
end

pendulumコマンドを実行するだけです。

# dry-run で 適用内容を確認
$ pendulum --apikey='...' -a --dry-run
# 適用
$ pendulum --apikey='...' -a

AWSのRoute53に対するRoadworker的なものを想像してもらえるとよいかと思います。

エクスポート

既存のスケジュールジョブがある場合はエクスポートもできます。

$ pendulum --apikey='...' -e

実行ディレクトリに Schedfilequeries ディレクトリが生成されジョブの定義とクエリが出力されています。

修正後、dry-runによるapplyを行ってみると、差分が検出されていることがわかります。

$ pendulum --apikey='...' -a --dry-run
Update schedule: my-scheduled-job (dry-run)
  set cron=@hourly

Schedfile

APIで利用する名称と同じものが使えます。

schedule 'test-scheduled-job' do
  database    'db_name'
  query       'select count(time) from access;'
  retry_limit 0
  priority    :normal
  cron        '30 0 * * *'
  timezone    'Asia/Tokyo'
  delay       0
  result_url  'td://@/db_name/count'
end

priority:very_highなど、cron:dailyといった読みやすい値も使えます。

query_file

クエリはquery_fileを使って別ファイルのクエリを読み込めます。

query_file 'queries/test-scheduled-job.hql'

集計用のクエリは長くなることが多いと思うので、こちらを使っていくことになるでしょう。

result

Result Exportの先を定義する、result_url をわかりやすくするための result もあります。

schedule 'test-scheduled-job' do
  database   'db_name'
  ...
  result :td do
    database 'db_name'
    table    'table_name'
  end
end

現時点では出力先としてTreasure DataPostgreSQL、カスタムのresultをサポートしています。他の出力先をresult記法で書きたいときはPullRequestをお待ちしております。

force

Schedfileに定義されていないスケジュールジョブは通常はUndefined scheduleとなり削除対象とはなりません。削除が必要な場合は--forceオプションを使ってください。

また、Treasure DataのAPI都合上、result_url内のパスワードは***とマスキングされており差分が比較できません。もしパスワードを変更した場合も同様に--forceオプションを使って適用してください。

config

environments/default.ymlなどを用意することで、DSL内でsettings経由で取得することができます。

...
  result :postgresql do
    ...
    password settings.password
  end

また、-E オプションによる環境ごとの設定ファイルにも対応しています。

まとめ

コード管理により履歴管理やレビューといったフローに乗せることができるので大変便利になりました。そのあたりの運用で困っているかたは使ってみてはどうでしょうか。

mrubyからSidekiqに非同期ジョブを登録するmrbgemをつくった

ngx_mrubyでHTTPリクエストに対して非同期処理をしたかったので、mruby-sidekiq-clientという mrbgem をつくりました。

mrubyからSidekiqのジョブ形式でRedisに非同期ジョブを登録し、別途用意したSidekiqのサーバーが登録されたジョブを捌いていくという方式です。これにより、非同期処理は通常のRailsやCRubyのコードで書くことができ、mruby側の処理はシンプルに保つことができます。

使い方

RailsなどでSidekiqを使っている方にはお馴染みのやり方です。

1. 非同期ジョブにしたいWorkerクラスを定義します

class HardWorker
  include Sidekiq::Worker
end

performメソッドはmruby側では実装する必要はありません。Sidekiqサーバー側のRubyコードに実装してください。

2. 非同期ジョブを登録する処理を定義します。

HardWorker.perform_async('bob', 5)

指定時間後に実行するジョブも登録できます

HardWorker.perform_in(300, 'bob', 5) # 300秒後に実行

mruby側はこれだけです。あとは先ほどのWorkerクラスと同じクラスをSidekiqサーバー側に追加し、performメソッドに非同期ジョブの内容を記述します。

ngx_mrubyで使う

mruby_userdataを使って、リクエストごとにRedis再接続しないようにしておきます。

http {

    (snip)

    mruby_init_code '
        userdata = Userdata.new "redis_data_key"
        userdata.redis = Redis.new "localhost", 6379
    ';

    server {

        (snip)

        location /hello {
             mruby_content_handler_code '
                 userdata = Userdata.new "redis_data_key"
                 Sidekiq.redis = userdata.redis

                 class MyWorker; include Sidekiq::Worker; end

                 (snip)

                 MyWorker.perform_async(args)
             ';
        }

Sidekiqサーバー

SidekiqサーバーはPlain Rubyの環境でも動作するため、ngx_mrubyとRedis、Rubyだけでシンプルなジョブキューをつくることができます。 手順はこちらを参考にしてください。

インストール

build_config.rb に以下を記述してください。

conf.gem :github => 'monochromegane/mruby-secure-random'
conf.gem :github => 'monochromegane/mruby-sidekiq-client'

mruby-secure-randomSecureRandomをmrubyで使えるようにするためにつくったmrbgemです。SidekiqのJIDを算出するために利用しています。ランダムデバイスとして /dev/urandom しか対応していないため Windows環境だと動きません。PullRequestお待ちしております。

まとめ

こんな感じでmrubyからSidekiqと連携できるようにしてみました。シンプルなジョブキューであればRails使わずにngx_mrubyとRedis、Rubyだけでつくれてしまうので便利では〜と個人的には思っています。

あわせて、今後、mruby使った動的なフロントサーバーがサービスのどの要件までを担当すべきかといった構成は常に考えていかなければいけないだろうなあとも感じています。適材適所それぞれの利点を最大限に活かせる構成を検討したいところ。

2016

去年も相変わらずGoを書いたり、ブログ書いたり、発表したり勉強会開催したり、自分のペースで自分の楽しいことをやってきたし、ふりかえってみれば、自分なりにそれらしい量もやれたかなとも思うけど、どうしても一昨年からの漫然と続く楽な活動であったと言われれば否定はできない感じがあった。活動の前提が個人の枠を超えていない。Go書いたりブログ書いたりも個人の小さな承認欲求を満たしたいだけなのでどうにもつまらんなあという感じ。

個人活動は非常に楽である。自分の好きなときにつくって公開して、たまに褒められてニヤリとして、また次をつくる。当たらなくても趣味なのでという言い訳が自分に立つ。なんと楽なことか。アウトプット最高!

そう、アウトプット最高なのだ。個人のアウトプットをキッカケに色々なところで知ってもらえて、つながりができていく。アウトプットでスキルが洗練される。ペパボに入る前はこういうことが喜ばれる環境や仲間に憧れて今、これができるようになっていることはとても楽しい。でもここはスタート地点だった。

昨年は仕事の中で、エンジニアとして技術で小手先ではなく戦略レベルの解決策を提示したり、人やチームに良い影響を与える人達を身近に見てきてきた。アウトプットの質が高く、かつそれらが業界や業務にフィードバックされていく。これがまさに専門職。趣味のアウトプットから次に進もう。

僕は自分に自信がないと話すのを躊躇してしまうので、そこの性格を直すというよりは自信が持てるように知識をつけていきたいと思っている。人間は変われないけど、知識がそれを補うことができると信じたい。なので今年の前半はたくさん本を読もうと思う。古典から新しいものまで。大量に読み流すのではなくて自分なりに体系立てていけるようにしたい。とにもかくにも考えをまとめれるようになりたい。

それらが後半以降に組み合わさって、自分なりの専門職としての武器になってくれればよいかなと思う。現時点で具体的な案が出せてないのはつらいところだけど、そもそもそれがあるなら、今ここで長々とこんな文章を書いてはいない。

問題を見つける、それを解決する技術を修める、それを適用していくためにまわりを巻き込む。

全部難しいことだし、今もできていないことばかり。2016年は個人活動から一歩先に進むため、一生懸命もがいていきたい。

2015年のふりかえり

仕事

今年は7月頃に2年ほど携わっていたチームから異動して新しい環境になったのが一番大きな変化だった。異動前にPHPバージョンアップを成すことができたし、新しいチームでは新機能開発しながらも技術的な課題がサービスの発展を妨げることのないよう、継続的な改善ができる体制を取ることができた。今のチームは最高で、お互いに敬意を払いながらも得意領域で活躍し、不足しているところを補い合えているんじゃないかと思う。ただ、チームとしての成熟は変化に反応するための柔軟性を失う可能性も含んでいるので、新しい目標、例えば新しい技術への挑戦とか持っている技術の深掘りとかお互いを刺激し合える環境というのをつくっていきたいなあと思う。

技術

2014年から引き続きGo言語一色の年になった。Top Go GitHub developers in Japanで3位に位置付けられてるのは素直に喜びたい。当たるか当たらないかに関係なく自分が必要と思ったらOSS前提でつくるようになれたし、発表も特に臆することなくできるようになったと思う。

今は、OSSや発表も個人ベースだったりGo言語界隈という感じで範囲や関係する人が限定的なので、来年はそのあたりをもっと広げて新しい世界を見たいと思っている。

OSS

Go楽しい〜の一年だった。argenとかの大きめのプロダクトもつくれたし、The Platinum Searcherの高速化も達成できたのはよかった。

発表

200-300人規模の発表に参加していくことができたので少しづつ東京での勉強会でも顔見知りが増えてきたり声を掛けてもらえるようになったのはうれしい。地元でのFukuoka.goがあんまり開催できてないので、やり方検討しなおして来年はなんとか再開していきたい。

Fukuoka.go#7 ソースコードリーディングvol.1を開催しました

Go Conference 2015 summer で発表してきた

第2回ペパボテックカンファレンスで発表してきた #pbtech

「minne」技術戦略カンファレンスで発表してきた

まとめ

ペパボに入って3年経って、とにかくコードを書きたいという気持ちはOSSやアウトプットで消化の仕方が分かってきた。来年は楽しみとしている技術を専門職として業務にフィードバックできるようにひとつ成長したいところ。なんにせよ一年おつかれさまでした。

Archives