https://kotlinlang.org logo
#android-architecture
Title
# android-architecture
c

Cicero

01/16/2022, 5:20 PM
Hello people, I keep getting messages in arguments about project architecture like: "it's a matter of preference" and I often answer with ''it's a matter of engineering". I can't discuss opinions that are based on "liking things", I need arguments like "improves readability, testability, performance, organization". For me, There must be some explanation of why things are being done. Maybe I'm a bit obsessive here but this kin d of argument was use too often to sneak in things that this developers often can't even understand (the "is a matter of preference" answer comes here). Please shed light on my ignorance. This was the message I got when I questioned the use of interfaces in use cases:
Copy code
Hey Cicero,
Using interface is a matter of Clean Code Architecture, so yes we are using interfaces with UseCases. Please whenever you need to add a new one make sure that you do an interface for.
This project is intended to be big and continues project, so if we are going to support Unit test in future then we need to make sure that we can test each part separately.
The ViewModel is the only exception at the moment because Koin does not accept interfaces when we define the ViewModel. If we you know a way then please tell me to add interfaces to ViewModels.
So, I understand why I would use interfaces in repositories, right, mocking and what not, but aren't use cases supposed to represent business rules that will shape the information in your view? And aren't this business rules supposed to be prime to the functionality of your viewmodel? Also, what about adding interfaces everywhere when no code is tested or "it's going to be teste in the future"? This kind of discussion eat me inside last year.
j

Javier

01/16/2022, 5:45 PM
I prefer only using use cases and dont use repositories, so I havent this abstraction duplication
but I see a bit useless to have interfaces for repositories and use cases, you can pass fakes repos to the use cases
1
c

Cicero

01/16/2022, 6:30 PM
Exactly my explanation.
c

Colton Idle

01/17/2022, 4:43 AM
Architecture is the ultimate "it depends" response. to me, I almost don't care what architecture we use. I care that one is clearly defined so that if I submit a PR, no one can come back to me and say "uhm you did this "wrong""
ive worked at too many places where a "lead" just judges PRs based on this imaginary architecture written in there head. If the arch is written out, then I'll follow it. I might not agree with it, but for the love of god please write out your arch so you can't scold me in a review. "clean code" and "good architecture" and "best practice" are almost as useful of arguments as someone saying "for security reasons". 😂
k

K Merle

01/17/2022, 5:53 AM
I like to avoid fake objects just cause it gives a bit of overhead of maintenance if real object changes. I prefer mocks. As to interfaces, it sounds like a reviewer is blindly following clean code suggestions. If interface is not needed (architecturally or test wise) I don't add it just cause.
On the other hand, if you've arrived on a project that someone else developed, and they've followed this practice for some period of time, it's best to adapt imo.
c

Cicero

01/17/2022, 8:29 AM
They just started and the argument is that it's easier to mock the use cases than the repositories. And I don't see how this will be assertive in thr long run. The project is already covered with empty "will be tested in the future interfaces". And because this is supposed to be a long run project I, would like to avoid pitfalls like "mocking use cases" . If you need to mock a use case. In my perspective, this comes from a person that is not used to wrote tests in general, be ause ic you think about it, the probability you are going to test your UCs is high, that means you will already have everything setup to test your view models with mkst valid cases you would expect from your use cases. In casw you need a new data format, just add a different mocked data set. Right? The argument revolves around the possibility of multiple repositories, which is zomething that doesn't exist yet, but as if it's something that will increase the complexity of the apllication in a way that is easier "if we just mock the result of this 2 repos", where in my vew the output of this os much more in the are of creating opportunity for mistakes. Mocked data sources + use case vs mocked use cases
a

allan.conda

