その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

社内でDDD勉強会をやった

DDD (Domain Driven Design/ドメイン駆動設計) についての学習気運があり,その勉強会を社内でやったのでその経過を記すものです.
DDDに関する詳細な内容には触れません (良い本や資料が巷には溢れています).読書会自体をどうやったか的な話です.

前提

developer.hatenastaff.com

基本的にこのスタイルを真似しました.

読んだ本

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

実践ドメイン駆動設計

実践ドメイン駆動設計

エリック・エヴァンスドメイン駆動設計 (青本) を読んでから,実践ドメイン駆動設計 (IDDD/赤本) を読んだという流れです.

.NETのエンタープライズアプリケーションアーキテクチャ 第2版 (マイクロソフト公式解説書)

.NETのエンタープライズアプリケーションアーキテクチャ 第2版 (マイクロソフト公式解説書)

やっていませんが,続いて上記の本 (黒本) を読むというのもありかも知れないね,という話を会のメンバーとしました.

も良いかもわかりません.

が,とにかく青本をやってから赤本をやるということにしました.理由としてはやはり原典を読んで知識を付けてから実践に行ったほうが良いであろうという考えからです.確かにDDDを形作るエッセンスが青本には記されており,一読しておいて損はないと思いましたが,しかし後になって思い返すと別に赤本だけでも問題ない気もしました (もしかしたら青本の代わりにInfoQのDomain Driven Design Quicklyを読むのでも十分なのかもしれない).読みたい本を読むべきです.

進め方

  • 1週間に1回開催 (やむを得ない場合は開催されないこともある)
  • 1回あたりに1章やる (1章が長い場合は2回程度に分割する.話を忘れてしまうので2回を超えて分割しないほうが良いと思っている)
  • 全員があらかじめ該当する範囲を読んでおく
  • 週替りで当番を決め,当番になった人はその章の中で疑問に思ったことや議論したいことをmarkdownにまとめてGitHubのrepositoryにpull requestとして投げる
    • あくまで疑問点や議論したいポイントをまとめるのであって,内容をまとめるわけではない
    • 当番でない人も,疑問に思ったことや議論したい点についてはpull requestのコメント等で表明していく
    • 当番になった人はその回の司会もやる
  • そのmarkdownをベースとしながら疑問の解消や議論等を行なう (適宜本の内容をなぞっていく)
  • 勉強会が終わったら飲みにいく

重要な点は,「参加する全員が本をしっかり読み込んでおく」という点と「疑問点や議論したい点をまとめる」という点です.
前者が成り立つからこそ,後者も成り立ちます.しかし後者は慣れるまでなかなか難しい.うっかり内容のまとめになってしまいがちなので「全員しっかり本を読んでいる」という事を意識していく必要があると思いました.

そして個人的に重要だと思ったのは「勉強会が終わったら飲みに行く」というものです.これは勉強会の延長のようなもので,ざっくばらんに議論してみたり,あるいは「最近こういうことで困ってるんだけど,今日のこのアプローチでいけないか」などという感じで軽く相談が出来るので,なかなか良かったと思いました.また飲み会が勉強会のモチベーションのひとつにもなる (個人の意見です)。
飲み会が嫌いな人には合わないかもしれませんが,幸いにも今回の勉強会のメンバーはみんな飲み会が好きな人が集まったので,これはよくドライブしたように思います.

なおGitHub使うかどうかとかは重要な問題ではなく,チームや企業に合ったツールを使えば良いと思います.

規模

今回は4人でした.これくらいの人数でちょうどよかったな,という感想です.
勉強会の規模が大きくなっていくとどうしても自分事感が希薄になっていき「俺が読んでなくても大丈夫だろう」「議論に参加しなくても問題ないだろう」という感じになっていきがちですが,この程度の規模感だとそうなりにくく,全員参加型でほどよい緊張感を持って進めていけるので良いと思いました (あとこれくらいの人数だと飲み会の予約も取りやすいし).

困った点

DDDに本当に詳しいエキスパートが不在だったため,「これで本当に合っているのか」などといった疑問に襲われることが何度かありました.
そういう時は一応議論をしつつインターネットで調べながら手探りで答えを探してゆき「まあこういうことなんじゃないか」と全員で認識を合わせることで乗り切っていきましたが,もしかしたら間違えた知識を身につける可能性も孕んでいます.
勉強する分野のプロがいた方が良いな〜というのには首肯するところであります.

所感

