エンジニア的なネタを毎週書くブログ

東京でWebサービスの開発をしています 【英語版やってみました】http://taichiw-e.hatenablog.com/

SlideShareの再アップロード機能がなくなってしまったので、Speaker Deckに引っ越す。(比較表もあるよ)

プレゼン資料のアップロード。
もともとSlide Shareを使っていたため、ちょっとイライラする事があったり、「イケてるエンジニアの人のSpeaker Deck率高いなぁ…」と思いつつもSlide Shareを使い続けていたのですが、
何やら技術的な理由*1によって再アップロード機能を廃止したとのこと。

www.linkedin.com

私も技術屋の端くれなんで、

You will still be able delete your older SlideShare files and upload new presentations.

って言いたくなる気持ち、わかります。「更新」って意外とメンドウなんだよね。単なる新規登録に比べて。

…とはいえ、これは利用者としては受け入れられねーわ。
自分が発表した後に、ブログからリンクしてもらったり、埋め込んでもらったものを全く変えられないというのは辛い。

…ということで、Speaker Deckに移行しようと思います。

このタイミングなら誰か検索で来てくれそうな気もするので
自分の目で見たところの比較表でも書いておこうかと。

アカウント

  • SlideShare
    • 独自アカウント
    • LinkedIn アカウント
    • facebook アカウント
  • Speaker Deck
    • 独自アカウント
    • GitHubアカウント

どちらもよく使う、覚えているアカウントが使えるのでまぁOK.
SlideShareFacebookアカウントでログインできるのが地味に便利ではありましたが…。

スマートフォンでの閲覧

以前から、人様のスライド on SpeakerDeckをSNSなどで見つけて見る時にちょっと気になっていた点。見られないほど苦痛ではないけど見やすくもない。*2
一方、SlideShareのアプリはアプリで、結構問題があって、ストレスの一因ではあったのですが…(Webより機能が落ちていたりとか、何故か真っ黒でスライドが全然前表示されない時があったりとか)

アップロード

  • SlideShare
    • PDFの他、パワーポイントのファイル(pptx)が直接アップロード可能
  • Speaker Deck
    • PDFのみ

SpeakerDeckはパワポ、上げられないんですね。
とは言え今時は、Windowsパワポからでも普通にPDFが吐けるので、大して問題ではないです。
強いて言えば、SlideShareはpptxファイルの置き場そのものとしても使えたんだけど、SpeakerDeckの場合は別で管理しなきゃだなーと。

再アップロード

  • SlideShare
    • できない
  • Speaker Deck
    • できる!!!

ここまでの項目は見ての通りSlideShareに未練タラタラ感あるのですが… これは譲れねーわ。

*1:この辺のブログを見ると、以前からSlideShareさんの中では再アップロードが問題になっていた模様です。 http://did2.blog64.fc2.com/blog-entry-396.html

*2:Androidで勝手アプリを発見しましたhttps://play.google.com/store/apps/details?id=com.unosk.speakerdeck&hl=ja

新しいサービスを引き継ぐにあたって「ドメインナレッジ」は必要か

今年の二月ころ、ある会議の中で、
ドメインナレッジが不要なプロダクトを作りたい」
と発言した。

他の参加者の皆さん(偉い人多め)からは、総じて「ポカーン」とされてしまった。

実は、その時の私は、なぜ「ポカーン」とされているのか、よくわからなかった。


正直に言うと、二月のその会議で、一体自分は何を言いたかったのか、
その時は自分の中でもうまく言語化できていなかった。

それがついさっき、急に、ちょっとだけ分かった気がしたので、忘れないうちに言語化しておきたい。


私は、

ほぼドメインナレッジを持たない状態のエンジニアが
初めてそのプログラムを読んだ時に(あるいはコンポーネント図などシステム全体の構成を知った時に)
システムの設計からドメインナレッジ(どういうビジネスを代行するシステムなのか)を知ることができる

そういうプロダクトを作りたかったのだと思う。



いま同僚と、こちらで紹介されている、オブジェクト指向エクササイズに取り組んでいる。
qiita.com

