nuits.jp blog

C#, Xamarin, WPFを中心に書いています。Microsoft MVP for Development Technologies。

Visual Studio 2019 Preview 16.4.0 Preview 2.0で.NET Core 3.0が削除される問題の対処方法

まだ未確認ですが、Visual Studio 2019 Previewの16.4.0 Preview 2.0を入れると、.NET Core 3.0が削除されるようです。

RuntimeだけなのかSDKもなのか、詳細は不明です。

これは明らかな不具合で解消する予定だそうです。

今は手動で改めて再インストールすると治るそうです。

手動ダウンロードはこちら。

dotnet.microsoft.com

Visual StudioでNuGetパッケージマネージャーコンソールが開けなくなった場合の対処方法

何もしてないのにVisual Studioのパッケージマネージャーコンソールが壊れました。(ちかって怪しい操作した記憶はありません)

次のようなエラーがでます。

f:id:nuitsjp:20191013194119p:plain

拡張型データ ファイル 、C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO\2019\PROFESSIONAL\COMMON7\IDE\COMMONEXTENSIONS\MICROSOFT\NUGET\Modules\NuGet\NuGet.Types.ps1xml: 次の検証例外のため、ファイルがスキップされました: ソフトウェアの制限のポリシー (グループ ポリシーを使用して作成されたポリシーなど) によって操作がブロックされているため、ファイル C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO\2019\PROFESSIONAL\COMMON7\IDE\COMMONEXTENSIONS\MICROSOFT\NUGET\Modules\NuGet\NuGet.Types.ps1xml は読み込めません。。 の読み込み中に次のエラーが発生しました。

探すとMSの証明書が信頼できない証明元として登録されているからだという情報を見つけました。

github.com

なのでIEのインターネットオプションから削除します。

f:id:nuitsjp:20191013194254p:plain

注意すべきは「certlm.msc」からではないということです。

SQL ServerのサンプルDB「AdventureWorks」のDockerイメージを公開しました

SQL Serverのサンプルデータベース「AdventureWorks」をDocker上のSQLサーバーで利用するためのコンテナイメージを公開しました。

cloud.docker.com

これを利用することでローカルにSQL Serverをインストールすることなく、AdventureWorksを利用することができ、クリーンな環境でデータベース接続アプリケーションの評価などに利用できます。

なおDocker初心者なのでDockerfileが本来はあまり良くないかもしれません。特にSQL Serverを明示的に停止していないあたり?ご指摘あればIssueたてて頂けると助かります。

https://github.com/nuitsjp/docker-adventureworks/blob/master/Dockerfile

続きを読む

開発ツールの自動構成スクリプトを公開して、変更案を募集してみる

以下に主にChocolateryを利用した開発環境の自動インストールスクリプトを公開してみました。

全部じゃないですけどね?恥ずかしいし・・・。

github.com

Chocolateyの概要と簡単な使い方はこちら。

www.nuits.jp

でせっかくなら、これ便利だよあれ入れなよ的な意見を募集してみたいと思います。GithubのIssuesに書いていただいたりPR頂けると嬉しいです。

ドシドシ投稿お待ちしております!(マサカリはソフトに投擲ください)

  • よく利用する開発対象は以下の通り
    • WPF
    • ASP.NET Core
    • .NET Core Console Application
    • .NET Core Windows Service
  • Azure・・・は趣味で触る程度
  • 基本はChocolateryで入れたい
  • でもVisual Studioなど無理がある場合は、別途できるだけCLIで入れたい

Chocolatreyによるインストール

install-choco.cmdを実行するとChocolateryをインストールし、chocolatery.configに設定しているアプリを一括でインストールします。多分。

CubePDFとCubePDF Utilityはハッシュが違うと怒られるけど、一応忘れないように書いておいてあります。

SSMSが英語で入ってしまうのが悩み。最新でもないし。

Visual Studio

インストーラーをダウンロードして「vs_professional.exe」にリネームする。

そのあとinstall-vs-pro.cmdを実行する

世界一わかりやすいClean Architecture

本項は「C# Tokyo オンライン「世界一わかりやすいClean Architecture」他」による発表の登壇原稿となります。過去に発表した.NET版の記事はこちらにアーカイブしています。

