ゆーすけべー日記

はてなBlogってどーなの!?

SlideckっていうWebサービスをつくった

tl;dr

Slideckっていうエンジニア向けっぽいWebサービスをつくりました。できたてホヤホヤです。

slideck.io

GitHubのレポジトリに、とある簡単なフォーマットに従ったMarkdownのテキストファイルを置いとくと、 Slideckの機能を使ってオンラインでクールなスライドショーが表示出来ます。 ルールに従ったURLでアクセス出来るのでブラウザで開くことはもちろん、シェアすることも可能です。 皆さん使って下さいね。

追記

要望を早速もらったのでGistにも対応しました!

↓のGistファイルを...

/gist.github.com/{owner}/{id}/{filename} というパスでアクセスすれば...

スライドになりま〜す!これで気軽に試せるね!

モチベーション

reveal.jsのMarkdown編集機能を使ったスライド作成が、場合によりKeynoteやパワポより効率的で、 見栄えもカッコよくて好きです。好きがこうじてreveal.jsのラッパーツールであるApp::revealupやrevealgoと言ったプロダクトを自分でつくってきました。

これらは基本的に自分のPC上にプレビュー用のサーバーを立てる「ローカルホスト」のためのツール群です。 reveal.jsとMarkdownテキストを使ったスライドの表示がより手っ取り早くなるので自分でも重宝しています。

ところが、いざつくったMarkdownテキストをオンラインでシェアする場合に、わざわざサーバーを用意してHTMLでラップさせるという作業が面倒です。 後述するルールに則ったMarkdownテキストであれば自動的にreveal.jsを使ったスライドへコンバートして表示してくれるものを求めていたのです。

Slideck

そこで思いついたのがSlideckです。 godoc.orgに若干インスパイアされる形で考えました。 みんな大好きGitHubのレポジトリ上にスライドのMarkdownファイルを置いて、 そのパスを指定するとサーバーアプリがフェッチしてくれてスライドショーを描画する仕掛けです。 以下の様な特徴があります。

  • revealjs / revealgo との互換性
  • GitHubに置いた画像の埋め込みなどにも対応
  • privateレポのスライドを見たければGitHubログインすればOK、当人しか見れない
  • revealgoとは違いMarkdownを一度HTMLへ変換しXSS的にも安全

f:id:kamawada:20160318142707p:plain

ちなみにGolangで実装、ホスティングはHerokuで行いました。 思いついてモックアップが出来るのに一晩、デプロイまで含めると2日間というスピード開発です。

使い方

例えば、サンプルで用意しているドキュメントがあるので、それを元に紹介しましょう。

僕は先ほど、GitHubのpublicレポジトリgithub.com/yusukebe/slidesをつくってここにスライドのMarkdownファイルと画像などを置いてくことにしました。

この場合、ownerが「yusukebe」repoが「slides」となります。そして「sample.md」というpathに以下を書いたMarkdownがあります。 ---がスライドのページ区切り文字ですね。

# Title

Hi, my name is yusukebe.

---

## Lists

* List1
* List2
* List3

---

## Hello World


    package main

    import "fmt"

    func main() {
        fmt.Println("Hello World")
    }

---

## Image

![Slideck](images/slideck_ss.png)

---

Check out Slideck now!

<https://slideck.io/>

レポジトリ上のMarkdownをスライドとして描画するには、こちらのルールに従ったURLでSlideckにアクセスします。

https://slideck.io/github.com/{owner}/{repo}/{path}

今回の場合は下記URLです!

するとどうでしょう!GitHub上のリソースを勝手に取ってきてくれてreveal.jsを適応したスライドになるじゃありませんか!

f:id:kamawada:20160318145603p:plain

Slideckのトップページでは、フォームにリソースの場所を記載すれば勝手に飛んでくれるような機能があるので活用出来ますね。

まとめ

ということで、Markdownベースのスライド作成は捗るし、シェアしやすい仕組みをGitHubを利用しつつつくってみたので、使ってみてください!

slideck.io

今日これから行われるYokohama.(pm6?|go)ではデモを交えてSlideckの話をします〜

宣伝

Podcastやってます!ゆるい感じらしいです。聴いて下さい!