お題になっている自動販売機のソースはこんな感じ。
https://gist.github.com/i-takehiro/3ccb2ece25c89d4ed41c

(エクササイズのお題として)非常に素晴らしいコードだ。
このコードを見て、
自動販売機とは何か
・そもそもこのプログラムが何をしたいのか
理解するのはかなり難しいと思う。


「ポカーン」とされた、会議の話に戻る。
当時の私は二年ほど、上記のような「自販機」のメンテナンス(新規の追加機能開発含む)をしている状況だった。

意図が全くわからないコードに対して手を入れなければならなかった。

作った人たちは既にほとんどいなかった。あるいはいらっしゃっても(失礼ながら)元の業務を知らないか、忘れているか だった。
(あるいはご存知なのに私が決めつけて聞かなかった時もあったかも。この点は反省)

業務に詳しい人はいたので、どういうビジネスモデルなのかは教えてもらえた。
しかし、そこから当時のエンジニアが何をどう思って今のコードに至ったのか
そのコードに手を加えるとしたら何が正しいのか

は必死に過去のエンジニアの考えに想像を巡らせる必要があった。


過去に作られたシステムの運用なんて大体そんなもんかもしれない。
とは言えその時私が見ていたシステムはあまりにビジネスそのものとプロダクトが複雑で、自分のキャパを超えていて、正直辛かったし病んでいた。


それでも。
私は、

私が作ったシステムを引き継ぐ人がほぼ背景の知識が0であってもシステムの意図を理解でき、その後変更が加えられる

そんなシステムが理想的だと思う。

当然、そんなシステムを開発するためには
・背景にあるビジネスへの理解
が欠かせなく、
更に、
・そのビジネスを「理解できるシステム」に落とし込むことができる設計力が必要だ。


だから、「ドメインナレッジが要らないシステム開発」のようなことを言って「ポカーン」とされたんじゃないかな、と
今になってみれば思う。


おまけ:当時見ていた「自販機」はこんな感じ

「自販機」はすごく複雑なものだ。

・「喉が渇いたな- 甘くて冷たいのが飲みたい」というユーザのリクエストを受け…
・まずは原料を調達。香料や砂糖などを生産している会社に在庫を問い合わせ、仕入れる。
仕入れてきた材料を混ぜ混ぜして製品を作成。コーラとか、ソーダとか、お茶とか いくらかの商品が完成する。
・商品を陳列。ユーザに選んでもらう

というような機能を持っていた。

なお、
・材料を生産・売っている会社
・ジュースを作る会社
・ジュースを販売する会社
は全部違う会社で、それぞれの会社が利益を出すために会社間の取引の際に
 ・原価に利益率を掛けて卸したり
 ・販売戦略に合わせて原価割れするくらい値引きしたり
するのだけど、この3社の、そういったお金に関する計算も全部一台の自動販売機がやっている。

「境界づけられたコンテキスト」なんてクソ食らえな、スーパー自販機だ。

※そんな自販機、今日も元気に稼働しています。毎日ぼくのお給料を稼いでくれてありがとう。
 そしていまメインで見てくださっている担当者の皆さん、本当に有難うございます。

非同期処理の成否をクライアントが追いかけるのは良くない

何かのサービスを非同期で実行する場合。

運悪く、サービスダウンなで実行されなかった場合に、どのように検知・リカバリを行うか。

 

サービスダウンによる再送をクライアントにしてもらうのはよろしくないので、

サービス提供側がキューを用意して、再送処理なりなんなり自分でハンドルすべき…

 

と思ったのですが、じゃあキューが落ちてたらどうするの?というところでふりだしに戻る…。

 

やっぱり送信側がハンドルするしかないかな…。

 

キューを冗長化するのはありなのかな。

 

一番厳密にやるなら、あとで付け合わせる方法がベストなんだろうけど、これは密結合になりやすいからあんまりしたくない…

雑記:MVC「コントローラ」ってコントローラか。

私がMVCモデルという言葉を知ってからかれこれ10年以上経つんですが、「コントローラ」っていうのが長いことずっとしっくり来ていませんでした。

