Toyama.rbのロゴを作ってみた

Toyama.rbのロゴがない問題

Toyama.rbを1年以上続けていて、ロゴがないことがずっと気になってた。 管理用のリポジトリでもこんなissueが立っていて、1年以上放置されてたという・・

f:id:mugi1:20170226220158p:plain

ロゴって大事

でもやっぱ、ロゴって大事だな〜と今更改めて思い始める。

  • 「ちゃんと活動してるコミュニティ」感が出せる
  • Doorkeeperとかでパッと見つけやすい
  • ステッカー作ってmacに貼ったりしたい

お隣石川県で活動されているkanazawa.rbでは、とてもカッコいいロゴが用意されていて、いいな〜と思ってたのは秘密。

(以前参加した時にステッカーを貰って、Toyama.rb主催者にも関わらず嬉しくて今でもずっと貼ってるという)

どうやってつくる?

プランはいろいろあった。

f:id:mugi1:20170226222803p:plain

地元でなんとかしよう作戦

うっすら思ってたのは、「ずっと続けてればデザイナーの方とか参加してくれたりするんじゃないのか?」とかいうもの。

ただこれにはいろいろと問題が。

  • デザイナーの方が参加される気配はない
  • というかタダでやってもらおうなんて考えはそもそもプロに対して失礼
クラウドソーシングで依頼する

クラウドワークスランサーズのようなサービスを利用して、有償で依頼をかけてみたらどうか?というもの。

参加費で徐々に積み立てていって、そこから捻出すればいいかな?という考え。

結果としては、基本的にほぼ毎月収支0で運営しているような状態なので、運営費からの捻出は難しいかな〜?といった感じ。

(私の自腹は最終兵器)

私が描く

最も手っ取くかつコストがかからない方法。

ただ、自分は以前にとある事情から、某社のマスコットキャラクターのデザインをしてしまい、絶望的な仕上がりになったという前科がある。

が・・・、まあもう細かいことは言ってられない!

描く

描くことにした。

ツール

任意の大きさへの拡大や縮小なども考えると、ベクタ画像をいい感じに生成できるものがいいかな〜と思い、Sketchを使った。結果としては、直感的で非常にわかりやすかった。

Illustratorなどのほうが機能的には優れているっぽいけど、本気デザイナーではない私にはすぐに使いこなせるとは思えず、わかりやすさのほうが重要。

どんなデザインにするか

