個人事業主になったので真面目にアウトプットしてみるブログ

フリーで顧客の会社に潜り込んでAndroidアプリつくって、とりあえず食っていけるようにアウトプットを増やしていくブログです。

Clean Architectureについてメモ

Clean Architecture(以下CA)と
https://github.com/googlesamples/android-architecture
ここに書いてあるブランチのMVP-cleanの実装とはわりと別物。

前者はドメイン層とその外側の境界をちゃんと意識した実装を主張しているのに対して、後者は説明ではCAについてのリンクを貼っているけど、内容はMVPにUseCaseをつけてコマンダーパターンにしただけ。後者は設計の知見が少ないと、簡単にドメイン層に外側の事情が持ち込まれるし、複雑なアプリではかえって冗長性が度を過ぎる場合が多い。UseCaseをつかってRepository(DataSource)にアクセスしてーってところについてはコードの一貫性が心地よい。 そこだけじゃ?

class GetItem extends UseCase<Param, Response> {
    private final ItemRepository repos;
    GetItem(ItemRepository repos) { this.repos = repos; }
    @Override void execute(Callback callback, Param param) {
      Item item = repos.find(param.id);
      item.update(param.value);
      repos.save(item);
      callback.onSuccess(new Response());
    }
}

Googleのサンプルだけを見てうまくできるのはまずCAもちゃんと知っているけど、CAだとファイルが多くなりすぎるから、MVPとDIPを取り入れてみるだけでとどめたいって感じの人なんじゃないかなーと思うと、チームでこれをうまくやるには割とハードルが高い。
あとそのまま低機能なUseCaseHandlerを使うなら、多少学習コストがあがっても枯れているRxJava使った方がいい。 (自分はUseCaseHandlerをキャンセルしこめるようにしたり、Handlerの制御を変えたりと、低機能なやつを改造する方をやったw) ガチでやりたいならCAをちゃんと理解してレイヤーごとにModule化して強制的にDIPなコードにする勇気が必要。
その上でファイルがーって話ならKotlinでやればなんとなく気楽に書けそう。

CAとDDD

DDDの本質はドメインのロジックが、リーダブルでありストラテジックに組みあがっていることを目指すもの。
けどGUIなアプリでは単純にコレクション(DataSource)の出し入れのコードになるので、DDDは結局のところ、Bounded Contextとか戦略的なDDDを適用するで終わってあとはひたすら似たようなことを繰り返すことになる。
特に何かお金や時間みたいな抽象性を利用したライブラリをつくるってわけでもなければ、コード自体は期待したストラテジックには組みあがらない。
CAはドメイン層とその外側との境界を守る方法でDDDとは相性は悪くない。

DDDのストラテジックな表現ってあんまりやるケースがないけど、単純にファイルをクラウドに上げるって感じだと

Content content = MyFileSystem.of(path);
StoreResponse res = Cloud.store(content);
println("rest:" + withByteStr(res.restSize) + " amount:" + withByteStr(res.total))
//とか
ContentList list = MyFileSystem.getNews();
StoreResponse res = Cloud.store(list);
//さすがにフィードバックがないとあれなので
ContentList list = MyFileSystem.getNews();
Cloud.store(list, callBack);

クラウドに上げたファイルをダウンロードって感じだと

Content content = Cloud.getContent(id);
/*
 * パスが指定されていないのは、限定されたパスの直下に配置するという意味で。
 * さらにたとえばキャッシュパスを指定するならMyFileSystem.saveAsCache(content)になる。
 * staticである必要はない。DIをするならなおさらのことstaticではだめだ。ここではあえてDDDとして簡潔なスタイルをとった例として書いている。
 */ 
MyFileSystem.save(content); 
// とか
ContentList list = Cloud.getContentList(groupId, callBack);
MyFileSystem.saveAll(list, callBack2);

GUI関係ない感じだとこんな感じでもいいのかなって。

命名がアレなのはデフォルト。

これをストラテジックな実装の参考にするくらいなら、たしかエリック・エバンス氏が取り上げていた

Eric Evans氏の基調講演より - ドメイン駆動設計を実践するには

ライブラリとしてJoda-Timeや

Joda-Time - Home

氏の書いたライブラリのTimeAndMoneyを参考にした方がいい。

GitHub - neuhalje/TimeAndMoney: Time and Money Code Library

こっちは氏のライブラリ。SourceForgeにあったコードを有志のかたがサルベージしたもの。