モデルとビューをつなぐ だとか。
ユーザの入力を受けてモデルを呼び出す とか。
Ruby On Railsタイプのフレームワークだと「コントローラ」にロジックがわりと書かれたりとか。

どれもしっくりこないなーと思っていたんですが、そもそも自分が「コントローラ」という単語に持っていたイメージが間違っていました。
私は、アプリケーション内で、様々な機能を呼び出し調律する機能を「コントロール」だと思っていたのです。
オーケストレータとかコンダクタって呼ばれる機能ですね。

そのイメージをずーっと持っていたのですが最近ふと気づきました。

「コントローラ」ってこれじゃん。
f:id:taichiw:20171112174256p:plain

「Aボタンを押したらジャンプする」という“UI”があった時に、この「Aボタン」に相当するのがコントローラかと。

これに気づいた時に、今まで抱いていたもやもやが随分スッキリしました。

持論:Application Layerがシンプルなコードは読みやすい

DDDでは全てのビジネスロジックドメインクラスに、とのことなので当然プログラムの肝はドメインクラスなのですが、

コードの読みやすさは8割がたアプリケーションレイヤで決まると思っています。
Springで言えば、Controllerから呼ばれるServiceクラスの、はじめに呼ばれるメソッドです。
f:id:taichiw:20171112172552p:plain

ここがいかにスッキリ、整然と、必要なことのみが書かれているかで、プログラム全体の可読性が決まると言っても過言ではないと思います。
具体的には、このメソッドの行数が10行を超えていたら、既に随分怪しい香りがしている…と思います。


何故ならば、このクラスは(一般的なWebページ、あるいはWeb APIを想定した時に)、
そのURLに対して実行されるふるまいが書かれる箇所であり、普通そのふるまいは、せいぜい3-4ステップで説明できるからです。

例えば、

1. 条件に合う「A」を(DBなどから)検索
2. 同じく、条件に合う「B」を検索
3. AとBをルールに合わせて結合・加工
4. 出来上がった結果を返却

と言った感じです。

(細かく見れば内部はもっと複雑でしょうが、この程度の長さで説明できないふるまいであれば、そもそも一つのURLで扱うには重すぎです)

さて、例えば上記のように4ステップで表されるふるまいであれば、アプリケーションレイヤの(最初のメソッドの)コードは理想的には4行で書かれるべきです。


人がコードを通しで読む場合、普通は頭から読んでいくケースが多いと思います。
その際、アプリケーションの先頭がスッキリ書かれていることで、そのエンドポイント全体の振る舞いを把握することができ、それ以降の理解がしやすくなると思います。


【追記】
1. 「普通は頭から読んでいくケースが多いと思います」ということで、当然一番上のコントローラがスッキリしていることも重要です。ただし、コントローラはサービスクラスと違って明確にロールが決められているため、そこまで酷いことにはなりにくいように思われます。*1
2. 主役たるドメインクラスはもちろん重要です。…が、適切な命名がなされたメソッドがあれば*2、最悪中が多少複雑だったりゴチャゴチャしていても概要をつかむことは可能です。一方、外側が整理されていないと、まず概要をつかむことができません。

*1:Struts時代には酷いActionクラスをたくさん見ました。酷いものはインフラ層が滲み出ていました。 …とはいえ、さすがに今時はそんなことはないかと

*2:ドメインクラスに適切な名前がつけられる人のアプリケーションレイヤはそもそもきっときれいなのですが…(逆も然り)

『現場で役立つシステム設計の原則』 増田亨さん を読んだ。「データしか持たないデータクラスは作らない!」

こちらの本を読んででのレポートです。


複雑な業務ロジックは「適切な境界」で分離されていれば理解しやすくなる!
…が最近の自分の持論なのですが、じゃあ「適切な境界」って何よ? …と言われると、うまく言語化説明できない。

そんな私にたくさんヒントを与えてくれた本でした。
なかなか消化しきれていないところもあるのですが、腹落ちさせるためにもブログに落としてみます。

