Service Locator と DI どちらを使うか、という話。

Service Locator とは?

Create a service locator that contains references to the services and that encapsulates the logic that locates them. In your classes, use the service locator to obtain service instances

サービスへの参照を含み、それらを見つけるロジックをカプセル化するサービスロケーターを作成します。 クラスからは、サービスロケータを使用してサービスインスタンスを取得します。

The Service Locator Pattern | Microsoft Docs

どちらがどうなのか?

The choice between Service Locator and Dependency Injection is less important than the principle of separating service configuration from the use of services within an application.

Service Locator と Dependency Injection のどちらを選択するかは、アプリケーション内でサービスの設定とそれの利用を分離するという原則よりも重要ではありません。

Inversion of Control Containers and the Dependency Injection pattern

Service location is not an anti-pattern. There are anti-patterns that involve use of a service locator along with other similar constructs. There are anti patterns that involve the use of DI. Most devises we use in programming involve both (virtuous) patterns, and anti-patterns, which is really just a grand way of saying pros and cons. Generally speaking people who summarise the world in terms of only pros or only cons are said to be engaging in splitting.

Service Locator 自体はアンチパターンではありません。 他の要素と共に Service Locator を使用するときにアンチパターンが存在します。 DI を利用する場合にもアンチパターンがあります。 私たちがプログラミングで使用するほとんどの案は、良いパターンと悪いパターンの両方を含みます。 一般的に言えば、長所のみまたは短所のみの観点から要約する人々は、分割に従事していると言われています。

Splitting (also called black and white thinking or all-or-nothing thinking) is the failure in a person’s thinking to bring together both positive and negative qualities of the self and others into a cohesive, realistic whole. It is a common defense mechanism used by many people. The individual tends to think in extremes (i.e., an individual’s actions and motivations are all good or all bad with no middle ground.)

分割(白黒思考またはオールオアナッシング思考とも呼ばれます)は、自己と他者の肯定的な面と否定的な面の両方の性質をまとまりのある現実的な全体にまとめることができないことです。 それは多くの人々によって使用されている一般的な防御メカニズムです。 個人は極端に考える傾向があります(すなわち、個人の行動や動機はすべて悪い、またはすべてが悪いこともありません)。

I need to take a look about and see what discussions there may be on the subject of polarised views and whether they are more prevalent among programmers than other professions.

私は偏極的な見解に関してどのような議論ができるのか、またそれらについて議論します。 他の職業よりもプログラマーの間で流行しています。

Service locator vs dependency injection. | Weird Scenes Inside The Goldmine

Dependency injection is all the rage now on Android but there are also some other patterns worth considering for managing dependencies. A Service Locator is a very simple pattern which can be implemented in few lines (50?) of code and can sometimes be a viable alternative or complement to DI frameworks like Dagger 2.

依存性注入は現在Android上で大流行していますが、依存性を管理するために考慮する価値のある他のパターンもいくつかあります。 Service Locatorは、ほんの数行(50?)のコードで実装できる非常に単純なパターンであり、Dagger 2のようなDIフレームワークに代わる実行可能な代替手段である場合もあります。

The Service Locator is considered by some (or many) as an anti-pattern, but I would argue that you always have to choose the right tool for the job (and it’s good to have a variety of tools in your toolbox). In some cases the Service Locator can be an extremely simple and efficient solution. It can also get handy in case you have constraints like APK size, method count, build speed or overall complexity.

Service Locatorは、一部(または多数)によってアンチパターンと見なされていますが、仕事に適したツールを常に選択する必要があると思います(ツールボックスにさまざまなツールを用意しておくことをお勧めします)。 場合によっては、Service Locatorは非常に単純で効率的なソリューションになります。 APKサイズ、メソッド数、ビルド速度、全体的な複雑さなどの制約がある場合にも便利です。

Service Locator pattern in Android - INLOOPX - Medium

‘Dependency Injection’ is only one form of the D in the SOLID design principles, ie. Dependency Inversion. I do highly recommend Dependency Inversion in any application that has a need to interact with dynamic data, or that has any level of business logic. Both Service Locator and Dependency Injection can be an anti-pattern or a viable pattern depending on the scenario.

「依存性注入」は、SOLID設計原則におけるDの1つの形式にすぎません。 依存関係の反転 動的データとやり取りする必要があるアプリケーション、またはあらゆるレベルのビジネスロジックを持つアプリケーションでは、Dependency Inversionを強くお勧めします。 シナリオに応じて、Service LocatorとDependency Injectionの両方をアンチパターンまたは実行可能パターンにすることができます。

Dependency Injection is over Hyped – Candor Developer

まとめ

「Service Locator」は、「シンプルなDI」てなイメージでいようと思います。

しかし、Dagger2を使うほうが後々便利なのかもしれません。

👉 Service Locator is an Anti-Pattern 


Android Paging Library と Retrofit

例えば、このパターン、Network only。

ここでは、PositionalDataSource を拡張するが、他のタイプのDataSource拡張でも同じ。

compositeDisposable のように viewModelScope をはるばる持ってきたにもかかわらず、