www.wada.fm

僕がプレゼンのスライドをつくる時に考えること

僕がひとり語りしているPodcast「wada.fm」の前回のエピソードでも話したんだけども、プレゼンテーションのスライドをどうつくるか?みたいな話。

f:id:kamawada:20160310110331p:plain

ちょいと最近とある方に

ゆっけさん(彼は僕のことをこう呼ぶ)のプレゼン資料いいよね〜

と褒められ、結果彼の会社のプレゼン資料的なのをつくるアドバイスをすることになった。まぁ確かに大抵プレゼンでつかうスライドは時間が許す限り、分かりやすく楽しいものにしようと心がけているのでそう言ってもらえて嬉しかったので調子に乗りつつ「自分がどうやってプレゼンの資料をつくっているか?」をまとめつつあります。本エントリーではその一環も兼ねて記事にします。

プレゼンの前提

スライドをつくる際にどのようなプレゼンの場で発表するための資料なのか?を把握しておくことは僕にとって重要です。まずどのツールを使って、どんなスライドを何枚用意しなくてはいけないかが決まってくるからで、それが定まらないと書き始めるモチベーションが生まれない。例えば、

  • それが勉強会なのか?カンファレンスと呼ばれる規模のものなのか?それともセミナーなのか?
  • 参加者もしくは聴講者の人数は?
  • その人達の属性はどんなもの?
  • 発表時間は何分か?
  • 場所はどんなところか?
  • テーマに縛りがあるかどうか?

あたりを発表する会合の主催者などに問い合わせて、プレゼンのための前提条件を確定する作業をよくしています。

f:id:kamawada:20150903213610j:plain

上記の事柄がハッキリすると経験上、自分が壇上で喋っている姿が想像出来るので後ほど紹介するストーリーテリングしていくことが出来ることになります。

スライド作成ツール

こうした発表する場の前提条件をクリアにした後は、何を使ってスライドをつくるか?といったツールを確定させます。といっても僕が使っているスライドツールは2つのみ

  • Keynote
  • reveal.js + Markdown

reveal.jsという名前が聞き慣れない方もいるかと思いますが、HTMLベースのプレゼンテーションツールで、ブラウザでスライドを表示させるとJavaScriptを使ったエフェクトでクールな描画をしてくれます。reveal.js自体のオフィシャルな紹介サイトもこのスライドで構成されているのでどんな見た目になるか?を確認出来ます。

lab.hakim.se

reveal.jsはMarkdownフォーマットでスライドの中身を記述出来るのがよくて、Keynoteと比べるとテキストベースのページを素早く作成したり、プログラミングコードを掲載するのに向いています。ただ、画像を載せたい時に微調整が難しいという課題があったりします。一方Keynoteで作成した場合、画像の細かい位置調整などは楽だし、PDFに「キレイに」書き出しが出来る=SlideShareやSpeaker Deckなどのスライド共有サイトでのシェアが容易ということもあって「後ほど見てもらう」ためにはコチラ、Keynoteの方が向いていたりします。

このようにツールによって振り不向きがあるので、プレゼンの前提条件に合わせ、

  • サクッとスライドをつくりたい場合やコードがたくさん出てくる時はreveal.js
  • 気合入れて、かつ後からリファレンスしてもらいたいような時はKeynote

というように使わけています。

構成する手順

さてツールが決まったらいよいよスライドを書き始めたいわけですが、その前にどんな構成にするかを考えて一旦寝かせます。その間には具体的にこんなことを考えます。

  • 話したいこと、分かってもらいたいことは何か?
  • プレゼンのオチをどこに持っていくか?
  • どういう順番で話していくか?
  • 書くスライドページのタイトルは何か?

大抵の場合、プレゼンの発表時間は「思っているよりも」短い場合が多いという感覚があります。なので、言いたいことを一つだけ決めてそれをオチとしてどうまとめるか?に注力して流れを妄想するしておくと書き出しがスムーズになったりしますね。

ジョブス流とパワポ式の中間を狙う