このブログに書いたことをまとめると・・・

  • 修正が大変なのはロジックが分散しているから
  • データとロジックをひとつのクラスにまとめるとロジックが分散しない!
  • じゃあWeb APIでサービス間連携するときも、データを持つほうにロジックを寄せるべき… と思ったら、そうでもない?

この本のすごいところ

こういうコードは修正が大変ですよね。
だから風にリファクタリングしましょう!

…と、身近なイケていないコードのリファクタリングの話を読んでいたはずが、
いつの間にかドメイン駆動な設計の話に移っていきます。

ドメイン駆動設計の部分はエリック・エヴァンスの所謂DDD本をベースにしており、


「あー あの本で見た。よくわからんかったけどとりあえず見た。」

という事柄が、随分噛み砕かれ、理解しやすく書かれています。
なのでエリック・エヴァンスに勝てなかった方には大変オススメ。
もちろんエリック・エヴァンス 誰それ? って方にもおすすめの一冊です。

ソフトウェアの変更が大変なのは「設計」が悪いから (第1章より)

ソフトウェアの変更は大変。

  • どこに何が書いてあるかを理解するまでに、調査に時間がかかる
  • ちょっとの修正なのに、変更すべき箇所があちこちに散らべっている
  • 慎重に修正したのに、思わぬ副作用に苦しむ


こういった変更が大変なプログラムは以下のような特徴がある。

  • メソッドが長い
  • クラスが大きい
  • 引数が多い


ならばリファクタリングしましょう。

  • わかりやすい名前を使う
  • 目的ごとに変数を用意する
  • メソッドを独立させる
  • 異なるクラスの重複したコードをなくす
  • 狭い関心事に特化したクラスにする

ここまではおそらく、ほぼ万人に受け入れられる、「当たり前のこと」ではないでしょうか。
うんうんそうだよね、と読める内容。

ところがここからじわりじわりと、人によっては「お!?」と思うような内容が書かれています。

値オブジェクト(Value Object)を用意する。基本データ型を使わない。

  • 数量を扱うために、Quantityクラスを作り、1以上100以下の様に制約も記述する。マイナスや非常に大きな値もの取りうるintをそのまま使わない
  • 電話番号を扱うのに、フォーマットのルールまで定めたTelephonNumberクラスを作る。Stringをそのまま使わない
  • 値オブジェクトを作ることで、業務の用語がプログラム中に現れるため、変更の際の調査が用意になる。『業務に関係するデータとロジックを閉じ込めておくことができる』
  • 値オブジェクトはImmutableに。1つの変数を異なる目的に使うような、変数の引き回しを防げる

そんないちいちクラスを作るなんてコード量が多くなるだけ… という意見が出てきそうなところです。
実際、私が今まで仕事で見てきたプログラムでは、ここまで徹底して値オブジェクトが作られているものは見たことがありませんでした。

コレクションオブジェクトを用意する。配列やコレクションを表に出さない。

  • ループなど、コレクションを扱うコードは複雑になりがち。プログラムのあちこちに散らばり始めると読みにくくなる
  • 専用のクラスに閉じ込める。例えば、Listを直接表に出さないで、Customersというクラスを作り、そのインスタンス変数としてListを持つ
  • Immutableにするため、インスタンス変数をそのままGetterで返さない。別のコレクションを作り直して返す
  • コレクションに対する処理(全要素を返すとか、追加するとか、特定の条件のもののみ返すとか)は全てクラス内にメソッドとして実装

確かに、Javaでは8以降Lambda式が導入され、コレクションに対する処理の記述力が高まりましたが、だからこそ(?)複雑なStreamによる、一見するとよくわからない処理がかえって増えたようにも感じていました。
この方法にすることで、強制的に各処理に名前をつけざるを得なくなるため、可読性は高まりそうです。

一方で、慣れないと、Customers→Listの構成が冗長に感じたり、
「一個のインスタンスだと思って蓋を開けたら実はリストだった。びっくりした。」
ということもありそうに感じました。

データとロジックを一緒に置く (第3章より)

この章の主張は

  • データとロジックを別のクラスに分けることがわかりにくさを生む
  • データと機能が分離していると…
    • 同じ業務ロジックがあちこちに重複して書かれる
    • どこに業務ロジックが書いてあるか見通しが悪くなる