なんやかやこういうスタイルで1年近く継続して勉強ができて良かったです.
独習に向く分野もあれば,複数人で学ぶのが向いている分野もあると思っており,DDDは後者に近いと思いました.その理由というのも,DDDには方法論だけではなく,プロジェクトに関わる全員に関係のある組織論に近い要素が含まれていると思ったためです.複数人で議論をし,認識を合わせ,不明な点を少なくしていくというスタイルは実際のDDDにも通じるものであり,その結果このような勉強会のスタイルは上手くマッチしたのではないかと思いました.

今後も何か興味深い分野があったら,このようにやってみたいものです.

私信です

私信ですが転職いたします.以下の通りです.

From: LINE
To: Soracom

関係各位に感謝を申し上げます.ありがとうございました.
以上です.よろしくお願いします.

なお本記事は以下のレギュレーションに従いました.

twitter.com

[追記]
職場崩壊だとか,ネガティヴな方向に持って行きたがる向きが散見されますが,それらに対する回答は以下の通りです.職場崩壊なんて一切無かったし,本当に良い会社及び同僚でした.これ,キラキラレギュレーションに引っかかりますかね? まあいいや!

Kyoto.なんか #3で「そして物語は更に何度目かのアプリ内通知再実装を迎える」というタイトルで話してきました

kyoto-nanka.connpass.com

「そして物語は更に何度目かのアプリ内通知再実装を迎える」というタイトルで話してきました.スライドは以下です.

speakerdeck.com

前回開催のKyoto.なんか #2では「そして物語は何度目かのアプリ内通知再実装を迎える」というタイトルで話したのですが,今回はその後日談 (?) の話をしました.

とにかくストレージ周りで苦労をしたくない,そしてできるだけ生に近い状態でデータを取り扱いたい,というモチベーションから,バックエンドのストレージにS3を採用し,RSS (Atom) ファイルをPUT (or PATCH) することで,低い労力でスケーラビリティを確保するというアーキテクチャを提案しました.
実際のS3をバックエンドとしたアプリ通知実装は,個人の趣味アプリでPoC的に実装した程度なので,実際に高い負荷が与えられた時にどうなるのかというのは身をもって体感していませんが,まあある程度はいけるんじゃないでしょうか……という見解でいます (とはいえこれは実際にやってみないとなんとも言えないでしょう).


スライドの後半に出てくる,「onetime tokenを用いたS3からのfetch」については,発表中に「Pre-Signed URLsを用いれば似たようなことができる」という指摘を頂戴しました.ありがとうございます.セキュリティの要件にも依りそうですが,これを使うと対応できそうですね.
またスライドの方のブコメにも付いていましたが,「Amazon STSを使う」という方法でも対処できるようです.知りませんでした.


発表後の懇親会で議論した内容としては,

  • ユーザ数が多いとPUTやGETする為の金銭的コストがばかにならないのではないか
  • 複数の通知を1つに束ねる場合にRSSだと難しいのではないか

というものがあり,確かに……となりました.

前者の「金銭的コスト」については,確かに配膳する対象のユーザが増えれば増えるほどかさんでしまうので,実サービスに投入した時にうっかり破産,という風にならないような工夫が必要だなあと思いました.ここらへんは既存ストレージの管理コストや開発コスト等とのトレードオフになりそうな印象を抱きました.

そして後者の「複数の通知を1つに束ねる」というのはなかなかの難題だと感じました.例えば「Aさんがいいねをしました」という通知と「Bさんがいいねをしました」という通知をそれぞれ独立した1通ずつの通知にするのであれば,素朴に各々を1つのエントリにして,片一方を追記すれば良いので実装は単純ですが,仮に「Aさんがいいねをしました」という通知が来た後に「Bさんがいいねをしました」という通知が発火した際は「AさんとBさんがいいねをしました」という新たな通知文言となって届く,というような要件を満足したい時はそこそこ複雑な実装が求められることとなるでしょう.
こういう場合は追記するだけでは機能を実装できないので,過去の通知を舐めて,同種の通知をまとめて1つの新しい通知エントリにした後に不要なエントリを除去するというような実装になりそうですが,そうすると保持する通知件数に齟齬が生じる (例えば,フィードは10件の通知項目を保持しておいてほしいのにもかかわらず,その10件が同種の通知であった場合は1件にまとめられてしまい,通知画面が寂しくなる) 可能性があり,もう少しひねった実装にする必要がありそうです.なんらか工夫をする必要がありそうですね.大変だ.


