アイデアや仕組みを知ることでモチベーションをキープする

数年前の話になりますが、チーム開発実践入門 という書籍で、開発フローの一例として GitHub Flow が紹介されています。この書籍では GitHub Flow が次のように解説されています。

  • master は常にデプロイ可能である
  • 開発する際は master からブランチを作る
  • master に作成したブランチの Pull Request を送る
  • 作成したブランチが master にマージされたらすぐに本番環境にデプロイされる

GitHub Flow が世に出てきたのは2011年頃で、当初はこのフローだったのだろうと思いますが、GitHub のブログでは次のように書かれています。

The basic workflow goes like this:
・Push changes to a branch
・Wait for the build to pass on our CI server
・Tell Hubot to deploy it
・Verify that the changes work and fix any problems that come up
・Merge the branch into master

Deploying at GitHub - The GitHub Blog

このブログが公開されたのは2012年です。GitHub の中のひとたちは割と早い段階でフローを変えていたようです。もしかしたら、今はさらに変わってたりして...。ちなみに、チーム開発実践入門が出版されたのは2014年です。同様に GitHub実践入門 も同時期。

今ではそれほど不思議ではないかもですが、feature ブランチをデプロイして問題なく動作していることを確認してから master にマージする、というところが個人的にはなかなか衝撃的で、GitHub の思想や達成したい目的に合っていて、なおかつ master を安全に保つという課題をシンプルに解決しているところに感銘を受けたものです。

まとめ

たまたまこのツイートを見かけた際、このあたりのことを思い出して考えてみたんですが、自分の場合、誰かをメンターにしたりキャリアモデルを参考にしたりということがあまりなくて、どちらかと言うと、上記のような画期的なアイデアだったり、ある課題を解決するための目から鱗が落ちるような仕組みに影響を受ける傾向にある気がします。

いろいろ情報収集して自分のモチベーションに繋げたいと思う今日この頃です。

How to Think About HTTP Status Codes

2年ほど前の記事になりますが、HTTP ステータスコードについて解説している記事を、勉強を兼ねて翻訳してみました。ところどころ自信がないので間違いなどあればご指摘いただけますと幸いです。

原文はこちら。
mnot’s blog: How to Think About HTTP Status Codes


HTTP ステータスコードには少なからず混乱や戸惑いを感じることがある。私は長年に亘ってストレスを抱えた開発者から次のような相談を受けている。

409400 のどちらを使うべきでしょうか?または 500 がいいでしょうか?私の同僚はどんなときにでも 200 を使おうとしているし、向かいの席のひとは新しいステータスコードを定義しようとしています。

HTTP ステータスコードのことやその使い方について掘り下げてみましょう。

Two Levels of Meaning

HTTP ステータスコードは構造化されている。1桁目はレスポンスの種類を示し、他2桁はそのレスポンスを具体的にどのように処理するかを示す。定義済みのレスポンスの種類は次の通り。

例えば、201 Created2xxステータスコードで、成功したレスポンスを示す。01 は、リクエストによって Location ヘッダーに指定されたURLにあるリソースが作成されたことを示す。

同様に、409 Conflict4xxステータスコードで、サーバーの処理によるものではなく、リクエストに問題があることを意味する。4xx09 は、リクエストがサーバーの状態と競合していることをクライアントに伝えており、再度リクエストを送信する前に競合を解決する必要がある。

1桁目の数字はそれ自身が意味を持っているため、ステータスコードの受け取り側はそれを調べてレスポンスの意味を理解できるが、どのように処理するべきかは明確ではない。これにより、新しく定義されたステータスコードを一般的に処理できるように適切に格下げすることができる(きちんと設計されていれば)。(※)
(※訳注: 適切に汎化できるという意図だと思われる)

Generic Semantics

ステータスコードは、すべての HTTP リソースに適用される可能性があると定義されていることを理解することも重要である。私たちは 汎用的なセマンティクス (※) と呼んでいる(まさに HTTP メソッドと同様に)。
(※訳注: この訳が相応しいかどうかちょっと自信がない...)

これを知ることは混乱の原因を明らかにする。アプリケーション固有のセマンティクスを汎用的なセマンティクスにマッピングすることは困難であり、間違えやすいやり方である。アプリケーションを一連のステータスコードに「一致させる」ことは苦労を招くだけである。これはやってはいけない。

/foo リソースの 200 OKウィジェットが昇順に並んでいることを意味する」とか「ウィジェット404 Not Foundウィジェットが逆順であることを意味する」ということを述べようとしている仕様を見かけることは残念ながらよくあることである。これは、実際のところステータスコードのセマンティクスを再定義することである(汎用的ということを思い出して)。それによって、事実上、HTTP のプライベートバージョンを作成することになり、コードに悪い影響を及ぼす可能性がある(もともとそういう決まりがないのであれば)。