本稿のサンプルコード・PPTはこちらで公開しています。 「CC BY-SA 4.0」で公開していますので、気に入っていただけたら営利目的含め、ライセンスの範囲で自由に利用していただいて問題ありません。

github.com

また動画を以下で配信しています。よろしければご覧ください。


世界一わかりやすいClean Architecture

はじめに

まず初めに、クリーンアーキテクチャの誤解されがちな二つのことについてお話させていただきます。

その上で、クリーンアーキテクチャの本質とは何か?押さえておくべき、本当に重要だと考えている三つの事について、お話しします。

注意事項

さて本題に入る前に、少し注意事項があります。

今回お話しするのは、あくまで私の解釈です。

特に極端に要約しているので、今日お話しすることがすべてではないことはご理解ください。また明確に書籍に書かれているわけではないですが、拡大気味に解釈している箇所もありますし、書籍の記載とやや異なる説明もします。

それでも私は著者が本当に言いたかったこと、クリーンアーキテクチャでもっとも大切なことは今日お話しする三点にあると考えています。

なお異論・反論は大歓迎です。ぜひ議論させていただけると嬉しいです。

誤解されがちな二つのこと

この図をご覧になったことのある方は多いんじゃないかと思います。

f:id:nuitsjp:20200403155744j:plain

実はこの図が良くできてい過ぎることが、大きな誤解を招く要因になっていると私は考えています。

この図の何がそんなに誤解を生んでいるのでしょうか?

f:id:nuitsjp:20200403155756j:plain

ひとつは、この図は決してソフトウェアの関心をControllerやUseCase、Entityに分離しろという意味でもなく、レイヤーをこの4つに分割しろという意味ではないということです。

f:id:nuitsjp:20200403155803j:plain

そしてふたつ目は右下のこれです。

これはデータや処理の流れを一方通行にしろという意味ではないですし、Presentationを古典的なMVCのように設計しろと言っている訳でもありません。

では、どういう意味でしょうか?

f:id:nuitsjp:20200403155816j:plain

この図で本当に大切なことは、依存性は外から中だけに向かっていなくてはいけない。

というたった一点にあります。

でもじゃぁ、例えばEntitiesの状態が変わったことで、UIを受動的に変化させたい。みたいな、中から外を呼ばなければいけないときはどうすれば良いの?という疑問が、すぐに湧いてきますよね?

f:id:nuitsjp:20200403155823j:plain

右下の図は、内側の変化に応じて外側を呼び出したい場合に、依存性は外から中に向けたまま、処理の流れとして中から外に戻すにはどうすればよいのか?

を例示しているものです。

そんなこと言っても、本当にあってるのか?って、今皆さん思いましたよね?

はい。もちろん根拠あっての話です。

そもそも著者は書籍の冒頭でこう明言しています。

f:id:nuitsjp:20200403155839j:plain

「アーキテクチャのルールはどれも同じである!」

日本語版では帯にも書かれていますよね。

f:id:nuitsjp:20200403155844j:plain

つまり、本当にすべてのソフトウェアが同一のアーキテクチャに帰結するとすれば

  • レイヤーが4つ限定であったり
  • UIがMVC的でMVVMなどを否定していたり
  • そもそもWeb限定だったり
  • 中から外の呼び出しがApplicationレイヤーとInterface Adapterレイヤーの間だけで発生する

なんて分けないですよね?

レイヤー数が4つで有る必要性がない事は、書籍にも明確に記載されています。

f:id:nuitsjp:20200403155850j:plain

書籍を読めば、ちゃんと先の図があくまで例示であると書かれています。

もともとクリーンアーキテクチャの発表前は、ヘキサゴナルアーキテクチャとかオニオンアーキテクチャが広く共有されていました。そしてそれらのアーキテクチャには類似の共通点があることも知られていました。

f:id:nuitsjp:20200403155858j:plain

クリーンアーキテクチャの解説は、それらの著名なアーキテクチャは、先ほどの図のように記述することで単一のアイディアに統合することを例示するために書かれた図なんです。

そう

f:id:nuitsjp:20200403155904j:plain