という感じでまだまだアプリ内通知の設計・実装についての悩みは尽きないわけですが,ひとまず現状のステータスを更新したという次第です.今後も頑張ります.
なお,自分個人としての思いは「OSに通知機能があるなら,自前実装せずにそれに乗っかったほうが良い」というものです.しかしそうも言ってはおれん時もある.人生のようです.よろしくお願いします.

builderscon tokyo 2017に参加してきた

builderscon.io

参加してきました.
見た中で印象に残ったトークについて感想を少し.

詳細な内容を何も書けないんですがはちゃめちゃに面白かった

ブラウザ拡張のクロスブラウザ対応についての話.いろいろな便利ツールを自作して利用していて格好良かった.とにかくクロスブラウザ対応は大変そうという印象 (特にedge).なんとかなってほしい……

複雑なUIを持つブラウザアプリケーションをどう設計・実装するかという話.毎度のことながら実例や実コードを交えてわかりやすく説明していてよかった.Validation周りのアーキテクチャについてはあまり触れられていない分野だと思っていて,そこに言及されていたのは大変参考になった.
最後に言っていた「いくらきれいな設計に見えても,チーム内で合意が取れていない設計は間違えた設計」は本当に至言だと思う.

分割QRコードは完全に初耳で,その存在を知れただけでも収穫だった.大きなQRコードだと破損確率が上がるから,それを分割して1QRコードあたりの情報量を下げることで破損確率を下げるというのは考えられているな〜と思った.便利.

CIに時間がかかってしまうと開発のテンポが悪くなり結果的にスピードが落ちる.とにかくCIが遅いとつらい.そこで大量の並列数でゴリゴリぶん回して高速化を図るというのは合理的な考え方だと思った.そうした開発の足周りについてしっかりR&D的な活動をしているのは素晴らしい.

ファブレスな環境でキーボードを大量生産するという話.去年のbuildersconではcho45さんがキーボード製作のテクニカルな話で登壇されていたけれど,このセッションはどちらかと言うと製品製造の話で,製品設計や工場選定,部品選定,QAに至るまでのフルスタックなプロセスについて話されていて,とてつもなく濃密なセッションだった.有象無象の工場がどんどん違法行為を働いている様もうっすら明かされており迫力があった.普通にこういうコンサルタントで金を取れそう.しかしファブレスで製品を作るのはとにかく大変そうだ……

PHPの話かと思いきやHHVMの話だった.かつてPHP5で関数 (風) プログラミングスタイルで書かれていたSlackのサーバサイドソフトウェアをHHVMに徐々に移行して,今となってはHHVM + hacklangでPHPコンポーネントの全てが書かれているというのはなかなか先鋭的で面白かった.
「なぜHHVMを使っているのか」という質問に対して「SlackにはHHVMのコントリビュータがいて,知見を持っている人がたくさんいたから」と回答していて,技術選択のポリシーが確立されていてとても良いと思った.
ところで本筋とは関係無いんですが「Surprised type conversion」を「びっくり型変換」と通訳の人が翻訳されていて,非常に良い翻訳だと感心しました (本来は「Unexpected type conversion」とかになるはずなので,元の言葉のニュアンスを踏まえた結果なんでしょうが).

雑感

会場の日吉は程よく都心から遠く,カンファレンスに参加しているという感じがして良い.
慶応日吉キャンパスはHUBがあるので便利な一方,しかしついつい酒を飲みすぎてしまい一長一短あると感じている.毎日体調が悪かった.
それはそれとして今回も前回のbuilderscon同様様々な分野の話を聞けて良かった.次回も参加したい.

YAPC::Fukuoka Hakata 2017にてWeb Application Good Error Messageというタイトルで話してきました

表題のとおりです.話しました.
これは僕が普段の開発中にエラーメッセージと触れあう時に気にしていたり,考えていることを上手いこと言語化したいという試みから始まったものです.

speakerdeck.com

発表中にdan kogaiさんから「『間違えたことを言っているエラーメッセージ』も悪いエラーメッセージじゃないのか」というフィードバックを頂いて,確かに!! と思いました.すっかり抜けていました.おっしゃる通りです.