また、すべてのリソースと生成可能なステータスコードを一覧表示しようとする HTTP の API を見てきた。これはいい取り組みではあるが、悪いプラクティスである。クライアントが受け取るかもしれない一連のステータスコードは、彼らが把握しているひと握りの一覧より遥かに多いものである。これは、プロキシが設定されているかもしれないし、サーバーが 421 Misdirected Request429 Too Many Requests500 Internal Server Error を返す可能性があるためである。

代わりに、アプリケーションはメソッドやリソースの表現の観点からリソースの振る舞いを定義するべきである。例えば、

リンク形式で識別される foo のリソースは、application/foo+jsonapplication/bar といったフォーマットで表現でき、application/foo+json で PUT したり、application/json-patch+json で PATCH することでその状態を更新できる。

受け取るステータスコードは、すでに定義されており、広く知られている。一覧化したり、改良する必要はない。

POST のセマンティクスは特に汎用的であるため、特別なケースを示す。次に述べることは理にかなっている。

ウィジェットを並べるには、リンク形式で識別される foo リソースに application/example で POST し、成功時は Successful のステータスコード (2xx) で示される。

2xx 系のステータスコードは、成功を示すものとして使われることに留意する。それによって、将来のステータスコードとの前方互換性を保つことができる。

場合によっては、POST が固有のステータスコードを返すことを説明する必要があるかもしれない。例えば、新しいリソースを作成するために使われた場合、リソースの場所を示す Location ヘッダーとともに 201 Created を使う。あるいは、POST (または PUT) の処理がサーバーの状態と競合する可能性がある場合、409 Conflict を使う。ただし、これらはよくあることではない。

そして、もちろん、仕様には多くのサンプルを含めるべきである。

Specific Effects

これまでに述べたように、ステータスコードはレスポンスの具体的な作用を明らかにする。

例えば、301 Moved Permanently はリソースが移動したことをクライアントに伝えており、必要に応じて新しいリクエストで作ることができる。401 Unauthorized は HTTP の request authentication (※) の仕組みを使うきっかけになる。429 Too Many Requests はリクエスト数の上限であるため、落ち着くまでリクエストを止めることをクライアントに伝えている。
(※訳注: 日本語訳は こちら)

粗末な 404 Not Found であっても固有の処理がある。キャッシュがいわゆる「ネガティブキャッシュ」として機能することで(すなわち、ヒューリスティックな期限を割り当てられたもの)、Web クローラーのような自動的なエージェントは、リソースがすでに存在しないことを示すシグナルとしてそれを使用する。

これらの具体的な作用は、上記で述べた汎用的なセマンティクスに一致する。これは一般的な HTTP のソフトウェアによって処理されるためである。つまり、これらはアプリケーションに固有のものではなく、汎用的な HTTP スタック、例えば、キャッシュやクライアント、仲介者、場合によっては Web スパイダーによるものである。リソースのさまざな状態に関する情報が担うことは(「ここにある」「ここにはない」「向こうにある」とか)、それらが受け取るものとほぼ同じくらいアプリケーション固有のことである。(※)
(※訳注: このあたりの訳は自信がない...)

これらは、どの HTTP ステータスコードを使うか検討する際に考慮するべきことであり、アプリケーション固有のセマンティクスにどのようにマッピングするかということではない。特に、レスポンスの意図された処理が既存のステータスコードと同じ場合は、それを使うこと。

いくつかのステータスコードは、通常、HTTP レイヤーで自動的に処理されない。例えば、アプリケーションでリクエストが受け付けられたが、まだ処理はされてないことを示すために 202 Accepted を使うのであれば、それをドキュメントに記載した方がよい。

ここでも、固有の作用 (ステータスコード以外でリクエストが成功したかどうかを判断する必要があること) がすでに定義されているため、ステータスコードのセマンティクスを再定義する必要はない。代わりに以下を参照。

まして、それぞれのアプリケーションを HTTP ステータスコードに「深く」マッピングしようとすることは間違いであり、ほとんどの場合において、その粒度ははるかに粗い。疑わしい場合、適切なものがなければ、汎用的なステータスコードとして 200 OK400 Bad Request500 Internal Service Error を使っても問題ない。

Refining the Semantics of a Status Code

アプリケーション固有のセマンティクスは body に含めるのが適切である。ほとんどの場合において、使われるステータスコードを指定する必要はなく、「成功レスポンス」ということだけでおそらく十分である。HTTP ヘッダーを作成することもできるが、ここでは言及しない。

エラー (4xx5xx) の場合、自身で作成したくない場合は これらのフォーマット を使うことができる。