Appleの製品発表会のプレゼンテーションは素晴らしいのですが、アレ真似するの相当大変です。TEDでのプレゼンにも通ずるところがありますが、いわゆる「ジョブス流」のプレゼンは、スライドにはイメージや一言コピーだけ、あとは身振り手振りで聴衆を惹きつけるという手法です。カッコいいしウマくいけばウケはいいんだけれども... 綿密な練習が必要になって来ますし、スピーチの内容を予めつくらないと難しそうです。しかも後ほどそこで使ったスライドを見てもイメージが多いので「なんのこっちゃ」になりそうです。

一方で日本古来の習わし的なパワポを使った箇条書きの資料があります。昨今では「よろしくない」とされているのですが、一方では後ほど資料だけ見て「振り返るため」のものとしては機能しそうです。が、やはり、文字が多くてそれを読み上げるだけのプレゼンは退屈でしょう。

そこで個人的には「ジョブス流とパワポ式の中間あたり」を狙ったスライドをつくろうとしています。いいとこ取りしようって魂胆です。

  • ジョブス流からは大きな画像を見せたり、キャッチコピーでインパクトを与える点
  • パワポ式からはその場にいなくともスライドを見るだけで内容がなんとなく分かる点

このようなハイブリット型を取ることによって、印象に残るプレゼンを練習をそれほどせずにも出来て、後からスライドを共有するだけで拡散して「こんな発表したんだ」と見てもらえるということを目指しています。ちなみに、その例として直近で僕がいちお、それを心がけてつくったスライドを掲載しておきます。多少、高橋メソッドも入ってますね。

www.slideshare.net

ストーリーテリングとコピー

発表をする経験を踏んでこそだんだんスライドづくりがうまくなって来たり、コツがつかめる部分が多分にありそうです。その際に

  • 分かってもらえるお話をつくる力=ストーリーテリング
  • インパクトのある言葉を生み出す力=コピーライティング

この2つの能力って大事になってくると思っているので、今後も意識して伸ばしていきたいと思います。

まとめ

以上、プレゼンのスライドというテーマで、前提条件をまずピックアップすること、ツールの件、構成を考えるための諸要素、「ジョブスvsゲイツ」的な何かのいいとこどりをしようとしている、などを紹介しました。具体的にページをどういう風につくるかという実装寄りの話とかもまだあるのですが、今日はこのあたりで!

宣伝

Podcastやってます!ジングルがクールです。聴いて下さい!

www.wada.fm

何をどう実装するか?コードを書かない話

最近思っていることをツラツラと。

サービスにとって「コードを書く」という行為以上に「何をどう実装するか?」を決定するスピードと精度が非常に大切だと改めて感じている。一般的な言葉で言うならば「要件定義」や「設計」に当たるところ。ある程度サービスが成熟してくると、その理念としてもビジネス的にも「ある程度」正しい要件を決め、矛盾や運用に負荷の無い設計を企てることが一番重要なんじゃないかと。もちろん「やれることを増やす」という意味では技術的な調査や実装として手を動かす作業は日々続けるとして、僕らの現状を話します。

チームスペック

まず前提としてのチームの規模。僕らのサービスはアプリにして500万弱のダウンロード数を誇るものの、比較的ミニマムな人員で開発されている。以下はザックリとした役割と人数です。

  • APIサーバを含むWeb側の開発 => 2人(僕含む)
  • iOS/Androidネイティブアプリ開発 => 2人
  • デザイナー => 1人
  • ディレクターやマーケティング担当 => 2人〜3人

ちなみにこれらの人達は決してオフィスに定時で集まるというスタイルをとってはいなく、リモートかつベストエフォートでリソースを割くという方式で動いています。 なので打合せや集まっての作業はノマド的な喫茶店で行なうのが主流です。

f:id:kamawada:20160223162659j:plain

コードは書いた瞬間に負債になりうる

我々にとって「闇」として話題に上がるネタに技術的負債という言葉があります。以前から参加させてもらっている「IVS CTO Night&Day」のアンカンファレンスでもそのテーマがあって色々考えたんだけども、辿り着いた結論は

コードは書いた瞬間に負債になる