クリーンアーキテクチャというのは、どんなソフトウェアにも適用可能な普遍的なアーキテクチャです。

誤解を恐れず言えば、クリーンアーキテクチャを採用しないという選択肢は、「基本的には」無いといって差し支えありません。

おさえるべき三つのこと

では先の図のように実装することがクリーンアーキテクチャではないとしたら、クリーンアーキテクチャについて何を抑えたらよいのでしょうか?

私はつぎの三つこそ、本質的に重要なことだと考えています。

f:id:nuitsjp:20200403155935j:plain

ひとつめは先ほども話しました。

ソフトウェアは、より上位レベルの方針にのみ依存せよということ。

ふたつ目は、ひとつめを実現するために、依存性を制御の流れから分離してコントロールする必要があるということ

そして最後に、「上位レベル」とは相対的かつ再帰的であることに留意する必要がある。ということです。

さあ具体例を見てみよう!

てことで、ここからは具体例を見ながら解説したいと思います。

具体例はAndroidのアプリケーションを例にお話ししますが、まずはサンプルアプリケーションを開発することになった背景からお話ししましょう。

これは大切な意味があることです。

f:id:nuitsjp:20200403155947j:plain

あるところに、田中さんという方がいました。田中さんは技術営業をしている方です。

田中さんはホットペッパーというサービスが大好きで、忙しいさなか、新しく訪れた場所で、新しいお店と出会うことが一つの生きがいです。

田中さんは、ホットペッパーが大好きなんですが、一つだけ不満があります。

それは、毎日必ず同じ条件で検索するのですが、都度明示的に検索するということ自体を面倒だと感じているということです。

そこで田中さんは、自分用のホットペッパー検索アプリを開発しようと考えました。

f:id:nuitsjp:20200403160010j:plain

アプリケーションはリクルートさんのWebサービスを利用させてもらい、大好きなホットペッパーの情報を閲覧できるように作ります。

アプリは起動するとダイレクトに周辺の店舗情報を検索して一覧表示します。

そのさい、お昼の時間帯であれば自動的にランチ営業のある店舗だけを表示します。

こういったアプリケーションを、まずは伝統的なレイヤーアーキテクチャで作成し、その問題点を解説した上で、クリーンアーキテクチャを適用していく。

という流れでお話したいと思います。

Layered Architecture

f:id:nuitsjp:20200403160025j:plain

全体は大きく、Presentation・Usecase・Infrastructureの三つに分割されています。

Infrastructureには、外部のWebサービスを利用するApi、位置情報を利用するlocation、時間を利用するtimeコンポーネントが含まれています。

f:id:nuitsjp:20200403160031j:plain

それぞれのコンポーネントにはこちらのようなクラスが含まれていて

f:id:nuitsjp:20200403160036j:plain

こんな感じで動作します。

まずViewModelからusecaseのfindが呼び出されます。

UsecaseはDeviceLocationProviderを利用して、現在の位置情報を取得し、続いてTimeProviderから現在時刻を取得します。

そしてGourmetSearchApiを呼び出して、周辺のレストラン情報を取得します。

一見、そんなに悪くないように見えますよね。しかし実際には大きな問題を含んでいます。

では一体、何が悪いのでしょうか?

f:id:nuitsjp:20200403160057j:plain

それは安定度と柔軟性のバランス配分です。

f:id:nuitsjp:20200403160103j:plain

このレイヤーモデルでは、柔軟性と安定度は、こちらの図のような配分になっています。

usecaseとinfrastructureの柔軟性と安定度の配分に問題があります。なぜこのような配分になるのか?

それを理解するためには、依存関係による安定度と柔軟性のトレードオフを理解する必要があります。

f:id:nuitsjp:20200403160115j:plain

依存関係にあるオブジェクトがあったとします。

オブジェクトはクラスでもいいですし、コンポーネントでもいいですし、なんならサブシステムでも構いません。

それぞれを変更することを考えてみると、理解できます。

f:id:nuitsjp:20200403160123j:plain

まずは依存される側を変更することを考えてみましょう。依存される側を変更すると、

f:id:nuitsjp:20200403160134j:plain

依存する側は、何らかの影響を受けます。