これに対する例外は、既存のステータスコードを利用する汎用的な HTTP の拡張機能を構築している場合である。例えば、新しい認証方式など。その場合、ステータスコードの仕様に記載されていることや、使おうとしている既存のヘッダーに留意する。これらは互換性を保つ必要がある。例えば、「511 Network Authentication Required というレスポンスの Location ヘッダーが意味するものは…」と書いてあっても、511 の仕様を更新しない限りこれは機能しない。

So You Want To Create a HTTP Status Code

これまで述べてきたことをすべて読んだ上で、それでも新しいステータスコードが必要であると思うのであれば、それはすべてのリソースに適用できる可能性があり、HTTP の実装に明らかな効果がある。既存のステータスコードで同様な効果があるものはない。そして、手続きを進める意思があるなら、これらの ガイドライン を読んでください。

gitbook-plugin-uml プラグインが更新されました

GitBook で UML を使う場合、gitbook-plugin-uml プラグインを使いますが、昨年頃からこのプラグインをインストールする際に以下のエラーが発生していました。

Error: node-plantuml@0.6.2 postinstall: node scripts/get-plantuml-jar.js

で、少し前に issue を立てたんですが、先日、ようやく npm パッケージの更新版が公開されました。現時点ではこのエラーは発生しないはず。

Please update npm package · Issue #12 · vowstar/gitbook-plugin-uml · GitHub

その他

以前公開した GitBook Tutorialワークアラウンドの手順を記載しています。今はもう不要になりましたが、ひとまずは注記を付けた上でそのまま残します。

GitBook Tutorial についてはこちら。

kntmr.hatenablog.com

突撃!!隣のアーキテクチャに行ってきた #totsugekita

突撃!!隣のアーキテクチャに行ってきました。簡単に所感をまとめます。

totsugeki-architecture.connpass.com

所感

ちょっと予習不足なところもあって若干理解できてないところもありましたが、他のひとがどのようなことを考えてアーキテクチャ設計しているのかを聴けてとても勉強になりました。わりとリアルな現場の話が聴けてよかったです。

ユビキタス言語がブレた場合、どういう過程を経てコードまで落とし込むんだろうか。アジャイル的に細かいサイクルで変更を取り込んでいく感じなのかな。

あと、自分の周りではわりと機能単位でパッケージを切ってるケースが多い印象だけど、レイヤごとにパッケージを切るのがよさそう。たぶん、これが Clean Architecture というものだと思われる。要勉強。

以下、メモから抜粋。

SUGARのアーキテクチャ - SUGAR

  • イメージは Clean Architecture
    • View > Adapter > Application > Domain
    • 内側のものだけ利用できる
    • Infrastructure は他から利用されるもの
  • 同じ存在でもサーバー/クライアントで呼び方が違うことがある☆
  • Application
    • 必要な Domain 層の実装を組み合わせて意味のある単位にまとめる役割
    • DI された Domain 層の実装を組み合わせて何かしら意味のある処理にする実装を置く
  • Adapter
    • Domain 層の実装を置く
    • json の相互変換はここでやる
  • View
    • Entity や VO をそのまま json にして返すことは少ない
    • APIごとに必要なものだけ詰め替える

CQRS+ES(再)入門 - Chatwork

  • Chatwork のバックエンドは CQRS+ES
  • 伝統的なアプローチ
  • データ指向からコマンド指向に
    • クライアントからコマンドを送信する
    • コマンドによって意図が明白なIFを作る
    • 命令の文脈を表したコマンドをモデルとする☆
  • コマンドとクエリの要件は違う☆
  • クエリサイド
    • クライアントが表示するために必要なDTOを返す
    • ドメインオブジェクトが不要 (DTOへの変換が不要)
    • SQLを発行するDAOを使う
  • コマンドサイド
    • ドメインオブジェクトは内部状態を外部に晒す必要がない
    • コマンドの処理以外に必要なクエリメソッドは持たない
  • ドメインイベント (コマンドとクエリの結合)
    • 過去に発生したできごと
    • イベントがわかればコマンドがわかる
  • Event Sourcing
    • イベントはイミュータブルな歴史を表す
    • ドメインイベントの追加はロック不要
    • パーティショニング (集約IDで書き込みを分散できる)
    • イベント列から最新の状態を得る
  • イベント列が大量にある場合は時間がかかる
    • スナップショットを持たせる

AbemaTV iOS Architecture - AbemaTV

  • Presentation Domain Separation
  • MVVM + Flux
    • Flux は Store が大量のロジックを持ちがち
  • ViewModel
    • グローバルで状態を持つ必要がない場合は ViewModel を使う
    • Flux を小さくする方針
    • ライフライクルが明確で管理がラク (View のライフサイクルに依存する)
    • メッセージングがリレーだらけになる
  • Unio☆
    • 自由度が高く実装がバラバラになりがちな ViewModel を矯正する