まずは富山っぽいものってなんだろう?と考えてみた。

  • チューリップ(県花
  • 県自体の形
  • ます寿司
  • ブリ
  • 黒いラーメン

複雑なデザインは無理だと思うので、ある程度シンプルなもので、かつ富山っぽいもの。

見た目も良さそうで、シンプルに作れそうなものということで、ひとまず

  • チューリップ

を採用

作ってみた

アイコン的なもの

f:id:mugi1:20170226232229p:plain

名前入り

f:id:mugi1:20170226224951p:plain

自分でいうのもあれですが、割といい出来になったと思う。妻にもいろいろと意見を貰い、最終的にこの形に落ち着いた。

(始めたら意外と楽しくて、試作して捨ててみたいなことを繰り返してた結果、6時間ぐらいやってたという)

それなりに好評

Toyama.rbのslackで流してみたところ、それなりに好評だった。

f:id:mugi1:20170226230455p:plain

改良

いい感じだ!ということで、ここから改良を重ねる。

そして翌日。

試行錯誤の末

完成したデザインがこちらになります。

f:id:mugi1:20170226230646p:plain

大人気

f:id:mugi1:20170226231007p:plain

どうしてこうなった

私にも良くわからないが、「BURIRuby食ってるVerも作ってみたらどうなるか」という謎の衝動に駆られて作ってしまった。

アンケート

そうはいってもこれはダメだろ!という意見もあるかと思い、一応先に作ったチューリップバージョンと比較して、どっちが良いかアンケートもとってみた。

さすがにBURIは面白いけど、ロゴとなるとチューリップがいいよね〜

結果

f:id:mugi1:20170226231458p:plain

f:id:mugi1:20170226231520p:plain

かくして

f:id:mugi1:20170226231800p:plain

ロゴ完成!!

今後

ステッカーを作って、完成後は参加者に配りたい。 (BURIはちょっと・・・という方もいると思うので、チューリップverも多少は用意しようかと思う)

今後ともToyama.rbをよろしくおねがいいたします。

TDDBC Toyama 参加(と主催)してきた

こんなイベントに参加&主催側として色々やってきた。

tddbc.connpass.com

TDDBCとは

TDD Boot Camp(TDDBC) とは、テスト駆動開発(Test Driven Development)について、座学だけでなく、実習形式で手を動かして体得することを目的とするイベントです。

各地のコミュニティの方々が中心となって、全国各地で行われています。

(http://devtesting.jp/tddbc/ より引用)

Toyama.rbにも頻繁に参加してくれている @hikaruworld さんが中心となり、@kunitooさんと私で手伝うような形で準備していて、この土日に無事開催できた。

特別ゲスト

@t_wada 氏。もうこれ以上無い完璧なゲスト。
個人的には「えっ、まじで!?あの@t_wadaさん来てくれるの!?」って感じだった。

会場

秀夢木楽館

www.airbnb.jp

この会場がすごかった。

  • 5階建
  • 一棟丸々借りれる
  • 立派なキッチン
  • カトラリー使える
  • コーヒーメーカー使える
  • セミナールーム的な空間もある
  • 全体的にオシャレ
  • 木の雰囲気がいい感じ

こういうイベントのために存在してるんじゃないのってぐらいの会場だった。問題があるとすれば、一定の人数がいないと借りることができないというのがあって、たとえばToyama.rbで毎月借りれるような会場ではない。

TDDBC - Day1

@t_wadaさんによるライブコーディング

FizzBuzz問題を題材としてTDDを実践した場合の例を @t_wadaさん自らがライブコーディングしながら解説。

とても印象に残ったのは、「テストを減らす責任」という部分。

仕事のなかで “テストコード”, “TDD” といった文脈で会話をするときに中心に挙がるのは

  • テストを書く文化をどう根付かせるか
  • テストをうまく書くにはどうするか
  • 効率のよいテストはどう書けばよいか
  • テスト駆動をするためには何が必要なのか

みたいな、「テストを書く」といった部分にフォーカスすることが多かったように思う。

今回 @t_wada さんが言っていたのは、私の理解では以下のような内容。

  • 実装者以外がテストを消すことは心理的な面でも非常にコストが高い
  • 対称性の無いテストコードがあると、後から見た人には「意味があって非対称」「意味なく非対称」の区別がつかない
  • 実装者であればそこの判断がつくため減らしておくことができる

書くことも大事だけど、書いていく過程でテストコード自体もリファクタリングをしていき、テストコード自体が負債とならないような意識を持つことも大事だな〜と感じた。でもこのあたりは、いかに芯を捉えたテストコードを書けるか?ということにも繋がってくると思うので、経験と勘も必要になりそうだ・・。自分はまだ修行が足らなそう。

ペアプロで実践TDD

  • テーマ「セマンティック・バージョニング」
  • “1.4.2” といったバージョン情報を取り扱うクラスをTDDで徐々に拡張していく
  • 言語ごとにわかれてペアプロ
  • このときはjsで参加した

デモ

主催者側ということで、問題のさわりの部分のペアプロの雰囲気を @kunitoo さんと二人でデモをした。色々と困惑するような雰囲気も含めて全部デモとして伝えればいいでしょ!とか思ってたら、本当に細々と困惑して期待通りの結果になった。

  • 反省 : 事前に用意した不要なサンプルコードは邪魔なので消しとくべきだった。

ペアプロよかった

仕事ではまともにペアプロというものを経験する機会がなかったので、若干緊張していたのは秘密。

「ペアでやったからといって効率が落ちるわけではない。むしろ上がることもあるよ。」みたいな話を聞いたことがあったけど、実際やってみると確かにその通りだった。

一人だとついつい細かいところを考えすぎて手が止まっちゃうところで、二人でやっていると不思議と「とにかく前に進めよう」という気持ちになる。

ただ、これも噂に聞いていた通り、死ぬほど疲れるというのも事実だった。 逆に言えば一人のときに短時間でそこまでは疲れないので、「実は自分ってそんなにパフォーマンス出せてないんじゃないの?」という気持ちに。

教える学び

どちらかというとペアの方と自分とでは、自分の方がjsに関するノウハウは持っていて、教える側に回ることがちょくちょくあったけど、これは教えてる側も思考が整理される行為だった。

どこかで聞いたようなワードだけども、うまく教えるためには教える側がしっかりと理解していることが前提条件になってくるので、逆に自分がフワっとしてる部分も現実として突きつけられたりしてた。 (整数判定で自分が Number#isIntegerを思い出せなくて絶望したりした)

夜の部

なぜか尋常では無いご馳走が振る舞われた

  • ぶりしゃぶ

  • ぶりとふぐ

  • 乾杯

  • カワハギの肝

特にカワハギの肝が半端じゃなかった。

これを醤油に溶いてブリつけて食べたら、もう美味すぎて死ぬかと思った。
富山県民でよかった。
(ご用意していただいた @nagise さん、ありがとうございました)

Hololens

持ってきた方がいらっしゃったので、MicrosoftのHololensを体験させてもらった。

壁を認識しているようで、空間に映し出されているオブジェクトやウィンドウが、綺麗に壁に沿って配備されるのがなんだか不思議。

操作感としては、個人的には難しく慣れが必要だな〜と感じたけど、色々な可能性を感じるガジェットだった。

寝不足

色々と盛り上がってしまい、AM4:00まで起きてて完全に寝不足。

でも楽しかったし満足も多いので、まったく後悔はしていない。

でも寝不足。

TDDBC - Day2

ダメコード鑑賞会

二日目の朝は、まずはウォーミングアップということで、とある非常に強烈なダメコードを皆で鑑賞しながら、好きに喋ってみようみたいなことをやった。

途中、"&&“ と三項演算子が入り混じったコードがあって、全体的に「え?これって結果どうなるんだ・・?」みたいな議論が起きた。

ただ、肝心なのは「そもそもこういう議論をしないためにもちゃんとやろうね!」というところだな、という認識を改めて確認。

実践版リファクタリング&機能追加

あらかじめ用意されている Java/C#/Javascript/Ruby/PHP のサンプルコードを利用して、リファクタリング・機能追加をTDDを交えながら実際に体験。

サンプルコードについては極力言語差異が無いように、

  • 構造は同じ作り
  • 変数名も完全に同じ
  • 結果は標準出力のみ

といったものを事前に用意。

さらにいえば、

  • 実装漏れとなっている部分も同じ
  • バグも同じ

といった状態。

これは、Toyama.rbのもくもく会を使って用意した。
PHPのみに関しては事前に用意できず、1日目の夜の部のときにPHP希望者の方にご協力いただいて作成。(感謝)


余談として、Toyama.rbもくもく会では最初に「今日やること」を宣言しており、この時の私の宣言は「今日はJavaでクソコードを書きます」だった。もはや自分でも何を言っているのか解らなかった。


さらに言うと、クソコード作成中は「綺麗なコードですね。ダメです。」みたいなワードが飛び交っていて、カオスな雰囲気が実に良かった。

既存問題にどう立ち向かうか?

テーマとしては、

  • すでに存在しているコード
  • テストはない
  • 仕様もない

みたいなものにどう立ち向かっていけば良いのか?というところだったと思う。

アプローチとしては、まずは全体のアウトプットをテストするコードを用意し、内部を変えた場合にブラックボックス的に問題が無いことを維持できる状態を作っていた。

あとは、「機械にやらせる」というワードも覚えときたい。

@t_wadaさんも含め、ガンガンIDE(WebStormとか)の機能を駆使している光景が良く目に入ってきた。当然といえば当然だけど、確かに手でやるより安心してやれるわけだし、使えるもんは使った方がいいよね。

既存バグの恐怖

サンプルコードを用意した側としては、本音を言うと軽い気持ちでバグを仕込んだものの、これが参加者に対して「既存コードのリファクタリング中に既存バグに出会ったらどうするか?」を考える良いきっかけになった。

というか仕込んだ私自身がどうしたらいいか悩んだ。

悩みどころとしては

  • バグも含めて既存実装なんじゃないの?
  • いやいや仕様が明確なんだから直すべきでしょ

という点。
明確なゴールが定まっている場合にはテストを書いて修正する方法もあるけれど、そうではない場合は難しいこともあるし、こればかりは状況に応じて判断する必要があるようだった。

参加してみて

学べた

実に学びが多かった。

Toyama.rbでも「手を動かしたい!」というのは前から言っていて、今回もゴリゴリに手を動かして参加するイベントで、実際に何かが身についた感がある。

次は実践

「TDDはスキル」という言葉も印象的だった。

一人でも、まずは小さいところからコツコツやっていこう。

というわけで

参加者の皆様、そして @t_wada さんありがとうございました。

@hikaruworldさん、@kunitooさん、おつかれさまでした!

無線ルータをASUS RT-AC68U に変えたら色々改善された

昨年に家を新築したのですが、その際に無線ルータを新調しました。

その際に購入したのはBuffalo製の以下のものです。

buffalo.jp

3階建でもいけるよ!!みたいなことが書いてあったのと、Amazonなどでも売れ筋っぽかったので乗っかって買ってみたんですが、これがまた微妙でした。

  • 2階に設置して、1階にいると回線強度が弱い
  • 結構切断される
  • 速度が安定しない

wifiをOFF→ONとして再接続するとリカバリーすることが殆どでしたが、すぐに何かを確認したいときに切断されてたりすると、やっぱりイラっとするもので。

HPにはビームフォーミングがどうのこうのとか記載がありましたが、1年使ってみても、まったくそれらしい恩恵を感じることはできませんでした。

というわけで

無線ルータを買い換えてみました。

買い換えたのはこちら。

www.asus.com

知り合いからの情報やネットからの情報でも、比較的ASUS製のルータについては評判がよかったので、信じて購入してみた。

結果として、これがすごい良い買い物でした。
もともと抱えていた問題が全部解決。

  • 設置してからひと月くらい経つけど、一度も利用中の切断がない
  • 家中どこでも接続が安定している
  • オンラインの計測などでは、2〜3倍程度の速度に

今までの一体何だったのっていうレベル。

強いて欠点をあげるとすると、本体の大きさでしょうか。
存在感が半端ではないし、それなりに重量もありました。

我が家の場合は、2階の家族は使わない部屋(=私の書斎)の片隅に設置してあるので、大きさはそれほどデメリットにはなりませんでした。

5GHz帯と2GHz帯でSSIDを分けることができるので、スマートフォン類は2GHzに接続し、PCやChromecastなどは5GHzと、接続を分けています。

さらに使っていて驚いたのが、管理機能の速さ。
管理画面もサクサク動きますし、再起動もかなり速いです。

地味な部分ではありますが、こういうところも大事ですね。

無線ルータでなにを買おうか悩んでいる方にはおすすめです。

雑記でした。

社内ハッカソンを開催&参加した

あけましておめでとうございます。

年明け前の2016年の12月に、土日を利用して社内ハッカソンが開催され、 主催側として色々やったのと同時に、エンジニアとしても参加してきました。

中小SIer的な会社なこともあり、 「ハッカソン・・なにそれおいしいの?」 といった雰囲気も当初は漂っていましたが、なんだかんだいって上手くいったと思います。

事前準備

そもそも「ハッカソンやりたい!」といっても、課題がたくさん。

  • お金はどうすんの?
  • 平日?土日?
  • 会社の許可降りるの?
  • そもそも人集まんの?
  • etc...

解決のためにしたこと

  • 話自体は早めに進めた
    • ・・と思う
    • 会場とか予算とかは早めに
  • 初回なので規模は小さめにした
    • まずは1回うまくいった例が欲しかった
  • ホームページをガチで作った
    • 本気でやるからな!!という雰囲気を醸し出す

正直、「いらん根回し無しでスパっとやらせてくれよ!」と思っていた部分もありますが、まあ社風というか、言っても仕方ないし、それがやらない理由にはならないので地道に・・

私個人としてはホームページ作成を担当しました。 終了後のアンケートで「ホームページがかっこよかった」的な感想をいただけたので、うまいことガチなことが伝わるように作れたようです。

(ちなみにデザインにはMaterializeを使ってみました)

その他の部分は会社の先輩が尽力してくれたのがかなり大きかったです。感謝。

最終的には、土日開催で15人ほど集まりました。

つくったもの

チーム内にいたAWSに詳しいメンバーのアイデアで、AWSの操作をSlackから行うためのChatBotを作りました。

特徴としては

  • AWSの操作をSlackから行える
  • Serverless(AWS Lambda)で作る

2日間(作業時間は1日強ぐらい)で、EC2インスタンスを一通り操作できるところまで作れました。

(ミスを超煽って来るBOTの図) f:id:mugi1:20170108233126p:plain

serverlessで結構ハマりました。

というか、webpack+ES6+Babel+serverless の構成にしたときに、ビルドが通らなかったり、人のデプロイとぶつかったりして、コーディング以外の部分で結構つまづきました。

このあたりは事前準備が足りんかった。

感想(主催側として)

募集用のホームページや、開催終了後のレポートページを本気で作ったのは良かったように思います。(自分が作ったこともあるのでそう言っておきたいという節もありますが・・)

こういうイベントって、ノリや勢い、雰囲気といったものも重要だと個人的には思っています。 そういった部分を煽るためには、目立つ部分になるホームページなどをきちんと整備したのは正解でした。

また、長らく社内全体として技術への姿勢や考え方について課題があるな〜と思っていましたが、こういったイベントをやってみたことで、「お?意外と捨てたもんじゃないぞ?」という面があることにも気づくことができました。

ハッカソンを通じて普段接しない人と関わる機会が生まれたのも大きい要素だったように思います。

感想(参加側として)

事前準備が甘かった

個人的にはこれに尽きます。

テーマ自体は事前のアイデアソンで決まっていて、チーム内でフロントエンド部分の知識をある程度保有しているのが自分だったので、「ビルド環境などの整備はまかせてください!!」的なことを言っていたにも関わらず、そこそこつまづいてしまいました。 ルール上許可されるのであれば、コードを書く以外の不安要素はできるだけ取り払っておくべきですね。

すげーつかれた

仕事とは違う、なんともいえない疲労感がすごかったです。
達成感のある気持ちのいい疲れではありましたが、月曜日のパフォーマンスは正直落ちてた。

自分たちのスキルがわかる

うちみたいな会社ではよくある話なのかもしれませんが、 「結局だれがどのスキルをどの程度使えるのかがわからない」という問題をよく聞きます。

ハッカソンのようなイベントの場合、強制的にスキルを発揮しないといけないかつ、同じ時間の作業かつ最終的なアウトプットが存在するので、とてもわかりやすいんですよね。

経歴書などを書かせるよりもよっぽど正確なことが把握できるのではないでしょうか。

というわけで

機会があれば社外のハッカソンとかも参加してみたいな〜。

今年は色々と大変になりそうだけど、がんばるぞー!

1年ふりかえり

気づけば、Toyama.rbをはじめてまる1年経ちました。

あっという間でしたが、思えばこの1年ほどで色々と経験し、得るものも多かったです。

全然ブログ書いてなかったのもあるので、 このあたりで一度振り返ってみます。


プログラミングキャンプ参加

mugi1.hateblo.jp

自分の中ではすべてがここから始まってます。

PlayFrameworkがきっかけで触り始めたRubyRailsでしたが、 独学に限界を感じて勢いだけで突っ込んだ人生初の勉強会でした。

結果としては

  • もっと早く勉強会とか参加すればよかった
  • みなさんいい人だった
  • 世界は広い

といった感じ。

そして、富山にもコミュニティないのかな〜・・と思った結果

Toyama.rb開催

富山にはRubyのコミュニティはなかった。

上記の体験をブログに書いたところ、西脇.rb 伊藤さんの紹介で地元富山のエンジニアの方がブログにコメントしてくれたことがきっかけで、Toyama.rbを作っちゃった。

勢いで作った感じはありましたが、ちゃんと人数が集まって安心。

倉貫さんと語らう会

社内の先輩が以前から知り合いだったこともあり、新しい書籍が出版されるタイミングで、ビアバッシュ形式の語らう会を開催。

Toyama.rbで一番人数が集まった会でした。ゲスト効果すごい。 内容的にも得るものが本当に多かった。

自分自身を見つめ直す機会にもなりました。倉貫さんホントにすごかったです。

数学パズルを解こう会

www.shoeisha.co.jp

変わったことがやりたいな〜、と思い、みんなで同じテーマでコードを書いてみよう!という会を思いつきで企画してやってみたところ、結構盛り上がりました。

同じテーマだとコードをみたときにイメージしやすく、ちゃんと勉強になってる感があったのも良かったです。

フルリモートもくもく会

実験的にフルリモートで開催してみました。

・・・が、正直これには課題も多かったかな〜と反省しています。

  • 常に通信するので個人のマシンスペックによっては重い
  • 終始無言だと一人とさして変わらない
  • 普段リモートワークの人からすると、直接会うイベントだからこそ価値がある

なにごともチャレンジですよ!と付き合ってくれたコミュニティの皆様には感謝です。

東京・富山会場での開催

開催のうち半数ほどは永和システムマネジメントさんを東京会場として、2拠点開催することができました。

これは完全に @kunitoo さんのご協力あってのことだと思います。 本当にありがとうございます。


個人的にもくもく会でやったこと

  • RSpecを書いてみる
  • React.jsのサーバサイドレンダリングを試す
  • ターミナル環境を整える(zsh/peco/ghq/enhancdなど)
  • Gemのソースを読む(Faker)
  • ゼロからアプリを作ってどこまでいけるかやってみる
  • DeviseでOmniauth
  • Unicorn/Puma にデプロイしてみる

良かった点

  • Toyama.rbを毎月継続開催できた
  • もくもく会だけでもいいかな?と思っていたが、特殊企画もできた
  • 私しか居ない、という会は無かった
  • 参加者の方と仲良くなれた(と私は思っている)

改善すべき点

  • もくもくしすぎ感があったかも。参加者同士の交流が飲み会頼みだった。
  • 開催することに意識を持ってかれていた。
  • 自分のRubyスキルって上がったのか?
    (まあでもそれなりに色々やったような気もする)

まとめるとこんな感じかと思います。

来年以降の開催としては、もう少し参加者同士で関われるような内容になるよう、中身を工夫していければな〜と思っています。

個人的なところでいえば、なんだかんだいって書いたコード量が少なかったのが最大の反省点です。

原因としては、断片的に学ぼうととしていたことが良く無かったのではないかと。 少し書いて満足してしまって、トータルで見たときに、学んだこと同士があまり繋がらないのですよね。

何か1つWEBサービスなり何なりを決めて、それを軸にコードを書くようにしたほうが長期的に続けることもでき、実際に役に立つスキルを得ることもできそうです。

まずは案を考えるところからですが、来年はそんな方向でやってみようかと。


Toyama.rbに関しては参加していただいた皆様のおかげで続けることが出来ました。ありがとうございました。

これで終わりみたいな雰囲気ですが、今後ももちろん続けていくので、これからもよろしくお願いします!

「プログラマ脳を鍛える数学パズルを解こう会」を開催しました

(盛り上がってほとんど写真撮るの忘れてました)

Toyama.rb #05イベントとして、「プログラマ脳を鍛える数学パズルを解こう会」を開催しました。

プログラマ脳を鍛える数学パズル ?

↓こちらの書籍です

www.shoeisha.co.jp

翔泳社主催のITエンジニア本大賞 2016技術書部門大賞にも選ばれました。 プログラミングのスキル評価サイト CodeIQに掲載された問題から 良問とされる問題が抜粋されており、解き方のサンプルなども掲載されています。

私個人としては、Amazon翔泳社の技術書籍が半額セールだった時にkindle版を購入しました。

勉強会のテーマに

基本的にToyama.rbは毎回もくもく会を主体に開催していたので、各自が好きなテーマでもくもくとコードを書いていましたが、 今回は主催者(というか私)の都合で開催週がズレてしまい、「参加者が少ないかもな〜」→「じゃあ実験的にいつもと違うことやってみよう!」という発想で、この本をテーマに開催することにしました。

チョイスした問題

問題自体は私の独断と偏見で良さそうなもの(できれば現実世界の具体的なモノをイメージしやすそうなもの)をチョイス。比較的本の中でも前半〜中盤に掲載されている易しめの問題にしましたが、実際やってみたら全然易しくなかったという現実。

というより、解こうと思えば解けるけど、パフォーマンスや可読性などを考えると良い感じのコードにならなくて悩むという。易しめのにしたのは正解だったかも。

実際の問題は↓です


Q1. バスの両替機

前提条件
  • 両替で出てくるのは 500/100/50/10円の硬貨のみ
  • 両替で払い出せるのは最大で15枚まで
問題
  • 1000円投入した場合の両替パターンは全部でいくつあるか?

実際解こうと思うと、意外と手が止まっちゃいました。

悩んだ挙句私が叩き出したコード

module Q1
  def self.count
    # プライドを捨ててすべての組み合わせで1000円になるやつを探す
    count = 0
    (0..15).to_a.each { |a|
      (0..15).to_a.each { |b|
        (0..15).to_a.each { |c|
          (0..15).to_a.each { |d|
            if ((a + b + c + d) <= 15 && 500 * a + 100 * b + 50 * c + 10 * d) == 1000
              count += 1
            end
          }
        }
      }
    }
    count
  end
end

puts "answer : #{Q1.count}"

コメントがすべてを物語る。

後輩が書いてきたら「お前本当にこれで良いと思ったのか」って言われるレベル。

(0..15).to_a.each { |a| }の部分をコピペしている時に「絶対これ違うわ!!」と頭をよぎってました。

イメージ的には再帰を使ってスマートに解きたかったんですけど、時間制限を設けたのもあって間に合わず、途中で思考放棄してこんなコードに。

そして後で書籍を見ると、解答サンプルにこれを同じコードが乗っていて

「単純に解くならこんなコードで大丈夫だよ!」
「わぁ、これなら僕でも理解できるや!!」

という扱いを受けていました。屈辱である

他の参加者のコード

他の参加者の方のコードの中で、個人的に「お〜」と思ったのがコチラ

module Q1
  def self.count
    coins = [10, 50, 100, 500]

    result = []
    (2..15).each do |n|
      coins.repeated_combination(n).each do |cs|
        result << cs if cs.inject(:+) == 1000
      end
    end
    result.count
  end
end

puts "answer : #{Q1.count}" #=> answer : 20

私のコードのように無駄な重複がありません。
そして、repeated_combination がポイントですね。

リファレンス

呼び出すだけで、重複を許可したすべての組み合わせを列挙してくれます。
こういった機能の充実具合がさすがRubyだな〜といった感じです。

普通に知らなかった・・
(でもこういうとき以外で使うタイミングあるのかな?)

解き方のアプローチの違い

おもしろいな〜と思ったのが、もちろん最終的なコードは違いますが、解くまでのそもそものアプローチが人によって違っていたことでした。

上記の例の場合、根本的な考え方は

  • 使える硬貨を組み合わせて1000円になる組み合わせを探す

となりますが、人によっては

  • 1000円から使える硬貨を引いていき、0になるものを見つけていく

という攻め方をしていました。イメージ的には実際の両替に近いですね。


そして第2問目↓


Q2. ストラックアウト

前提条件
  • ストラックアウトをイメージ
| 1 | 2 | 3 |  
| 4 | 5 | 6 |
| 7 | 8 | 9 |
  • ボールを投げると的が抜ける
  • ボールは必ずいずれかの的にヒットする
  • 5以外の的は2枚抜きができる (1&2, 4&7 などはok / 5&6, 2&5などは不可)
問題
  • 的がすべて抜ける投球パターンはいくつ存在するか?

ポイントは2枚抜き。
というか2枚抜きがなければ階乗を出すだけで一瞬で終わりますね。

1問目以上に(私含め)苦戦していたようです。

  • なんか明らかに少ない数字になるぞ・・
  • 処理が返ってこないぞ・・

といった声が多数。大変楽しんでいただけたようです。

私がひねり出したコード

module Q2
  PATTERN = [
    [1], [2], [3], [4], [5], [6], [7], [8], [9],
    [1, 2],
    [2, 3],
    [3, 6],
    [6, 9],
    [9, 8],
    [8, 7],
    [7, 4],
    [4, 1]
  ]

  def self.hit(board, target)
    # いずれかが存在しなければ不正な投球
    target.each { |n| return 0 unless board.include?(n) }

    hit_board = board - target

    # 空になったら終わり
    return 1 if hit_board.empty?

    # 残りのパターンを網羅
    return PATTERN.map { |target| self.hit(hit_board, target) }.inject(:+)
  end

  def self.strike
    PATTERN.map { |target| self.hit((1..9).to_a, target) }.inject(:+)
  end
end

puts "answer : #{Q2.strike}"

今回は何を思ったか「今回は再帰で解きます!」と宣言してスタートしたので、明らかに自分の首を締めてしまったのですが、なんとか宣言通りのコードになりました。

「投げられるパターンが決まってるなら、全部投げていけばいいじゃない!」というスタンス。

コードの綺麗さというか、すっきりしてる感じでは悪くないのでは?と思います。

が・・・今回の問題では、答えを出す以外にも、さらに隠れ課題が。

処理速度

上記のコードでも答えは出るのですが、実行すると私のマシンでは約20秒程度かかります。

別に1回限りだしいいじゃん、という考えもありだとは思います。

でもほら、なんというか、速くできるなら速くしたいじゃないですか!!そこに深い意味はないんですよ!

他の参加者のコード

まずは私と同じく再帰を使っていた方の解答です

module Q2
  NUMS = (1..9).to_a
  PAIRS = [[1, 2], [1, 4], [2, 3], [3, 6], [4, 7], [6, 9], [7, 8], [8, 9]]

  module_function

  def hit seq, left = NUMS.dup
    if left.empty?
      [seq]
    else
      [
        *left.map do |i|
          hit [*seq, i], (a = left.dup; a.delete(i); a)
        end.inject(:+),
        *PAIRS.select { |pair| pair.all? { |i| left.include? i } }.map do |pair|
          hit [*seq, pair], left - pair
        end.inject(:+)
      ]
    end
  end

  def strike
    (@sequences = hit([])).count
  end

  def sequences
    @sequences
  end
end

以下がポイントなのかな〜と思いました。

  • 実際の投球パターンを網羅したリストが作成される
  • 不必要な投球を削ることで処理速度が向上されている

無駄が省かれているため、私のコードより2倍ほど高速に。

同じ再帰なのにこうも違うコードになるのか・・と感心してしまいました。

最速だったコード

そして全員のコードで最速だったコードが以下でした。

module Q2
  def self.strike
    board = *(1..9)
    count = factorial(board.count)

    two_numbers = (board.zip(board.rotate) + board.zip(board.rotate(3))). #=> [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 1], [1, 4], [2, 5], [3, 6], [4, 7], [5, 8], [6, 9], [7, 1], [8, 2], [9, 3]]
                   select {|ns| ns[0] < ns[1] }.
                   reject {|ns| ns.include?(5) }.
                   reject {|n| [[3, 4], [6, 7]].include?(n) }

    (1..4).each do |n|
      two_numbers.combination(n).each do |nums|
        next if nums.flatten.size != nums.flatten.uniq.size

        numbers = nums + board.select {|b| !nums.flatten.include?(b) }
        count += factorial(numbers.count)
      end
    end

    count
  end

  def self.factorial(number)
    (1..number).inject(1,:*)
  end
end

おそらくこのコード、書籍に載っていたサンプルより速いのではないでしょうか。
マシンスペックにもよりますが、おおよそ1ms〜2msで終了するようです。(爆速)

ポイントは、「そもそも網羅的に捜査はしていない」ということかもしれません。

処理的には

  1. まず、投球のユニークな組み合わせを列挙する
  2. 組み合わせごとに階乗値 = 投球パターンを算出する
  3. 2の合計を算出する

という流れのようで、結果的に処理の大半が単純な数値の演算となるため、非常に高速に動作するようです。

実際に自分でコードを書いたときには、「いかに網羅して調べるか」ということばかり考えていたため、 そもそも階乗すればいいじゃない、という発想がありませんでした。

根本の部分で自分の発想を疑ってみるのも大事ですね〜・・

ちなみに

今回は「よくやったで賞」という小学校のお楽しみ会でありそうな賞を用意しました。

具体的に何をしたか、というより

  • この人今日よくやったな

という人を投票で決めよう!というもの。

副賞として1,500円分のAmazonギフトカードを贈呈。(もちろん私の自腹で!)

結果的には上記の最速コードの作者に贈呈されました。おめでとうございます!

終わってみて

思いつきで開催した企画だったのですが、個人的にはかなり面白い内容だったと思います。 同じテーマでコードを書いたこともあり、会話も活発でした。

そして、人のコードを見るのは本当に参考になりますね〜

そもそも自分じゃ思いつかない発想に触れられるのはそれだけで貴重。

普段の業務で求められるコードなど、バックグラウンドとなる部分が人によって異なるからこういう結果になるのでしょうね。こういうのはコミュニティならではかもしれません。

また機会があれば全員で同じテーマでコードを書くイベントをやってみたいな〜

React/Redux 使ってみての勘所

前回のエントリでは、React/Redux/ES6のざっくりとした感想をまとめました。

mugi1.hateblo.jp

今回はその続きということで、React/Redux利用時において、

  • こうすればよかった!!
  • こうすべきじゃなかった・・

といったところをまとめてみたいと思います。

Immutable.js は使ったほうが幸せになれた

https://facebook.github.io/immutable-js/

javascriptで不変データ構造を提供してくれるライブラリ。(by facebook) これによって解消される問題が多数。

構造がネストした場合の更新が簡単に

「そもそもネストしないような構造にしろよ」という話なのですが、 大人の事情でネストせざるを得ないときもあります。

ネストしたstoreの場合、action経由で深い階層の値を更新したい場合に結構な手間になります。

たとえば user[0].products[2].item.name みたいになってしまったケース。

Object.assignやlodash#mergeなどを利用するのも手だと思いますが、 動作をきちんと理解せずに利用すると、

  • 同オブジェクト内の存在しないキーが落ちる
  • undefinedの値が落ちる(落ちない)

といった状態になり、ハマってしまうことがありました。 気をつければいいのですが、「気をつけているコード」で溢れかえるとかえって読みにくくなったり。

これがImmutable.jsを利用していると

state.setIn(["user", 0, "products", 2, "item", "name"], "yeah");

でstate自体に影響を与えることなく、新しいstateを得ることができます。

記述が統一できる

reducerで新しいstateを生成する際には、引数として受け取ったstateを書き換えず、新しいstateを生成する必要があります。

そのため、state生成時には操作時に注意することが出てきます。

  • 配列の要素を変更する場合
    • Array#concat などで新しい配列を作って差し替える
  • オブジェクトの生成方法が1つではない
    • Object#assign
    • lodashのメソッド(assign/merge/extend/default...)
    • 普通に自力で作成

これらで対応することそのものが問題ではありませんが、「ネストした場合の更新」の欄でも触れた通り、方法によってundefined状態のフィールドの取り扱いが違ったりするため、複数人での開発時には記法を統一するほうがベターだと思います。

「reducerでのstate操作はImmutable.jsで」としておけばそれだけである程度は操作が統一できるため、心理的負担も少し下がります。

比較が簡単に

Reactでコードを書いていくと、どこかでパフォーマンスチューニングのために、shouldComponentUpdate によるレンダリング抑制を書く機会が登場します。

このとき、とりあえず this.propsnextProps を比較して差異がなければレンダリングしない(return false)とするケースが多いのですが、Immutable.jsを利用していれば、=== を利用して容易に比較することが可能となります。

利用しない場合には自力で比較するか、lodash#isEqualなどを利用することになりますが、細かいところでカスタマイズが必要になるケースが多いです。

Reactの公式docにもImmutable.jsに関する記載はありますね。

facebook.github.io

構造をコード上に定義しておける

redux(flux)を利用した場合、アプリケーションの状態を表すstoreは一箇所で管理されますが、初期状態とすべきstore状態をどこに定義するか?という問題が発生します。

reducerファイル内に直接定義してしまっても大丈夫ですが、規模が大きくなってくるとカオスになりがちです。というかカオスになりました。

そこで、Immutable.jsを利用してデフォルトのstore定義のみを定義しておくことで、store全体がどのような構造かすぐ解るようになり、見通しが良くなりました。

また、reducerを分割管理している場合などは、ベースとなるstoreを定義しておき、そこからImmutable.jsのmergeを利用して拡張することで、継承っぽくstore定義していくこともできます。(お作法的にどうなのかは謎)

export const User = Immutable.fromJS({
  id: null,
  name: "",
  email: ""
});

export const AdminUser = User.merge({
  tel: "",
  address: "",
  permission: false
});
function user(state = User, action) {
  switch (action.type) {
    case 'USER_UPDATE':
      return /* update */;
  }
  return state;
}

function admin(state = Admin, action) {
  switch (action.type) {
    case 'ADMIN_UPDATE':
      return /* update */;
  }
  return state;
}

ただ、Immutable.jsはファイルサイズが大きいのがネックとなるケースもあるようです。

ご利用は計画的に。

connectはひかえめに

connect記述により、任意のstoreをsubscribeすることができます。

これを利用すると、Reactで陥りがちなpropsのバケツリレーをぶった切ることが可能となります。

・・が、実際にはあまりこれはオススメできません。 最初はガンガンconnectを利用してコーディングしてしまっていたのですが、後になって色々と問題が表面化してきました。

再利用しにくくなる

connectしてstoreをsubscribeするということは、そのstoreに依存していると言っても間違いではないと思います。 一概に全てというわけではありませんが、大半のケースでは、connectを利用したcontainerは1つの用途に限定されてしまい、「あー、connectsしてるから使えないじゃーん!」というケースが発生して悲しい思いをしました。

パフォーマンスに影響が出てくる

通常のReactコンポーネントであれば、親要素で shouldComponentUpdate によるレンダリング抑制を行った場合、子の要素も自動的にレンダリングが抑制されます。

とても素直な考えだと思いますが、ここで子がconnectしてしまっていると、親からのprops伝搬とは別に、storeの変更時にもレンダリングが発生することになります。

つまり、子自身の中で shouldComponentUpdate による抑制を行う必要が発生します。別にそれでもいいじゃん、という発想もありますが、数が増えてくると shouldComponentUpdate そのものが大量になってしまったり、パフォーマンス低下時に原因を追求するのが難しくなっていきます。

「親で shouldComponentUpdate ちゃんと動いてんのになんでこんなに描画重くなるんだ・・・」というときにこれが原因でした。

というわけで

などなどの理由から、基本的には、connectするのは最上位階層のみとし、子以下には素直にpropsでバケツリレーとするほうが、最終的には可読性・保守性ともに望ましい形のコードになりました。 SPAの場合は、ルーティング単位でrecducer分割してconnectするとちょうど良い感じですが、そのあたりは作成するアプリケーションに応じて差異があるかと思います。

いずれにしても、乱用しないほうが望ましいかも。

Storeはできるだけフラットな構造に

Immutable.jsの欄で「ネスト時の更新が簡単に!」とか書いてますが、そもそもの話としてはStoreはできるだけネストさせないほうが望ましいです。

理由は

  • ネストしていると、undefined/null を意識する手間が増える
  • そもそも更新がめんどうになる
  • PureRenderMixinが使えるようになる

などです。

normalizeするのも1つの方法ですね。

github.com



思い返すと他にもたくさんポイントとなる箇所はありましたが、また同構成を利用する機会があれば、とりあえずは上記は最初から抑えた状態で着手したいな〜という感じです。

ただ、やはりもう少し軽いもの(実装量的に)があれば嬉しいな〜

めまぐるしく変化し続けている世界ですし、2016年にもまた何か大きい変化があったりするのかな。