従って、依存する側は、依存される側より安定度が低くなります。自明の理ですよね。

逆に

f:id:nuitsjp:20200403160140j:plain

依存する側を変更しても

f:id:nuitsjp:20200403160151j:plain

依存される側には影響を与えず、依存先を考慮せず、自由に変更できることから、依存する側の柔軟性は、相対的に高くなります。

f:id:nuitsjp:20200403160156j:plain

そうです。

依存関係にあるオブジェクトの間の安定度と柔軟性は、どうしてもトレードオフの関係が発生します。

さて、これを逆説的に考えると

f:id:nuitsjp:20200403160210j:plain

変更頻度の高いオブジェクトは、依存する側として、関係性を設計すべきですし

f:id:nuitsjp:20200403160216j:plain

アプリケーションの本質的な価値を提供する「上位レベル」のオブジェクトは、軽微な変更の影響を受けないよう、依存される側として設計すべきです。

先ほどのモデルを振り返ってみましょう。

f:id:nuitsjp:20200403160229j:plain

全体として依存の方向は、上から下へと統一されています。

ではこれらのうち、どこの変更頻度が高く、どこが本質的な価値を提供するのでしょうか?

f:id:nuitsjp:20200403160242j:plain

最も変更頻度が高いのは、一般論としてUIですよね。したがってpresentationレイヤーの変更頻度が高くなります。そのため、上流に位置し、柔軟性が高くなっています。

これは適切な設計と言えるでしょう。

では、アプリケーションの本質的な価値は何でしょうか?

それは、これが開発されることになった背景に立ち戻ればはっきりします。

f:id:nuitsjp:20200403160256j:plain

これら、アプリケーションを開発する目的そのものが、このアプリケーションの本質的な価値となるでしょう。

f:id:nuitsjp:20200403160310j:plain

そしてその価値を提供しているのはusecaseレイヤーです。

ビジネスロジックやドメインと言い換えても良いと思います。

f:id:nuitsjp:20200403160320j:plain

したがってusecaseレイヤーは、ほかの枝葉の変更に引きずられてはならず、高い安定度となるように設計されなくてはなりません。

しかし、そうなっていない点に、このモデルは問題点があります。

依存性は、より上位レベルの方針にのみ向けよ

依存性は、より本質的な価値を提供する部分。

つまり、より上位レベルの方針に向ける必要があるのです。

f:id:nuitsjp:20200403160352j:plain

具体的には、依存関係をこのようになるよう設計する必要があります。

でもそれは実現可能なのでしょうか?

制御の向きはどうしても上から下にならざるを得ないなか、それと反する依存方向に設計する必要があります。

つまり、制御の流れと依存関係を分離する必要があるのです。

制御の流れと依存関係の分離

f:id:nuitsjp:20200403160403j:plain

一般的に依存方向は制御の流れに引っ張られがちです。

しかし、これらは分離してコントロールすることが可能です。

f:id:nuitsjp:20200403160416j:plain

そのためには二つの依存関係の間のコントラクト、つまり契約・仕様・お約束を文脈によって制御する必要があります。

まず、抽象的なコントラクトを導出することで、それぞれの具象概念をどちらも抽象概念であるコントラクトに依存させます。

そしてこのコントラクトを、どちらの文脈で定義するかによって具象概念間の依存関係をコントロールします。

f:id:nuitsjp:20200403160424j:plain

具体的には、コントラクトをサーバー側の文脈で規定したとします。

すると、文脈単位でみると、クライアントがサーバーに依存している構造になりますし

f:id:nuitsjp:20200403160430j:plain

逆にクライアントの文脈で規定すれば、サーバーがクライアントへ依存している構造となります。

f:id:nuitsjp:20200403160436j:plain

つまり依存性逆転の原則を適用するということです。

具体例に戻りましょう。

f:id:nuitsjp:20200403160448j:plain

全てを見ると、ちょっと分かりにくいので今回はusecaseとapiの関係に着目してみます。

f:id:nuitsjp:20200403160503j:plain

これらのクラスのうち、ここの依存関係にフォーカスします。

f:id:nuitsjp:20200403160515j:plain