という内容。

データとロジックはセットで。 という縛りを作ることで、自然にロジックが書かれる場所が定まり、どこに何が書いてあるのかわからなくなる事自体を防ぐ、という話です。

でも、Javaにおいて、データだけ持つデータクラス(=DTO、Entityクラス、JavaBeans、…)はよく見る手法…なのですが、

  • Javaオブジェクト指向であり、データクラスはふさわしくない
  • データクラスが広まったのは、Javaが業務サービスに導入された当時、COBOLやCなど手続き型言語の設計方法や開発方法が踏襲されたため
  • J2EEStrutsはこの流れで生み出されてしまった

と、なかなか衝撃的なことが。StrutsはともかくJ2EEまで否定されるともはや、「Javaらしさとはなにか」というのもよくわからなくなりますが(笑)

※ とはいえ、ここまではっきり言っていただいたところで、始めてStrutsにふれた時に
「俺の思ってるオブジェクト指向となんか違う…」
「Logicクラスって何??」
と感じた原因がわかったように思えます。

メソッドをロジックの置き場にする(=ロジックのないメソッド禁止)

  • getterのように単に値を返すメソッドはダメ。メソッドはもっと役に立つもので無くてはならない
  • もしgetterを見つけたら、getterを呼び出している側に注目。getした値を使って何かの「判断/加工/計算」をしているはず。その「何か」ごとデータを持つクラスに移動してみる

このようなリファクタリングを繰り返していくことで、徐々にロジックが「データを持つクラス」に集約され、ロジックが重複して実装されることがなくなる、としています。

なお本書の特徴として、はじめから上に挙げたような、完璧なオブジェクト指向で実装されることを要求していません。

実装当初はデータクラスや、ただのgetterを作るのは問題ない(そちらのほうが書きやすい場合がある)。一旦動くようになったあとで、このようなリファクタリングを繰り返していくことで、ソフトウェアの変更容易性を善くすることができる

と主張されています。

TDDと根底の考え方は一緒ですね。まず動かす。そしてリファクタリングする。

なお、TDDで一つ思ったのですが、はじめ、このようにクラスをまたいだリファクタリングを積極的に行う場合、
「『メソッドの振る舞いを記述したユニットテスト』は、テストそのものがリファクタリングの邪魔になるのでは?」
と、感じました。
しかし、もう一度考えてみると、

  • リファクタリング中に、ふるまいが壊されていないことが確認できる → 大きなメリット
  • ユニットテストが書かれている時点でメソッドは小さく、テストしやすいもののはず。概ね、そのメソッドがそのままデータのあるクラスに移動するだけなので、テストの修正量は小さい → 小さなデメリット

と、メリットがあったり、テストの修正が必要になるにしてもさほど大きな修正ではなさそう… ということに気づきました。

メソッドは必ずインスタンス変数を使う

インスタンス変数を使っていないメソッドはそのクラスのメソッドとして不適切。ロジックの置き場を再検討するべき。

これは先程の、「データとメソッドは同じクラスに置く」と逆のことをいっています。
例えばこのようなメソッドです。

BigDecimal total(BigDecimal unitPrice, BigDecimal quantity) {
  BigDecimal total = unitPrice.multiply(quantity);
  return total.setScale(0, ROUND_HALF_UP);
}

このメソッドは引数から全ての値を得ており、インスタンス変数を全く使っていないため、このクラスに存在している明確な理由がないのだそうです。

このような考え方はしたことがなかったので、衝撃的でした。

Web APIの作り方(第8章より)

ここまでは一貫して、

  • ロジックはデータの近くに置く
  • はじめから完璧なプログラムは書けない。徐々にリファクタリングして良い設計にしていく

ということが主張されてきました。

ということは、Web APIによってサービス間を連携する場合も、以下のような主張になる と思っていました。

  • データを使ったロジックはデータを提供する側のAPIに置く
  • APIを利用する側には極力ロジックを書かない

しかし、どうやらそう単純ではないようです。