発表後頂いた質問としては「(セキュリティ的な観点から) エンドユーザ (非開発者) に詳細なエラーメッセージを表示しては駄目な場合とかがあると思うんだけど,そこらへんどうしてるのか」というものがあったんですが,回答としましては:

  • 技術的に詳細なエラーメッセージはエンドユーザに提供しない
    • エラーが出ている場合,エンドユーザに技術的詳細を提供しても基本的に対処不可能 (多くの場合サーバのエラーなので)
    • 非技術的な方法で対処できる場合はその手順をエラーメッセージとして示す (e.g. 「ネットワーク状態の良いところで試してください」)
    • 仮に「エンドユーザの操作・手順がおかしいからエラーが出ている」という場合があったとしても,それはアプリケーション側のバグ (ユースケースを想定してない,あるいは限定しきれていない) ということなので,「ユーザに正しい使い方を提示する」といったエラーメッセージは (基本的に) 提示しない
    • Tracking IDみたいなものを併記すると問い合わせとかに使えて良さそう
  • 何らかの統一的なエラーに統一する,みたいな手法もある
    • 「アプリケーションがおかしいので後でやり直してみてください」みたいなのに全部のエラーを隠蔽するとか……
    • これに関しては賛否あると思いますが
  • 技術的詳細が書かれた「解決」の為のエラーメッセージは開発者向けには出す

という感じでした.このへんは発表時間の都合上,省略してしまったので情報が薄くなってしまいました.反省しています.

あと「moznionを呼ぶボタン」はどういう実装になってるのかという質問もあったんですが,あれはボタンを押すとikachanが発火して僕にチャットでメンションが飛ぶという素朴な仕組みになっています.


今回のスライドに書かれていることは個人の思想が強いので,他にも様々な意見等あることと思います.エラーメッセージに関してはもっと色々な考えや,トピックや,思想があると思うんですがあまり表立ったものが無い気がするので,色々議論したい感じがしています.しましょう!

Exit statusのセマンティクス

*nixのexit statusのセマンティクスについてかつて質問して,答えていてもらっていたことを思い出したので記します.

moznion   [5:46 PM] signal受け取ってexitする時,そのsignalの値をそのままexit codeに使う,みたいなお作法みたいなのってあるんでしたっけ
takesako  [5:50 PM] ないと思いますー
moznion   [5:50 PM] 特に無いんですねえ,ありがとうございます
songmu    [5:51 PM] なんか、ラッパースクリプトとか書くときは、ものによるけど維持するように気をつけることとかある。
          [5:51 PM] horensoとかは維持するようにしてたはず。
moznion   [5:52 PM] なんかそこら辺はお行儀みたいな感じですかねえ
songmu    [5:53 PM] 上位でどのシグナルで殺されたかとか判断したいかどうか、とかかなぁ。
xaicron   [5:53 PM] eixt code はアプリ自体で定義しているものを出すってことに決めればいいと思ってる派
          [5:53 PM] コマンドラインだったら成功か失敗かぐらいしかほとんどユースケース無い気がする。あとはログを出そう
moznion   [5:55 PM] まあですよねえ
          [5:55 PM] 利用者がexit codeで挙動変えるような使い方をしてるかも知れないから,ラッパーであればcodeを維持するみたいな理念だと察しました
songmu    [5:55 PM] そですね
moznion   [5:57 PM] ログを出しておいたばかりにそれを利用者側に正規表現で引っ掛けられて挙動を分岐させられるのは起こりえそうですが知ったことではない
hirose31  [6:09 PM] exit code、意味あるで
tokuhirom [6:12 PM] どこがダジャレになってるのか気になっている
hirose31  [6:12 PM] w
          [6:12 PM] http://www.unix.com/man-page/all/3/sysexits/ とか /usr/include/sysexits.h とか。
          [6:13 PM] sendmailとかは、aliasesで呼ばれてるフィルタプログラムが exit 75 (EX_TEMPFAIL) すると再実行したりするで。
cho45     [6:15 PM] 絶妙に中途半端な数字だ
hirose31  [6:16 PM] 「いそのー EX_UNAVAILABLE しようぜー」
kazuho    [6:31 PM] execすればexitコード一致問題なくなるで
yappo     [6:52 PM] ひどいw
moznion   [7:31 PM] exit code割と無自覚に使ってたもんで,なんか紳士協定とかがあるのか気になったという次第でした
mattn     [7:32 PM] http://linuxjm.osdn.jp/html/LDP_man-pages/man3/exit.3.html
          [7:33 PM] https://ja.wikipedia.org/wiki/%E7%B5%82%E4%BA%86%E3%82%B9%E3%83%86%E3%83%BC%E3%82%BF%E3%82%B9
          [7:33 PM] こっちか
          [7:33 PM] 普段 0/1 だけど usage 出す時に変えたりしますね