かもしれない。ということだった。コロコロと移りやすいWebやアプリへのニーズや技術の進歩によって、書いてしまったものが負債になる日は近いな、という印象。これは残酷だけどわりと言えてるかもしれない。確かに、プロダクションに投入した例のXXXのコードはカオス化していて毎回ソースコードを読まないとAPIが理解出来ない... なんて過去の経験もある。だからコードは短い方がいいし、つくらなくて済むならばつくらない方がいいかもしれない。ヒエーボクハコードカキタイヨ... でもスパゲッティになったコードを読むのは辛い。なんというかこの矛盾的思惑が面白いところだとは思う。もちろんそれを設計実装するエンジニアの腕もあるだろうが...

まぁ、といってもサービスとしてプロダクトを良くしていくためにはコードを書くのは必要だろうし、そのために「過ちのない」機能や改善点を定義することが大事なんだろうね。

それぞれの思惑とディレクター

僕らはここ数年、年始に今年何をやるか?と言った中期的な目標やマイルストーンを決める。今年も決まった。だが、粒度が荒いと「じゃ今すぐこれつくります」とも言えない。

優先順位を決めた細かい実装計画が必要なんだけども、それを決めるにあたって、ステークホルダーそれぞれの思惑がバラバラだったりする。とあるAさんは機能1を叶えたいと言い、Bさんは機能2を推す。実装する側としては色々試しましょう!と言いたいところだけれども、上記の「負債」の件も含めて、機能を追加することに関してはちょいと慎重になってしまう。結果「どこから実装すればいいの!?」という迷いが生じる。

そこを解決するのがディレクターという「役割」である。あくまで「役割」なので「ディレクターひとり」がいるという状態じゃなくても構わないと思う。ディレクターはプロダクトを愛し、責任を持ち、そのプロダクトの「小さな方向性」についてジャッジをしてくれると嬉しい。

たった今の話なんだけど、各自のやりたいことが微妙にバラついてるという上記した状況なので、今度メンバーのうちの数名で細かい実装の優先順位を決める打合せをする。誰かがディレクションするのかみんなでまとめていくのか?気になるところであるが楽しみである。

要件と設計をテキストでまとめる

これをやるぞ!と決まれば、後は正確に要件を洗い出し、設計のたたき台をつくってみんなで叩けばあとは大抵上手くいく。

その際に、最近ではある程度構造化されたテキストで「要件定義と設計の中間」くらいのものを文章や箇条書きでまとめるといいんじゃないかって思っている。 僕らはそのためにesa.ioを使い出した。この場合Markdownや図のファイルでやることを整理するページを僕がつくり、みんなに投げる。オンラインや喫茶店での打合せでアラがないかツッコんでもらうという形だ。

例えば、今回話題にあがっているサービスでは新規登録フローをとある事情で変更したのだけれども、以下のようなページを作成し、みんなで共有&議論した。一部のスクショを掲載する。

f:id:kamawada:20160307102459p:plain

ここでは以下の様なことを「特に書式やフォーマットを気にせず」書いている。

  • ユーザーフロー
  • フローに基づき裏側で何が起こるか?
  • 前提条件、事後条件
  • データ構造の変更点
  • WebAPIのエンドポイント
  • Webのパス設計
  • デプロイ計画

これがなかなかいい具合である。

いかに迷いなくコードを書くか?

僕は今まで設計にまつわることを一人でやっていた... と思うんだけれども、このように一度esaなどを使ってテキストに落としこんでみんなに見てもらうと、コードを書く前の迷いが消える気がする。このドキュメントにツッコんでくれるのは開発陣数人とアプリのディレクターのせいぜい3人程度なんだけども、それだけでも、ありがたい。抜けや欠けがどうしても出ることを防げれるので「何をつくるか?」に対する精度が増す。また、WebAPIとモバイルアプリの様に連携しあうサービスなので、API側の機能変更を予めモバイル側のエンジニアが把握しやすいという利点もある。

効率よくコードを書く際には上位工程である設計の迷いを持ってきてはよくないのだろうな。良いコードを書けたとしても「このままの仕様でつくっていいのかな〜」なんて思いながら、はなんかヤダなぁと思う。

Microservicesへの考慮