具体的にはusecaseがWebサービスを利用するための呼び出しです。

f:id:nuitsjp:20200403160520j:plain

ここを拡大してみると、usecaseがapiコンポーネントのインターフェースと、そのシグニチャに登場するクラスに依存しているのが見て取れます。

f:id:nuitsjp:20200403160535j:plain

これら、APIのインターフェースと、そのシグニチャに登場するクラス群がレイヤーをつなぐコントラクトです。

この構造には二つの問題があります。

ひとつ コントラクトがapi側に定義されている 

ひとつめは、コントラクトがapi側に定義されていることです。

f:id:nuitsjp:20200403160547j:plain

まずはこれらをusecase側に移動します。

でも、これだけでは不十分です。

ふたつめ コントラクトがWeb APIの文脈で記述されている

二つ目の問題点は、このコントラクトがWebサービスの文脈で記述されているということです。

f:id:nuitsjp:20200403160600j:plain

ホットペッパーのAPIを呼び出すと、このようなJSONが返却されます。

GourmetSearchApiの戻り値となるクラスは、このJSONの形状のままです。

実際の実装コードを見てみましょう。

f:id:nuitsjp:20200403160619j:plain

Usecaseの関数内で、APIの戻り値を、usecaseのオブジェクトに詰めなおしています。

つまりusecaseがWebサービスに依存してしまっているのです。

ではどうすれば、よいでしょうか?

f:id:nuitsjp:20200403160637j:plain

現在、usecaseとinfrastructureの間のコントラクトは、Infrastructureの文脈で記述されています。

このコントラクトをusecaseの文脈で再定義します。

f:id:nuitsjp:20200403160643j:plain

つまり、ここの依存関係を断ち切ります。

f:id:nuitsjp:20200403160650j:plain

そのためには、JSON依存のオブジェクトをinfrastructureへ隠蔽し、GourmetSearchApiのインターフェースはusecaseの文脈で記述しなおします。

f:id:nuitsjp:20200403160703j:plain

こうします。

少し見にくいですが、GourmetSearchApiの戻り値がGourmetSearchResultからRestaurantに変更されているのが見て取れるかと思います。

そしてJSONオブジェクトからusecaseのオブジェクトへの詰め替えはInfrastructureに実装します。

こうすることで、論理的な依存の方向が下から上に変化します

f:id:nuitsjp:20200403160709j:plain

その結果、制御の流れと依存関係を分離することができ、柔軟性と安定度を任意のバランスにコントロールすることができました。

そして、これを同心円状に並べなおすと・・・

f:id:nuitsjp:20200403160715j:plain

あら不思議。

どこかで見たようなモデルになりましたね。

f:id:nuitsjp:20200403160723j:plain

というわけで、依存性は上位レベルの方針のみに向ける必要があり、そのためには、制御の流れと依存方向を分離、コントロールしなくてはならないということに、共感いただけたのではないかと思います。

視点を上げてみよう

さて、usecaseからAPIへの依存は取り除けました。

ここで視点をアプリケーションとWebサービスの関係まで上げてみましょう。

f:id:nuitsjp:20200403160739j:plain

UsecaseからWebサービスへの依存は取り除けましたが、よく見ると、そもそもアプリケーション全体がWebサービスに依存してしまっています。

これは良いのでしょうか?

結論から言うと

f:id:nuitsjp:20200403160745j:plain

f:id:nuitsjp:20200403160753j:plain

このアプリケーションは、田中さんが愛してやまないホットペッパーを、より便利に利用するために作ったものです。

つまり、ホットペッパーに依存すること自体が最上位レベルの方針なのです。

f:id:nuitsjp:20200403160805j:plain

今回の場合、アプリケーションはWebサービスのインターフェースです。

本質的な価値つまり上位レベルの方針は、Webサービス側にあります。

つまり、アプリケーションはWebサービスに依存して良い。結果、apiコンポーネントもWebサービスに依存して良いことになります。

もちろんこのことは、アプリケーション側に腐敗防止層を設けることを否定するものではありません。

f:id:nuitsjp:20200403160812j:plain

もう一度、先ほどのアプリケーション構造のモデルに戻りましょう。