01/17/2022, 6:50 PM
I 'prefer' mocked data sources + use case. However it is a common argument that making a
ClassUnderTest(UseCase(FakeDataSource))
Is not a "Unit" test. You can check out SO discussions about it and there isn't really a complete agreement between software engineers. Also there was/is the trend of Unit test where all dependencies are mocked (even though mockito explicitly says to not mock everything) I think the problem is the focus on the labeling of whether it is unit test or not, more than focusing on writing valuable tests. In your case, I would do what would be consistent with the codebase, achieving consistency on the patterns is more important imo. For suggestions like these, I would be willing to discuss but applying your idea means your project needs a migration plan to apply it consistently throughout your codebase. Otherwise you'll get a mix of approaches and when it turns out your team unanimously decides to mock your use cases to write pure unit tests, your code with no interfaces just gets in the way. Controversial architecture topics like this will stay a 'matter of preference', because the topic is complex enough that there is no answer yet that the majority of the engineering community agrees on. In my case I'm on the opposite side of the table, where I'm the one trying to enforce the same idea as you, but others don't like it and try to argue against it. (I want Real UseCase with no interface.) The real challenge is making everyone follow the same thing even though they don't agree on everything. Tldr; Disagree and Commit
1
You did just mention you guys are just starting though. So I think there is room for discussion and decision. But I would follow whatever would be the team's decision.
👍 1
c

Cicero

01/17/2022, 8:39 PM
Let's forget the name “Use Cases” because it is indeed meaningless, a class that has written rules of how you are going to process the data that will be delivered to your UI is what we are looking for. This class will often hold weak implementations almost like a useless step in between a viewmodel and a repository. When I try to drop the “matter of preference” in favor of “matter of engineering” I try to argue that UseCases-> Data Transformation Classes are rules that should never be changed and will most probably be the first thing in pair with validators to be tested. On to that they will motivate you to write as much mocks as you can for this section of the code. Mocks being different structures of data that you and your team deem valid, being them examples from past occurrences that broke your app or just situations that are easily predicted like empty/null states and general cases given the models offered by the back end schema. Now after this, after designing the tests for your validators and use cases, it is hard to argue that you need to mock your uses cases because “it is easier” to compose data that might come from different repositories. “But what if my team wants to go backwards and test the view model first, they will argue that they need this simplified mocked use cases to make it work.” - That is most probable one of the scenarios, even then not a cool one, at least a rational one. So the counter argument here would be the waste of effort over mocking information that, in order to test the UseCases, you would need to mock anyway. Given that you mocked your repositories and the only source of data for your viewmodels are your use cases, you won’t need to mock this repositories any more so, for the sake of saving time you will be wasting your time. Worse, you will be overriding an implementation that should be canonic to how your data should be presented, creating more than one situation where an unexpected result might happen (mocking repos and use cases). Tldr; I don't believe in preferences when we are talking software architecture, "matter of preference" when talking architecture often comes from a place of ignorance. And designing architecture from a point of ignorance is dooming.
I will appreciate some light on my ignorance over preference when designing architectures without a serious backing motivation.
k

K Merle

01/18/2022, 6:28 AM
When I unit test a class my focus is only that single class. Does it behave as it should. It's almost like double book keeping, you have your real code and test code that does almost the same. This helps me in verifying that
single
class does what it's supposed to do, ensures that in the future, if I change anything in a real code accidentally, tests will tell. Also, it's like documenting your code. That being said, if I write use-case unit tests, I don't care about what repository does in his scope, as long as I can mock or fake data of repository, it's fine.
1
g

George Theocharis

01/19/2022, 8:17 PM
This is sound and good, but my experience says that is not the case in such tests. How do you test a use case with a mock repository? With verifying that the repo was called? Or do you stub a value on repo and check that the use case returns it? This actually mirrors the implementation details in tests and couples them together acting as an obstacle towards future refactoring.
k

K Merle

01/20/2022, 5:05 AM
I test with mocks. Not only if mock is called, but in what order, did it call when conditions met only, did it call with correct parameters. I wouldn't necessarily say that refactoring breaks mocks. I think that it breaks mocks where it should and you have to go back and fix the tests or your code. More then you'd like you'll find you actually broke the code. This is what the goal of tests are. Tight coupling with a code. That less tight coupling of fakes (cause your fake does not totally match real object possibly from the get-go or to many real object changes over time) could slip in the bug.
s

Sorin

01/20/2022, 11:55 AM
I think the matter of taste argument is just rubbish. As a guideline I would look into functional programming and the strive for immutability and purity.As long as that is followed I think in Android world at least the clear winners are MVI and redux uniflow architectures.
k

K Merle

01/20/2022, 12:00 PM
Each architecture has it pros and cons and we should be open to all. Only upside imo as for testability with MVI is that you can easier test your UI.
3 Views