class RemoteDataSource(
  private val coroutineScope: CoroutineScope,
  private val service: RemoteService,
  private val s: String
) : PositionalDataSource<Item>() {

  @ExperimentalCoroutinesApi
  override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback<Item>) {
    Timber.d("RemoteDataSource#loadInitial: ${Thread.currentThread().name}")
    ...

loadInitial() 内は、メインスレッドではなく、別スレッドで実行されている。


Timber.d("RemoteDataSource#loadInitial: ${Thread.currentThread().name}")


D/RemoteDataSource: RemoteDataSource#loadInitial: arch_disk_io_0
D/RemoteDataSource: RemoteDataSource#loadInitial: arch_disk_io_1
D/RemoteDataSource: RemoteDataSource#loadInitial: arch_disk_io_3

これらは、Android Architecture Component が作成した独自スレッド。

よって、同期なRetrofitの実行処理で良い、となる。

If I use enqueue with Retrofit 2.3 it will doesn't work but if i do a .execute() the LiveData is correctly triggered

Retrofit 2.3で、enqueue() を使用しても機能しませんが、execute() を実行するとLiveDataが正しくトリガーされます。

Android Paging Library LiveData> is triggered before the end of the api call

公式リファレンスにも記述はあるという。

To display data from a backend server, use the synchronous version of the Retrofit API to load information into your own custom DataSource object.

バックエンドサーバーからのデータを表示するには、同期バージョンのRetrofit APIを使用して、独自のカスタムDataSourceオブジェクトに情報をロードします。

Network only - Paging library overview

しかし、DiffUtilを使ったリフレッシュなアニメーションが実行されない。

「手間がかかる」でなく「沼にハマる」ことが最近は多くなった。

APIの仕様がおせっかいすぎやしないか。

しきいを下げようとして、余計に混乱させるばかり。

👉 あなたは Android Architecture Component をどう思いますか? 
👉 Fragment と Toolbar の歴史の話 - Qiita 


あなたは Android Architecture Component をどう思いますか?

ある人々のTwitter上の会話。ザクッと翻訳サービスを利用して眺めてみます。

Frankly, the expectation is that all applications of a considerable size already use some form of DI. Thus providing yet another way to pass dependencies via context is an overkill. All "non-DI" facilities are just gimmicks/workarounds for cases when there is no DI.

率直に言って、かなりの数のアプリケーションがすでにDIを使用している。したがって、コンテキストを介して依存関係を渡すためのさらに別の方法を提供するのはやり過ぎです。すべての「非DI機能」は、DIがない場合のギミック/回避策にすぎません。

On Android this sadly isn't the case. We seem to relish in bad architecture.

It's either "Why do I have to pass an executor/scheduler/dispatcher? So much boilerplate!" or "Why can't I test on the JVM? This library is poorly designed!"

Maybe KEEP-87 will save us from ourselves?

Androidでは、これは悲しいことではありません。悪いアーキテクチャーで大喜びしているようです。

「executor / scheduler / dispatcher を渡す必要があるのはなぜですか? かなりのボイラープレートです。」、「なぜJVMでテストできないのですか?このライブラリは適切に設計されていません。」

多分KEEP-87は私達を私達自身から救うのだろうか?

👉 [Kotlin] KEEP87 brings compiler-driven dependency injection without frameworks : androiddev 

On unrelated note. (disclaimer: I'm not an Android developer) I have a feeling that something is broken in testing or architecture approaches here. I've been writing huge (1M+ LOCs) UI apps for more than a decade and never had to use either DI or statics to make them testable.

無関係なメモについて。 (免責事項:私はAndroidの開発者ではありません)何かがここでテストやアーキテクチャのアプローチで壊れていると感じています。私は10年以上にわたって巨大な(1M + LOC)UIアプリを書いてきました。そしてそれらをテストするために DI や statics を使う必要は決してありませんでした。

Android never had architecture guidelines and the docs encouraged doing all the wrong things to make the tutorials easy. Basically equivalent to writing everything in main(). Even now almost all of the architecture offerings treat symptoms of this legacy and not the disease.

Androidはアーキテクチャのガイドラインがなかったので、チュートリアルを簡単にするためにすべての間違ったことをすることをドキュメントを奨めてきました。基本的にmain() ですべてを書くのと同じです。現在でも、ほとんどのアーキテクチャがこの遺産の症状を治療していて、疾患を治療していません。

👉 Roman Elizarov on Twitter: "@JakeWharton Frankly, the expectation is that all applications of a considerable size already use some form of DI. Thus providing yet another way to pass dependencies via context is an overkill. All "non-DI" facilities are just gimmicks/workarounds for cases when there is no DI." / Twitter 

みなさんはどう思っていますか?

Roman Elizarov
@relizarov
Team Lead @JetBrains, working on @Kotlin coroutines and libs, sports programming/ICPC, concurrency & algorithms, math/quantitative finance; formerly @Devexperts

👉 Roman Elizarov (@relizarov) / Twitter 

Jake Wharton
@JakeWharton
Opinions expressed here are my own, not those of my company. They made me write this because I complain about Inbox going away so much.

👉 Jake Wharton (@JakeWharton) / Twitter