はじめに
前置き
この記事は去年転職しバリバリのベンチャーで働き始めた、ようやく社会人3年目のエンジニアが。去年を振り返りつつ来年に向けて何を学んでいこうかという抱負をまとめようという主旨で執筆するものです。
既に経験豊富なエンジニアにとっては既知のものであったり、明らかな誤りであったりする情報が含まれていると思われますが、よろしければご指摘の程、お願いします。
執筆背景
- Scala
- マイクロサービス
- ドメイン駆動設計(DDD)
この記事のキーワードとして3つの技術的要素を列挙していますが、これらは新奇なものというよりは、十分な注目を集め思想としてはある程度枯れ始めている、あるいは十分に枯れているものかなと思います。
実は、これらのキーワードは私が転職を決めた際に、企業選びの取っ掛かりとして選択したキーワードで、ある文脈の中で自分が身につけたい技術や身を置きたい環境について語る上で実際に利用していたものなのです。
私としてはこの試みは自分の中で情報を整理していく上でそれなりに役に立ち、実際に転職後の業務に貢献してくれていると思っているので、この文脈をアウトプットしながら思うところを述べていきます。
題材について
列挙した3つのキーワードは纏めて扱われる事もそれなりにあると思いますが、それはなぜなのか疑問に思った事はありませんか?
それぞれの技術的要素はあくまでお互いを実現させるための要素で、必須になるものではありません。マイクロサービスという思想を実現するために選択する言語は Java でも Ruby でも Go でも良いですし、マイクロサービスの設計が DDD として成立していなければならない訳でもありません。当然、DDD という設計を実践するために Scala という選択が必然であるかというとそんな事もありません。
ですが開発プロセスの進化というより大きな枠組みからの要求がどう変遷を遂げてきたのかという視点からこれらの要素を見つめてみると、この3点セットにはある程度の必然性が感じられるように思います。
現在では開発プロセスにおいて思想として十分周知されつつある DevOps に向けて、せいぜいウォーターフォールやV字モデルでしか開発が語られていなかった時代から何が発見され要求されているのかを考えてみるとどうでしょうか。
Scala
Scala って何なの?
Scala について言及される時にとりあえず特徴としてあげられるのは以下のようなものでしょうか。
- Java系で既存ライブラリが利用しやすい
- Javaのインタフェースの代わりにあるTraitで多重継承だったり依存性の注入っぽい事が出来る
- オブジェクト指向でも関数型でも実装できる
- Option型でNullに対して安全
- Future型が非同期処理の記述に便利
私が実務で Scala を扱うようになり5ヶ月程が経とうとしていますが、確かにこれらはこのプログラム言語をそれなりに言い表していているように思います。では、なぜ Scala で書くのかという疑問に答える場合にこれらの特徴は十分な回答になるでしょうか。
なぜ Scala なのか!
なぜ Scala なのか、と言った場合その回答は 「副作用を抑制しつつ並列処理を簡単に記述できるから」 というのが、単に言語機能的な要素を上げるよりは近いはずです。
関数型言語において研究されてきたような副作用のない処理の記述方法がやはり実際のプロダクト開発でも重要なのではないかと注目され始めた背景があります。演算処理の高速化、マルチスレッド化により部分的なアルゴリズムでプロセスを効率化する事に限界を迎える、同時にオブジェクトの状態を管理しきる難易度が高まった事がその要因です。
オブジェクト指向の場合にメソッドのI/Oがあるオブジェクトの状態に依存して変化する事はままあることですが、開発者はそのメソッドが「いつ」「どのオブジェクトから」「どのような状態で」呼び出されるのかを把握し全てのパターンに対してテストをする必要があります。副作用のない「不変な」世界でプロセスを記述する事が出来れば、副作用がもたらす実行効率は得られないかもしれませんが、テスト対象からオブジェクトの状態による相互作用は切り離す事が可能で、状態に依存しない処理を大量に並列化する事が可能になります。
開発プロセス・開発ツールの進歩に伴いソフトウェア開発においてはテストコードを記述し、継続的インテグレーションの中で常にテストしながらアプリケーションを成長させていく事が要求されるようになりました。テスト駆動開発という開発プロセスの潮流に対して、 Scala は Java 系のオブジェクト指向で記述可能な言語でありながら、テスト対象を明確にする事で安全性を高め、仕様が担保されたプロセスを十分に並列化させる事でシステム全体のパフォーマンスに貢献できるでしょう。
マイクロサービス
マイクロサービスって何なの?
対義となるモノリシックな設計で構築された従来のシステムでは単一のサービスで構築するのが普通でしたが、これはモジュール間の依存関係の曖昧化・複雑化を防ぐ事が出来ず、部分的な機能の更新のためにもシステム全体をビルドし直す必要があり、開発者達を悩ませてきました。
単純に言ってしまえば、求められている機能の集合でサービスを分割しAPIによって疎結合に連携させる事でこの問題を解決しようとしたのがマイクロサービスという思想と言えるでしょう。
なぜマイクロサービスなのか!
モノリシックな設計と比較してサービス間の依存関係が疎結合になっているため、ざっくりと以下のようなメリットが得られます。
- サービス単位でデプロイ・スケールができる
- 改修の影響範囲をサービス外に及ぶか否かで容易に切り分けられる
- サービス毎に技術的要素の選定・導入ができる
もちろん単にサービスを分割してこのようなメリットを得ようという訳にはいきません。サービス間を疎にするという事は、どうしても重複して管理するようなデータをどのように扱う必要があるか明確にしなければなりません。あるサービスで入力された情報はいつ他の必要とするサービスに提供するべきでしょうか。APIで都度取得するのか、サービス毎にデータベースで管理するのか、そもそもどのサービスで管理すべきデータなのか。その回答はデータの性質や更新の要件によって異なるでしょうし、ある程度の方針を立てるにしろ見極めを行う必要があります。
マイクロサービスを実現・維持するためには依存関係を疎結合にしたなりのオーバーヘッドを抱える事にはなりますが、機能の更新・追加をより迅速に実施して商機を捕まえていきたいWebサービスなどを提供する場合には、デプロイの体制として継続的デリバリーを維持するという観点で貢献できるでしょう。
ドメイン駆動設計 (DDD)
DDD って何なの?
実態を十分に抽象化したモデルを作成し、実際に取り掛かるまでに深い洞察を得る事で最終的なアウトプットの妥当性を高め、効率化するという事は工学的に重要な事です。ソフトウェア開発においても様々なモデルの作成が試みられていて、 UML という統一規格が定められています。
モデル駆動開発(MDD) は開発過程におけるモデルの重要性に注目したソフトウェア開発手法の一つで、UML などを利用して記述された十分抽象化された設計と実装の対応が取れていれば、モデルの変更を実装に反映させる事やプラットフォーム毎にモデルを適正化させる事の自動化が可能になり生産性に寄与するだろうという考えのもと生み出されたものです。
DDD もモデルの重要性に注目したという点では同様ですが、その主眼が大きく異なります。DDD がモデルによって実現しようとするのは、システムが扱おうとしている問題領域 (ドメイン) を明らかにする事であり、それをサービスに関わる人間が同じ言葉で語れるようにする事で設計から実装まで一貫した表現を可能にする事です。
なぜ DDD なのか!
DDD ではモデルで問題領域 (ドメイン) を明らかにするために十分なツールが提供されています。その一つに「境界づけられたコンテキスト」という考え方があります。これはシステムをドメイン毎に切り分けるためのツールで、モデルがどの文脈によって語られるべきドメインによって語られるべきかを表す事ができます。同じモノでもそれを扱うコンテキストによってどのように捉えるべきか変化する事はままあります。例えば「商品」というデータを扱う場合、それを販売するという文脈と配送するという文脈では、保持しているべき属性や、関連付けられているべき他のモデルは異なっている事でしょう。 DDD ではこうしたモデルの違いを別の文脈に閉じ込める事で抽象度を高め、それぞれの文脈での課題を明らかにしていきます。
境界づけられたコンテキストを始めとして、 DDD には十分抽象化されたされたモデルによって
システムが扱う問題を実装から設計まで一貫した表現で語るためのツールや示唆がまとめられています。これにより実装と設計が切り離される事がなくなり、運用を考慮した洞察を反映する事が出来るようになります。
DevOps はリーンとアジャイルを文化的な背景に持っていて、ビジネスにおけるインクリメントを迅速な開発によって提供する事、ビジネスに対して適切な運用を行う事、運用におけるフィードバックを開発が過不足なくすくい上げる事が循環している事が重要になっているフレームワークです。そのためには運用・開発・ビジネスの三要素が同じ言葉で語られ、洞察が得られるようになっている事が重要で、よりスムーズで高速なプロダクトのインクリメントを可能にします。
おわりに
Scalaとかマイクロサービスとかドメイン駆動設計とかって結局何が嬉しいの?
つまるところ、それぞれの要素が進化してきた開発プロセスの要求に対して、単なる機能的な特徴に止まらない利点を持っていたから採用する価値があったのだというのが私の見解です。
テスト駆動開発が進歩しツールを利用した自動化によりより確実にパフォーマンスと品質を確保するために関数型のパラダイムで実装が可能な Scala に注目が集まりました。マイクロサービスは肥大化する現代のシステムに対する回答であり、アジャイル開発においてはインクリメントを継続的に反映させるための回答でもあります。ドメイン駆動設計では切り離されがちな開発とビジネスと運用というサービス展開の3要素を連続的に捉えるための知見を得られます。
マイクロサービスとドメイン駆動設計の間では相互の親和性も高く、サービスを実際にどのような単位で切り分け、実現していくかという点で重要な考察を得る事ができます。サービスを境界づけられたコンテキストで切り分けるというのは、設計時に文脈として異なると看做されているため自然に思えます。
DevOps という新たな開発プロセスの思想が広まり受け入れられていくまでの過程で、その有用性が見出されたのがこれらのキーワードなのではないでしょうか。
後書き
私が就職活動の場で語っていた事を要約すると、「技術を取り入れて進歩していく事の重要性について共感が得られる職場に入りたい」という事です。そのために利用していた文脈が開発プロセスの進化とScala、マイクロサービス、ドメイン駆動設計の関連でした。
当時あまり技術を取り入れ開発プロセスを更新する事に熱心とは言えず生産性と品質を高める事に興味が薄い (と私は感じていた) 現場で働いていたため、まず第一点として技術的な優位を取りに行く姿勢を転職先に求めていたわけです。学生時代に Scala とモデル駆動開発を扱っていた経験からマイクロサービスやドメイン駆動設計関連の勉強会に参加するようになり、そういった技術が実際にどのような現場で用いられているかを知りました。結果としてアドテク系の企業を中心にそれなりの数の企業を訪問し内定を頂きつつも、なんだかんだ技術に対する共感度が最も高いと感じたマーケティングツールのサービス展開を行う企業に参画させて頂いています。
そんな経緯もあって、業務のメインは Ruby on Rails なのですがチャンスがあれば Scala もと言っていた事で現在 Scala の実装箇所を任されています。仕事量はそれなりに重く日々頭を抱えながらこなしているところですが、働き方にもようやく適応し始めています。次なるステップとしては、自分自身の成長のため、学習のI/Oを増やしていくのが第一と思っておりますので、また別の記事でお会いできれば幸いです。
本当はもっとキャプションなりリンクなりをつけながらもっともらしく書きたかったのですが、普段なかなかアウトプットまで辿り着けていない身では思いの他時間がかかってしまいました。
ここまで読んで頂けた方には感謝の意を表明させて頂きます。