Mirrativ Androidアプリの取り組み

  • ユビキタス言語がブレる
    • 開発当初から呼び方が変わる
  • Android Architecture Components
  • パッケージ構造
    • 機能単位からレイヤー単位に
    • 将来的には機能ごとにサブモジュール化する

DIライブラリ Airframeを使ってみた

GoでのAPI開発現場のアーキテクチャ実装事例

  • Layeredish Architecture☆
  • パッケージ構成☆
  • Domain に repository のインタフェースを置く
  • Infrastructure に repository インタフェースの実装を置く
    • 技術的実装☆
  • Application は制御の役割を担う
  • 各レイヤのインタフェースを実装したテストダブルを作成して使う

ElmでSPA State設計

  • ドメインごとに Store (状態) を持たないようにした
    • ページごとに (URLごとに) 状態を持たせる
  • 共通ロジックがビジネスロジックを指すなら状態管理とは切り離した方がよい?☆
  • Elm は状態の構造やフローが宣言的に書ける

仕事をする上で意識していること

普段、仕事をする上でどんなことを意識しているかなぁという話になりまして。まぁ仕事に限った話ではないけれども。

で、個人的に最初に思い浮かぶのは「Simple」と「Easy」かなと思う。「Simple」は仕組みや構造が単純であること。「Easy」は使いやすくてハマりどころがないこと。

じゃあ、シンプルで簡単に使えることを目指しているのかというとそうとは言えない。これら2つは両立できるとは限らないから。

そのときに自分たちが何を求められているかを見極めるのが大事なのかもしれない。

Simple であることを保つために使いやすさを犠牲にすることがある。運用でカバーとかまさにそれの結果だと思う。ただし、それだけでヨシッとするのではなく、使う側が困らないような仕組み (ドキュメントとか) を準備する。もちろん、それに辿り着きやすくすることも大事。使うときにアクセスできなかったらどうしようもないので。

一方、Easy なものを提供するために内部の構造が複雑になることがある。ただし、使う側にこの複雑さを意識させてはいけない。複雑さを局所に留めて外部に露出させてはいけないことが大事。

その他

他にも「手段を目的にしない」とか。で、前にこんなものを書いてたことを思い出した。

kntmr.hatenablog.com

VSCode で Markdown 編集中にインデントサイズが変わる

普段、Markdown を書くときに VSCode を使っています。

VSCode では、Tab はスペースを挿入する設定にしており、サイズは 2 にしています。

"editor.insertSpaces": true,
"editor.tabSize": 2

基本的には、Tab を押すとスペースが2個入ってインデントされるのですが、これが何かのタイミングでスペースが4個入るようになることがあります。

で、VSCode の設定を見てみたらこんな項目が。

// Controls whether `editor.tabSize#` and `#editor.insertSpaces` will be automatically detected when a file is opened based on the file contents.
"editor.detectIndentation": true

別タブで何かしらの拡張子のファイルを開いたときに自動検出?して Markdown のファイルにも影響したのかも?たぶん。

というわけでこれを無効にします。今のところこれで大丈夫そう。

"editor.detectIndentation": false

現場からは以上です。

オブジェクト指向プログラミングと関数型プログラミングを対立的に考えない

少し前のものですが、こちらの記事がとてもおもしろかったです。

employment.en-japan.com

一部抜粋します。

オブジェクト指向プログラミングと関数型プログラミングは対立するものではなく直交する(直接関係がないため、自由に組み合わせられる)ものである

去年、この記事を読んだとき、この部分がイマイチ理解できてなかったのですが、最近、なんとなく理解できてきたような気がします。たぶん。というか、次のように考えてみると腑に落ちるような感じがします。

オブジェクト指向」は設計やプログラミングの 手法や指針のひとつ であり、「関数型」はプログラミング言語特徴 である。

「手法」や「指針」はいわゆるガイドラインみたいなものだろうし、「特徴」はそのものが持つ仕様みたいなものだと思っています。そう考えると、これらを対立的に考えたり、そもそも同じ土俵で比較すること自体があまり意味をなさないように思えます。

余談

あと、対立的な話としてたまに見かけるのが、例えば、「jQuery から xxx への移行」みたいな話。(xxx には JS フレームワークの名前が入る)

これらのフレームワークは、アプリケーションを構造化したり、ボイラープレートを隠蔽したりするための仕組みであり、jQuery は、DOM を操作するためのユーティリティであると思っています。「アプリケーションから jQuery の記述を駆逐して xxx に載せ替える」というのは、考え方がちょっと偏り過ぎというか、なんとなく手段が目的になっているようにも感じます。当然、適材適所はありますが、これらは共存できるわけです。

ものごとを対立的に考えすぎるあまり、本来あるべき姿と乖離しそうだなと思った次第です。