moznion   [7:34 PM] fsckって論理和でステータス変わるのか……
          [7:34 PM] ですね,僕もそういう感じで使ってました

JSON::XSでデシリアライズする時にtrueとfalseの扱いを変更する

Perl5の話題です.
JSON::XSを用いて,JSON StringをPerlのHashRefにデシリアライズする時にtrueとfalseの扱いを変えたいという話です.

デフォルト状態でJSON::XSを用いてデシリアライズすると, trueTypes::Serialiser::true すなわち JSON::PP::Boolean の真値として, falseTypes::Serialiser::false すなわち JSON::PP::Boolean の偽値として扱われます.
普通の処理であればこれで問題ないかもしれませんが,例えば「JSON StringをPerlのHashRefにしてそれを更に何らかのシリアライザに通す」といったような処理をしようとすると,JSON::PP::Boolean のオブジェクトだと取り回しが悪い場合があります.そういった時に,true/falseを任意の値にマッピングするにはどうすれば良いか.

https://metacpan.org/pod/JSON::XS#true,-false
Types::Serialiser - simple data types for common serialisation formats - metacpan.org

やり方としては上記のドキュメントのまわりにあるように, $Types::Serialiser::true 及び $Types::Serialiser::false を任意の値 (reference) に書き換えてやると良い.これらの変数はourで宣言されており,外から操作することができる.

use Types::Serialiser;
local $Types::Serialiser::true;
local $Types::Serialiser::false;
BEGIN {
    $Types::Serialiser::true = \1;
    $Types::Serialiser::false = \0;
}

use JSON::XS qw/decode_json/;

my $json = decode_json('{"true": true, "false": false}');
use Data::Dumper; warn Dumper($json);

例えばこのようにすると true\1 に,false\0マッピングされるようになります.

あるいは以下のように所望のオブジェクトにマッピングすることもできます;

package MyBool {
    sub new {
        my ($class, $val) = @_;

        return bless {
            val => $val,
        }, $class;
    }
}

use Types::Serialiser;
local $Types::Serialiser::true;
local $Types::Serialiser::false;
BEGIN {
    $Types::Serialiser::true = MyBool->new(1);
    $Types::Serialiser::false = MyBool->new(0);
}

use JSON::XS qw/decode_json/;

my $json = decode_json('{"true": true, "false": false}');
use Data::Dumper; warn Dumper($json);

注意としては, $Types::Serialiser::true 及び $Types::Serialiser::false はreferenceを要求しているという点です.仮にここにreferenceではないscalar値なんかを突っ込むとなにが起きるかというと

use Types::Serialiser;
local $Types::Serialiser::true;
local $Types::Serialiser::false;
BEGIN {
    $Types::Serialiser::true = 1;
    $Types::Serialiser::false = 0;
}

use JSON::XS qw/decode_json/;

my $json = decode_json('{"true": true, "false": false}');
use Data::Dumper; warn Dumper($json);
$ perl json.pl
Segmentation fault: 11

SEGVします. JSON::XSはxsの処理の中身で Types::Serialiser::trueTypes::Serialiser::false の中身を SV * つまりreference相当に割り当てているためです.ここで Types::Serialiser::true|false にscalar valueすなわち SV を割り当てると当然SEGVしてしまいます.

このへん
https://metacpan.org/source/MLEHMANN/JSON-XS-3.03/XS.xs#L95
https://metacpan.org/source/MLEHMANN/JSON-XS-3.03/XS.xs#L1974
https://metacpan.org/source/MLEHMANN/JSON-XS-3.03/XS.xs#L136

<追記>
誤りの指摘を頂いたので修正しました.SvROKで事前チェックすれば良い気もするんですがどうなんでしょうね.

karupanerura [17:59]
リファレンスでもスカラ値でも `SV *` だから、ここでSvRVしているときにリファレンスじゃないとNULLが返ってくるのでSEGVしているというのが濃厚なきがする https://metacpan.org/source/MLEHMANN/JSON-XS-3.03/XS.xs#L139
[18:01]
リファレンスは `SvRV` というSVで、数値も `SvIV` というSVで差異はなくて、XSでSVを扱うときは基本的に `SV *` として扱うので、<追記ここまで>

きをつけましょう.