粒度によっては日々発生するビジネスレイヤーの要望に対してMicroservicesを適応することで技術的負債を削減することが出来るかもしれないという淡い淡い期待はある。なるべくアーキテクチャ設計の時点で構造化していおくことで、サービスの様々な機能を追加を試せる土壌をつくっておくことに努力したい。そういう意味で「マイクロサービスアーキテクチャ」はいい本だったのでまとまったら、どこかで書くかPodcastで話そうと思う。

マイクロサービスアーキテクチャ

マイクロサービスアーキテクチャ

  • 作者: Sam Newman,佐藤直生,木下哲也
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2016/02/26
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る

まとめ

「サービスにとって」という前提ではあるが、なるべく無駄なコードは書きたくない。だからこそ「何をつくるか?」のジャッジをディレクターという役割を利用して精度高く決めていきたい。また、要件や設計仕様をesa.ioなどの構造化テキストでまとめていくのは、迷いなくプロダクトコードを書いていくために役に立つかもよ、というお話でした。コードを書かない時間も大事だし、コードを書くことを止めないでいきたい。

宣伝

Podcastやってます!ジングルが面白いです。聴いて下さい!

www.wada.fm

栄和堂を開店して2ヶ月が経った件

弟が店長、親父がカフェマスターを務めるカフェ&バーである「ブックスペース栄和堂」が開店して2ヶ月が経った。運営するのは僕が代表、そして彼ら2人も所属する株式会社ワディットである。

f:id:kamawada:20151127114031j:plain

僕は現状の仕事がある、そして「物理的に遠い」という理由から、顧問やアドバイザーというような立場でこの栄和堂のプロジェクトに参加している。今日は「定休日」なのでその時間を利用して新メニューの試食会やら弟の「淳也」による2ヶ月のデータ分析結果などを共有した。

f:id:kamawada:20160120143503j:plain

栄和堂は去年2015年の11月16日に、ワディット及び僕らの実家の近くにある鎌倉湘南深沢」にオープンした。そもそもITやWebを専門分野とするワディットがカフェもしくはバーを開店するには「入り組んだ」理由=ワケがある。そのワケがあるからこそ僕らの思い入れは強く、続けていきたい根源となっている。

実は栄和堂は元々「本屋」だった。店主は親父の弟さん、つまり僕の叔父である。いわゆる「街の本屋」で僕も幼少期の頃、栄和堂に行って、文具をあさったり、本棚の匂いを嗅いだり、叔父さんからタミヤの模型をもらったりして喜んだのを、すごく懐かしく覚えている。

f:id:kamawada:20160120181949j:plain

そんな栄和堂を営む叔父が一昨年の3月、急死した。あまりにも突然だったので正直びっくりした。人が世界からいなくなるという体験は不思議だ。

さて悲しい話は置いといて、問題は栄和堂だ。彼が20代の頃から40年以上営業しつづけた書店「栄和堂」をどうするか?結論を簡単に言えば、一旦閉店させた。親戚の中でも比較的動けた親父が踏ん張り、閉店セールをやったり業者を呼んだりして、在庫を一掃した。土地は亡くなった叔父の奥さんである叔母さんのものになったが、買い手がつかない。

そこで「どうせなら」ワディットが借りて何かやろうじゃないか?という話になったのだ。

f:id:kamawada:20150703190552j:plain

当初父親と二人だったワディット社員の僕らは色々考えたが「自らのアイデアに責任が持てない」という状況。そこへ、脱サラした淳也がワディットに参画。淳也は幼少時から持ち合わせている器用さを発揮し(そう、俺は永遠にマリオカートで淳也に勝てない)彼が店長になって栄和堂の場所を有効活用しようと動き出す。3人で話しながら、我々の目指すところは

本屋の再発明

であると定義した。ではどのように再発明するか?を今現在試しているところで、今日の会議で淳也はそれを

本棚を介して人がつながれる場所を提供すること

だと言う。ただ、このような目標を立てつつ、カフェやバーで収益を上げるというモデルは現時点で成功しているとは判断しにくい。正直、工事日数と、なによりもお金がかかっている。

f:id:kamawada:20151028172052j:plain