例えば、データ上存在している誕生日から年齢を計算する といった、計算ロジックをどちらに置くか という問題について、

  • どちらに置くにしてもロジックを持つ側の負担が増える
  • ロジックをどちらのアプリケーションが管理すべきかで判断する

と書かれており、「データを持っている方に置くべき!」という論調ではありません。
それぞれのサービスを担当する人が違うことによって、一つのアプリケーション内で閉じた話とは、格段に難しさが増しているようです。


とはいえ、
例えば誕生日から年齢を計算する例の場合

  • 基本データ(ここでは生年月日)の形式や内容の変更が利用する側のコードに大きく影響する
  • 逆に、導出結果を渡すAPIでは、基本データの形式や内容に変更があっても利用する側への影響は少ない

とあります。

基本データを変更することになるのは普通、提供側の都合(あるいは他の利用者の都合)だと思うので、ロジックを提供側に閉じ込めておいたほうが修正が早く、またテストもしやすくなると、個人的には思います。
また、本書で一貫して述べられてきた、データとロジックを一緒にすることでロジックの分散を防ぐ、という内容に沿わせることを考えると、やはり、データを持っている側のサービスにロジックを書くほうが全体として適切な構成になるのではないでしょうか。

(逆にこれで統一しないのであれば、提供する側は徹底してデータしか提供せずロジックは持たない、というルールにするべきだと思います。
しかしこの場合、年齢が複数のサービスから使われる時に、ロジックの重複を避ける方法がないのです)


追記
著者の増田さんご本人からコメントいただきました!


ご本人がまとめられている書評一覧を発見したのでメモ。他の方の意見が参考になります。
たくさんの書評、ありがとうございます | システム設計日記

『一生、エンジニアで食っていこう』漆原茂さん 楽天テクノロジーカンファレンス2017 レポート #rakutentech

楽天テクノロジーカンファレンスで聞いた、漆原茂さんの『一生、エンジニアで食っていこう』というセッションのレポートです。

私的に刺さった話

0x30歳ころ 何歳でも技術で仕事したい!…と思った。

そのためには、自分自身の「進化」が大きな課題だった。
「昔はこれこれ項で苦労したんだぞ」的な「技術おじさん」にはなりたくなかった。

若返りながら進化できる唯一の生物を探したら……

一つだけ見つけた。ドラキュラ!(笑)

「若者のエキスを吸う」ために

・若いコミュニティに飛び込む
・若い人をメンターにつける

最先端に居続ける

外を知るために、イケてる人に会いに行く。

SNSで探してメッセージを送ったり、メールを送って直接話したり。
セミナーは話を聞くためではなく、偉い人と仲良くなるために行く。

会いに行くコツ
質問しに行かない。言いたいことを言いに行く。
ビジネスネタとLTを準備しよう!


イケてる人と繋がれると、その人達からの情報で技術トレンドが読める。
さらに技術は掛け算で進化する。イケてる人同士を繋げる!

私は思いました

良いエンジニアでいるためには… コミュニケーション、すごく大事じゃん!


いやわかってるんですよ。
でもね、“自分みたいな”、コミュニケーション苦手な人間にはほんとつらい………

と思いましたが、わざわざこういう場で話されるくらいだから、みんな少しだけ恥ずかしかったり辛かったりするんですよね。
自分だけじゃない。

なので、そのちょっとだけの心理的なハードルを超えることで、
楽しい楽しいエンジニアリングを仕事として続けられるんだと思います。


なので私も… 若い頃の苦労話おじさんにならないように(既に時々怪しい…)…

  • 若い人に学ぶ
    • そもそもそのために若いコミュニティに飛び込む
  • イケてる人に話しかける! イケてる人にこそプレゼンする!
  • どんどん自分からアウトプットする!


頑張ります!
「楽しい」は最強!!


追記
若い人に混ざっていく、というのは以前参加したこちらでも聞いた。
http://taichiw.hatenablog.com/entry/2015/01/29/230538
情熱プログラマには、一番下手くそになる、というのがある。
スゴイ人たちは自らそういう環境に行くし、本当に謙虚に話を聴かれる。
スゴイと思う。