f:id:nuitsjp:20200403160816j:plain

ここから視点を上げると

f:id:nuitsjp:20200403160826j:plain

ソリューションの構造としては、このように図示することができますよね。

ちなみにこの関係が、常に正しいという訳ではありません。

適切な関係性は背景によって変化します。

f:id:nuitsjp:20200403160839j:plain

今回は、ホットペッパーを便利に利用するアプリケーションが欲しい!

という背景から端を発したので、アプリケーションが外部のWebサービスに依存して問題がありませんが

f:id:nuitsjp:20200403160846j:plain

旅行サイトの横断検索サービスのようにいろんな飲食店検索サービスを横断検索したい!という背景にが起点となっているなら、このように、飲食店横断検索アプリが、中央に来ないといけません。

f:id:nuitsjp:20200403160852j:plain

これまで存在しなかったような、新しい飲食店情報サービスを始めたい!しかもWebも含めたマルチプラットフォームでというのであれば、他社サービスに依存してはいけませんし、中央には飲食店情報サービスがきて、各プラットフォームのアプリケーションが周辺に来るはずです

でも、どの例の、どのプラットフォームでもアプリケーションは

f:id:nuitsjp:20200403160908j:plain

同じような構造になる可能性が高いでよね?

そうです。

「上位レベル」というのは相対的かつ再帰的であり、それに留意する必要があるということです。

f:id:nuitsjp:20200403160921j:plain

そもそもソフトウェアは良くフラクタルのようだと言われていますよね。

クラスとクラスがまとまってコンポーネントとなり、コンポーネントとコンポーネントがまとまってサブシステムになります。

そしてサブシステムとサブシステムがまとまってシステムになります。

ここではクラス・コンポーネント・サブシステム・システムを、ソフトウェア オブジェクトと呼ぶことにします。

ソフトウェアオブジェクトのすべてにおいて、ここまでした話の内容は適用できます。

もちろんサブシステム間は例えばWeb APIになったりするでしょうけど、どの要素間であっても、コントラクトの文脈を管理する事で、制御の流れと依存関係は制御することが可能です。

f:id:nuitsjp:20200403160928j:plain

こちらに各ソフトウェアオブジェクトごとの代表的なコントラクトを上げてみました。

なんならシステム間でのやり取りがCSVとか固定長テキストであっても、そのファイルがどっちのシステムの文脈によってるかによって、システム間の依存関係はコントロールできるわけです。

f:id:nuitsjp:20200403160933j:plain

「アーキテクチャのルールはどれも同じである」

という真意が何となく伝わってきたのではないでしょうか?

What is Software Architecture?

さて、ここまではどちらかというと、ボトムアップ的なアプローチで説明してきました。

ここからは少し、トップダウン的なアプローチでお話してみたいと思います。

f:id:nuitsjp:20200403160946j:plain

なおここからはクリーンアーキテクチャの書籍に書かれてる内容だったり世間の共通見解だったりするわけではなく、私個人の私見が多くなります。

私はそう考えてるというお話であることにご注意ください。

さて、そもそもアーキテクチャ、ここではソフトウェアアーキテクチャですね。

ソフトウェアアーキテクチャとは何なんでしょうか?

f:id:nuitsjp:20200403160953j:plain

Webや書籍上でよく見かける、ソフトウェア アーキテクチャというとたとえばこのあたりが該当するように思います。

これらは類型的なソフトウェアアーキテクチャのパターン群です。

ただし特定領域のパターンであって、ソフトウェアアーキテクチャの全てではありません。

では、ソフトウェアアーキテクチャとは何か?ドン!

f:id:nuitsjp:20200403160959j:plain

うん、良く分からん。

別の意見を見てみましょう。

f:id:nuitsjp:20200403161005j:plain

多分、世界的なアーキテクトの第一人者を10人上げろと言われると、多くの方がそのうちの一人として、マーティン ファウラー氏をあげるのではないかと思います。

彼はこう言っています。

ふむ。

ちなみにWikipediaには、こんなことが書かれています。

f:id:nuitsjp:20200403161013j:plain

そう、厳密で共通認識の定義は存在しないんですね。