開店の直後、淳也と親父は当初の売上目標との乖離にウズウズしている感はあった。実際、経営的視点で見ると、結構厳しい。とはいえ、客として訪問してみるとヒイキはあるかもしれないが満足度は高い。そんな中、淳也は詳細にデータを取っていることが今日の打合せで分かった。顧客データを独自の方法で細かく取っている。さらにはとある日にちを決めて、栄和堂の前をどれだけの人が通りかかったか?をカウントして期待しうるトラフィックを測っている。

実営業日で数えるとたった「40日」分のデータなので正確性にまだかけるが続けると指標が立ちやすいだろう。例えば、同じくらい行き来がある、場所の近いカフェで「うまくやってる」ところを見つければ参考になる。

f:id:kamawada:20150703192022j:plain

また、彼は、打ち出した「ブックスペース」というネーミングと実際のニーズとの距離感にも違和感を感じている。これは僕自身も事前に気づきにくかったが、Webなどネットの媒体では尖ったコンセプトが通じるが、リアル店舗の場合、より具体的に安直な表現を使った方が、お客さん=ユーザーに「ここで何が出来るのか?」が分かりやすくなって良い。妥協案かもしれないが、それに気づいた瞬間に、ウィンドウディスプレイに「カフェ&バー」の表記をつけたようだ。

やりたいこと、やらなくてはいけないことがたくさんある

と淳也は言っている。決して焦る必要は無いが、やることがたくさんあることはいいことだと思うので、親父共々頑張ってもらいたい。

f:id:kamawada:20150628115924j:plain

強引にまとめると...

栄和堂というカフェ&バーを僕の弟と親父が「鎌倉の外れで」やっているのでよかったら来てね♪

ということでした。よろしく!

eiwado.space

Golangを初めて本番投入したぜ!

先日「ボケて」サービス群の中でも「スタンプ」という機能を提供するアプリサーバがGo実装になりました。これが僕にとってほぼ初めての「Golang実戦投入」となります。Goの良さについては去年の10月に僕がやっているPodcast「wada.fm」でも言及していました。ただ、単純に良いからと言って、本番への導入となると既にユーザーを抱えているので、敷居が高いと感じます。そこで、工夫しつつ、じっくりと試して、現在に至りました。後述するようにハマりどころはありましたが、そのGoサーバは安定稼働していて、ユーザーへコンテンツを配信しています。そこで今回は新規にGoを導入する際の一つの事例として、今回、僕がやったボケてのスタンプサーバリプレースの経緯を紹介します。

LL言語への「若干の」不満

まず...

そもそもなんでGolangが必要なの?

ってところ。ボケてのアプリケーションはほぼ全てが以前からPerlで書かれていて、キレイに本番で不具合も無く動いてくれていました。Plack/PSGIが登場してもはや久しく、アプリケーションサーバが安定し、またApp::cpanminus/Cartonといったモジュールインストーラやライブラリ管理も賢くやってくれます。ただ、これはLL全般に言えることなんですが、型が無いんですよね。

型がないってことは、サクッと書くときにはいいけど、堅牢にやりたい時に手間がかかります。 例えばPerlにはData::Validatorというライブラリがあるので、それを使ってメソッドへの引数のタイプチェックなどを追加で実装していました。例えばボケて内のlib/Bokete/Model/Boke.pmには以下のようなコードが記載されています。

