Denis Brandi
2 min readMay 19, 2021

--

Hi Callum, thanks for reading the article!

1) If you put @ViewModelScoped in the use case you are coupling the use case with the DI scope, therefore you can't inject your use case in another use case with a different DI scope (Singleton for example).

Also importing DI annotations in every file adds extra compile time for the file and will make migrations to other frameworks very slow and hard (Dagger itself keeps changing, so even if you keep Dagger but migrate to let's say Dagger 3.0 I won't be surprised if there will be breaking changes!).

2) Without Interface you can't mock without a mocking framework, you may not care but by using mocking frameworks: you add extra dependencies which you may have to replace, you make your tests slower and you have troubles mocking final classes (Mockito now allows you to mock final classes if you are in `test` but still cannot mock a class that is inside `androidTest`)

3) You have transitive dependencies (slower compilation time), which is one of the problems the DIP principle along with the ISP are trying to solve.

Example 1:

MyViewModel has MyUseCase as collaborator, which is a concrete class.

MyUseCase has MyRepository which is an interface.

MyViewModel transitively imports MyRepository and hence any change to one of the repository methods will recompile both MyUseCase and MyViewModel.

If MyUseCase needs other use cases or other repositories you add up possible recompilations.

Example 2:

MyViewModel has MyUseCase as collaborator, which is an interface this time.

MyUseCaseImpl has MyRepository which is an interface.

MyViewModel depends only on MyUseCase and will recompile only when the interface changes, changes to MyUseCaseImpl will never affect MyViewModel and so changes to MyRepository.

Also other than recompilations you have the case of a clean build. In example 1 MyViewModel has to wait for the compilation of more components than in example 2 where it can compile in parallel with some of those components (let's say MyUseCaseImpl and MyRepositoryImpl).

I do agree that interfaces add boilerplate in use cases, you may want to have a look at how I avoid them using functions and typealiases here (https://medium.com/swlh/functional-use-cases-f896f92e768f).

Hope this helps.

--

--