みんな気軽にアーキテクチャ・アーキテクトと言いますが定義はあいまいなんです。

とは言え、おおよその共通認識はもちろんあります。

f:id:nuitsjp:20200403161024j:plain

まず、ソフトウェアアーキテクチャとはシステムアーキテクチャのうち、ソフトウェア領域のアーキテクチャを指します。

f:id:nuitsjp:20200403161030j:plain

そしてソフトウェアアーキテクチャとは、ソフトウェア構築における重要な決定事項の全てを指します。 その中でもどう分割し、どう結合・相互作用するかが、特に重要です。

f:id:nuitsjp:20200403161036j:plain

またソフトウェアアーキテクチャとを構築すする目的とは

  • システムの実現をサポートする
  • 持続可能なソフトウェアを
  • バランス良く構築する為

だと、私は考えています。

最後のバランスとは、QCDだと私は考えています。 特にアーキテクチャは非機能要求からも、おおきな影響をうける傾向が強いと言われています。

Clean Architectureを考えるうえで重要なポイント

さて、アーキテクチャが仮に先のようなものだとしたとき、Clean Architectureを考える上で重要なポイントがあります。

f:id:nuitsjp:20200403161049j:plain

それはこのどう分割・結合し、どう相互作用させるか?

という点です。

f:id:nuitsjp:20200403161055j:plain

そして、これらを実現するために最も重要となる、ソフトウェアアーキテクチャ3種の神器があります。

それが

f:id:nuitsjp:20200403161104j:plain

関心の分離、疎結合、依存性逆転の原則だと、私は考えています。

整理してみましょう。

f:id:nuitsjp:20200403161150j:plain

なんらかの大きな目的を表す上位の関心があったとします。

この時、現代のソフトウェア開発の現場では、これをそのまま、モノリシックなソフトウェアとして開発したりしませんよね?

まずは粒度の小さい、個別の関心に分離します。

これが関心の分離です。

このとき関心が何か?は、このとき皆さんに見えているスコープによって異なります。

上位の関心がソリューションであれば、サブシステムかもしれませんし、上位の関心がコンポーネントであれば、クラスかもしれません。

ただ実際にはこんな単純に分離できない事もあると思っていて、例えばソリューションはユースケースに分離されるかもしれません。

これはどちらが正しいという訳ではなくて、サブシステムとビジネスユースケースはお互いに影響を与え、双方が矛盾しないよう並行で決定する必要があるのかもしれません。

ちょっとこの辺は、私の中でも完全には消化できていないとこがあります。

さて、分離した関心は、それ単独では上位の関心を満たせません。

そのため、関心は再度結合する必要があります。そこで重要なのが疎結合ですよね。

せっかく関心を分離しても、密結合してしまってはありがたみが半減してしまいます。

ただ、本当の意味での疎結合を実現するためにはもう一つの概念が必要です。

そう。依存性逆転の原則です。

ここまでお付き合いいただいた皆さんは、もうご理解されていることでしょう。

結合は疎であるだけではなく、その結合時の依存関係を適切にコントロールすることで、より効果が高まります。

そのためには、制御の流れにとらわれず、依存方向を分離し、設計する必要があります。

そうすることで、上位の安定度と、下位の柔軟性を高めます。

What is Clean Architecture?

f:id:nuitsjp:20200403161157j:plain

ではクリーンアーキテクチャとはなんでしょう?

私は次のように解釈しています。

f:id:nuitsjp:20200403161203j:plain

クリーンアーキテクチャというのは、ソフトウェアアーキテクチャの3種の神器を適用した、リファレンスアーキテクチャのひとつだと私は解釈しています。

Clean Architectureって不可能では?

さて、最後に、ネット上などでよく見かけるClean Architectureに対する疑問について お話したいと思います。

書籍には次のような記述があります。

f:id:nuitsjp:20200403161214j:plain

要約すると、システムは外部のフレームワークなどに依存せず、サークルの外側に配置しよう。

フレームワークやデータベースなどの開発環境やツールの意思決定を遅らせられるよう、それらに依存しないように設計しよう。

という内容です。

f:id:nuitsjp:20200403161228j:plain