sub create {
    state $rule = Data::Validator->new(
        text => 'Str',
        odai_id => 'Str',
        user_id => 'Str',
        category => { isa => 'Maybe[Str]', default => undef },
        tags => { isa => 'ArrayRef', default => sub { [] } }
    )->with('Method');
    my ($self, $args) = $rule->validate(@_);

実装レベルでコードの中に出てくる「データ」もしくは「機能」それぞれに対して厳密にチェックしておきたい場合に、LLだと外部のライブラリを使う手間が生じたり、それが完璧に行われないケースがあるのです。逆に言えばそれがLLのいいところですが、使いドコロによってはより「strictに」やりたいアプリケーションもあるかと思うのです。

また、Perlは素晴らしく書きやすい言語だと思ってはいますが、他の違う言語も習得しておくと後々武器になって、楽しいんじゃないかなーって感じ、Goに手を出したという経緯になります。

Goの魅力

Golangを触ってみて良いなーって感じたことは前述した通り、wada.fmで話しております。興味のある方は聴いて下さい!

www.wada.fm

ただ簡単に列挙するならば...

  • 静的型付け言語だけどスクリプトっぽくかけてとっつきやすい
  • 構造体にメソッド生やして「クラスのようなもの」を実現するとか「素朴」で良い
  • コードを簡潔にするという方針などが現れた「ツンデレ」なコンパイラ
  • goroutine便利だし使いドコロが結構ある
  • Webサーバで負荷テストした時にCPUリソースをキッチリ使いきってくれて消費メモリも既存アプリと比べて少ない
  • 言語仕様的にもミニマムで「組み合わせでなんとかする」って点がPerlっぽい
  • 優良なライブラリもどんどん出てる

などなど、でしょうかね。とにかく触ってみて、スッとコードを書き始めることが出来たのがよかったです。

Goをスクリプト的に利用する

実は今回紹介するスタンプサーバ以前にボケてではGoを使っていました。ただプロダクトとしていつも動くサーバやバッチ、という形では無く、書捨ての「スクリプトっぽい」コードを利用してたのです。

例えばRDBMSのとあるテーブルの構造を変えて、データ移行したい場合においてです。なんでGolangをそこで使うのか?というとgoroutineがあるからです。Goだとgoというキーワードだけで並行処理が走り、かつデータベース接続もロックせずよしなにやってくれるので、MySQLサーバの負荷の様子を見ながら並行数を調整することで「ある程度の負荷をかけながら」素早くデータ移行が出来て便利でした。以下のようにsync.WaitGroupでそのgoroutineで平行に走らせる処理数を調整しています。

for ;; {
  var results []Entry
  err = db.Select(&results, db.Where("column1".IsNull()), db.Limit(limit));
  if err != nil {
    panic(err)
  }
  if len(results) == 0 {
    break
  }
  var wg sync.WaitGroup
  for _, e := range(results) {
    wg.Add(1)
    go func(entry Entry) {
      work(entry)
      wg.Done()
    }(e)
  }
  wg.Wait()
}

このように最初はスクリプト的にGoを使ってみて感触を掴んでみました。

どこからGolang化していくか?

さて、Goのパフォーマンス性能を活かせて、かつ、現行で走っているサービスに影響がなければ、Golang化したいところ。ただ、移行のコストとかも考えると全てをGoにするのは大変だし、Perlの方が得意なところもあるのでその辺は見極めなくてはいけません。ボケてではMicroservicesという言葉が流行る以前から、ある程度サービスをHTTPレイヤーで切ったコンポーネント化を進めておりました。そこで、大きな部分を一気に変更する、のではなく、小さな一部分だけを違う実装に変えるということが容易です。そこで、目をつけたのがスタンプサーバです。

ボケてではボケのコンテンツを画像として保存したりLINEで送る機能があります。「スタンプ」と呼んでいるのはまさに「LINEスタンプ」からインスプレーションを受けています。ようはボケの対象となるお題画像とその他ボケのテキストなどをコアロジックのWeb APIサーバから引っ張り、画像生成して、配信する機能が実装されています。試しに新しいGolang実装のサーバから配信されているスタンプ画像を直で貼り付けてみるとこのような画像です。

http://stamp.bokete.jp/1916834.png

このサービスはボケてのアプリの中でも「フロントエンドの1機能」としてPerlでつくられていましたが、ホストも違うし動かすサーバも違う。また、データはWeb APIから取得してくればOK!と、切り離しやすい箇所だったので、

まさにここからGolang化を試してみよう

となりました。

スニペットを集める

と言っても、いきなり画像処理や文字列の改行計算を含んだ「ひとつの」アプリケーションを書き始めるのはニュービーにとって漠然としすぎてて、ムリゲです。なので、スタンプサーバの実装要件をピックアップし、それごとに小さなGoコードの塊=コードスニペットをたくさん書いていきました。スニペットが集まっているレポジトリから選んでみると...

  • ローカルの画像をリサイズして書き出す
  • HTTP上の画像を取得して書き出す
  • ローカルの画像をWebで配信する
  • テキストを描画して画像として書き出す
  • 改行を含んだテキストを処理する
  • 日本語を含んだ文字列改行の禁則処理をする

などです。おそらく一番に書いたコードはこんなものでした。リサイズ処理にgithub.com/disintegration/imagingを使っています。

package main

import (
    "image"
    "github.com/disintegration/imaging"
    "fmt"
    "os"
)

func main() {
    args := os.Args
    if len(args) < 2 {
        panic("The argument is required.")
    }
    filename := args[len(args)-1]
    fmt.Println("Input filename is:", filename)
    orgImg, err := imaging.Open(filename)
    if err != nil {
        panic(err)
    }
    dstImg := resize(orgImg, 600, 0)
    err = imaging.Save(dstImg, "output.jpg")
    if err != nil {
        panic(err)
    }
    fmt.Println("Resize as output.jpg.")
}

func resize(img image.Image, width int, height int) image.Image {
    dstImg := imaging.Resize(img, width, height, imaging.Lanczos)
    return dstImg.SubImage(dstImg.Rect)
}

このようにスニペットを充実させていく作業をすると

お、これは本番用のアプリも実装出来そうだぞ!

と自信がついてきます。

画像生成サーバの実装と運用

そこでいよいよスタンプサーバの実装です。既に処理部分のスニペットがあるので、いかに個別のファイルにまとめてテストを書いて構造化するか?を考えればすんなりといけました。こんなファイル群でstamp_serverコマンドをつくっています。

$ pwd
/Users/yusuke/go/src/github.com/bokete/webstamp
$ tree ./
./
├── README.md
├── assets
│   ├── font-heavy.ttf
│   ├── font-medium.ttf
│   ├── stamp_404.png
│   ├── stamp_footer.png
│   ├── stamp_header.png
│   ├── stamp_panel.png
│   └── transparent.png
├── assets.go
├── client.go
├── client_test.go
├── cmd
│   └── stamp_server
│       └── main.go
├── stamp.go
├── stamp_test.go
├── util.go
└── util_test.go

デプロイはあまりベストプラクティスが共有されてない?っぽいので、少々悩みましたが、今まで通りAnsibleで以下の工程を自動化しています。

  • 要らないと思うけど「とりま」nginxをフロントに置く
  • スーパーデーモンにはdaemontoolsを使用
  • lestrratさん作のgo-server-starterをベースにホットデプロイを実現する
  • 上記ライブラリのlistenerをアプリ側に実装しておく
  • Perlアプリの時と同じくserver_starter(Go実装)を利用してアプリを立ち上げる
  • アプリをアップデートする際はサーバ側のGOROOT内でgit pullさせて次にgo getしてbin以下にコマンドを生成
  • 予め仕込んであるdaemontoolsディレクトリを$ svc -h /service/stamp_serverとしてgraceful restart

現状のコードだとgraceful shutdownにはうまく対応出来てない疑惑がありますが、画像配信サーバーですし、間に短いTTLを仕込んだCDNを挟んでますし、なんとかなります。

ハマりどころ

一番最初、デプロイしてしばらくたつと、

あれ〜、やけに詰まるな〜 Goだとパフォーマンス悪くなるのかな〜?

なんて自体に陥りましたが、これは別段Golangのせいでは無く、僕が書いていた禁則処理のロジックで稀に無限ループをつくってしまうバグが潜んでいただけでした。「あるある〜!」そう言語が悪いんじゃないんです、自分が悪かったのです。

と、まぁそこが大きな躓きポイントなだけであとは十分パフォーマンス出てますし、不具合もなく快適なアプリになりました!

まとめ

ボケてにおいてスタンプサーバをGo実装で書き直して、Go本番童貞を捨てた話を書きました。本番化しないと分からないことも結構あったので、やってよかったと思います。Perlと比べると言語の性質的に煩雑になるケースもありますが、コンパイルされる時点で「不本意なことを弾いてくれる」というのは強みであるし、単にGolangが気に入ったので、他のコンポーネントもジャッジ次第でGoで書いていきたいですね!

Go言語によるWebアプリケーション開発

Go言語によるWebアプリケーション開発

改訂2版 基礎からわかる Go言語

改訂2版 基礎からわかる Go言語