しかし、現実的に例えばUIフレームワークやライブラリに非依存に設計することは無理もしくは無意味なんじゃないか?

データベースに依存せずGatewayを実装するなんて可能なのか?

という意見を見かけます。

f:id:nuitsjp:20200403161234j:plain

例えば今回のサンプルアプリケーションではviewはGoogleが提供しているCardViewに依存しています。

これはNGなのでしょうか?

私は一定条件を満たせば問題ないと考えています。

f:id:nuitsjp:20200403161241j:plain

具体的には、次のような「上位レベルの決断」の上であれば問題ないと考えています。

そもそも自作するよりサードパーティーライブラリを利用したほうが生産性も品質も高くなると判断でき、そのライブラリの変更が緩やかで、十分に後方互換が考慮されていて、そのライブラリの変化をアプリケーション側で十分に許容できると判断しているような場合に、Presentation内に限定して利用を許可する。

といった場合です。

そもそもAndroidアプリケーションを開発しようという際に、AndroidというプラットフォームやKotlinというプログラミング言語、Android StudioやGradleのような開発環境に依存しないというのはナンセンスですよね。

f:id:nuitsjp:20200403161254j:plain

アーキテクチャや設計をどこまで抽象化するか、どこから具象化するかは程度の問題だと思います。

フレームワークなどの決定を遅らせることは、アプリケーション開発に自由度をもたらしますが、同時にイニシャルコストの増加や開発期間の延長を招きがちです。

早い段階で、特定の具体的なフレームワークなどを受け入れる決定をすることで、コストや開発期間の、圧縮や、品質の向上を図ることも当然検討すべきです。

そしてこれら自身を、アーキテクチャ上の「上位の方針」として受容するのは十分にありだと考えています。

Clean Architecture原理主義になる必要もありませんが、同時にAnti Clean Architectureになる必要もないのではないでしょうか?

まとめ

とうわけで、今日のお話は終わりになります。

最後に簡単にまとめましょう。

クリーンアーキテクチャは、どんなソフトウェアにも適用可能な普遍的なアーキテクチャです

f:id:nuitsjp:20200403161313j:plain

クリーンアーキテクチャは3種の神器を適用した、リファレンスアーキテクチャのひとつです。

f:id:nuitsjp:20200403161319j:plain

ソフトウェアアーキテクチャ3種の神器とは、関心の分離・疎結合・依存性逆転の原則だと、私は考えています。

f:id:nuitsjp:20200403161336j:plain

クリーンアーキテクチャの本当に大切なことが三つあると私は考えています。

ひとつは、依存性はより上位レベルの方針、つまりオニオンアーキテクチャであれば外から中にだけ依存するべきであること

ふたつめは、制御の流れと依存方向は分離してコントロールしなさいということ。

そして最後に、上位レベルというのは、相対的・再帰的なものであるということです。

f:id:nuitsjp:20200403161342j:plain

参考の図のとおりに関心を分離することや、データや処理の流れを一方通行にせよ、ということがクリーンアーキテクチャではありません。

と、著者がなんと言おうと、この解釈だからこそクリーンアーキテクチャには価値がありますし

f:id:nuitsjp:20200403161348j:plain

この書籍は、そのための手段を広く紹介している、名著だと私は信じています。

というわけで

f:id:nuitsjp:20200403161400j:plain

みなさん

「クリーンアーキテクチャチョットデキル」

ようになりましたね?

はじめてのChocolatey

LinuxやmacOSではそれぞれapt-getやhomebrewのようなパッケージマネージャーが提供されており、開発ツールのインストールなどはコマンドラインから行うのが一般的です。

対してWindowsではGUIから行われることが多いのですが、GUIからの操作は環境構築の再現性を保つのが難しい(もしくはドキュメントを用意するなど手間がかかる)といった側面があります。

そこで今回紹介するChocolateyです。

Chocolateyを利用することでWindowsでもコマンドラインからのパッケージインストールが可能となり、大量のソフトウェアの導入を自動化することが可能となります。Visual StudioやGit、.NETなどの導入も自動化できます(の、ようです)。

本稿でははChocolatey自身の導入と、Node.jsを実際に導入する方法を詳解します。

続きを読む