Dagger - What does 'Separate "do" from the "how"' means? - android

I've been watching Jake's slides about Dagger. At the page #29, he said 'Separate "do" from the "how"'. What specifically does that mean? And what are the benefits of it?
https://speakerdeck.com/jakewharton/android-testing?slide=29

If I had to expand the sentence it would be: "The code that needs to 'do' an action should not need to know 'how' that action is fulfilled."
This is a fundamental principle that can be lumped under a lot of different phrases but can most concretely be explained as interfaces and implementations in Java.
When you use a Set in Java you are concerned with the behavior: each element only appears once. Java provides multiple implementations of a Set. Each implementation fulfills the contract of the interface using different techniques: hash buckets, trees, or bits.
Code that interacts with the Set only cares about the behavior, not how it is achieved.
The same semantics can be applied to many different things in your application. My favorite example is something that posts tweets.
interface Tweeter {
void postTweet(String message);
}
If I'm a class that wants to post tweets, all I care about it the ability to send a tweet.
public MyClass(Tweeter tweeter) {
this.tweeter = tweeter;
}
#Override
public void run() {
tweeter.postTweet("I'm a Runnable that's being run!");
}
How does the tweet get sent? From the perspective of MyClass, who cares!
In my real application I will of course use a TwitterTweeter (either directly when instantiating MyClass or via dependency injection). However, I now have the ability to pass in a MockTweeter of my own implementation to write a test that asserts that when a MyClass is run() it posts a tweet.
Things like this might seem obvious, but it's not a rarity to see code that (for this example) needs to posts a tweet and knows exactly how to do so.
Before I leave, two important points:
Interfaces and implementations are not the only way to accomplish this, they're just a very effective means of doing so.
Abstraction in this form is icing on a cake. A cake without icing sucks. But a cake with 5inch-thick icing also sucks. Apply it where it's needed and logical.

Related

Which design pattern can be used instead of Manager class?

I have a class called PhotoManager it's a singleton. This class contains methods like:
fun downloadPhoto(context: Context, photoUrl: String) { }
fun savePhotoUri(context: Context, uri: Uri) { }
fun setWallpaper(context: Context, photoUri: Uri) { }
I also have some other classes that have Manager postfix in their names. For example, SuggestionManager that receives some input data and returns user-based suggestions.
I'd like to refactor these two classes but I don't know which pattern to use. Can it be the Facade pattern?
Why does PhotoManager exist? Does PhotoManager have any state? If not, then just get rid of it. In Kotlin you can have functions outside of classes.
If it does have state, then figure out why you need the class, and that will help you figure out better name.
"PhotoManager" is a bad name, because nobody thinks "I need something to manage my photos"... and if someone did think that, then your class doesn't sound like it would do the job. As a consumer of your class, what is it to me?
If you temped to call your classes Managers and often use singletons, in most cases, it would mean just lack of understanding design patterns and what problem they solve.
The similar questions have already been asked many times and I just feel that at this stage, you can get inspired by some topics below.
Naming Classes - How to avoid calling everything a "<WhatEver>Manager"?
How to avoid …Helper or …Manager classes
The Clean Code Talks - "Global State and Singletons"
When dealing with images from a remote source, I would suggest following the Repository pattern. It will give you much more flexibility and will be easier to extend and maintain. For Android, the pattern is described by Google in the Guide to app architecture. There are plenty of technologies to choose from for the implementation so do some research before you start coding.
That should cover the first two methods. As for the others, I don't think I understand what they do well enough to suggest a solution.

Naming convention for methods returning RxJava's Completable

I have and Android app with the view class (Fragment, Activity) observing its ViewModel.
The ViewModel exposes methods such as getUserName which returns Observable<String>. Although maybe there is a possibility to find a better name (maybe observeUserName), I'm happy with the current one - it is quite explanatory.
However, here starts the hard part: ViewModel also can tell the view to perform some operation - for example close itself, pop backstack etc. For this case ViewModel defines following method (and corresponging Subject):
class ViewModel {
// other methods, fields
// ViewModel can call returnToPreviousScreen.onComplete()
CompletableSubject returnToPreviousScreen = CompletableSubject.create();
Completable returnToPreviousScreen() { return returnToPreviousScreen; }
}
In my opinion, the method's name is terrible. Hovewer I can not find anything better. Something like observeWhenToReturnToPreviousScreen is maybe more explanatory but hard to read.
So, are there any recommendations or maybe commonly used practices for naming such methods?
There's no universal answer to the naming problem, so the only thing you can get are opinions.
Rule of thumb
My approach to naming in rx-java usually looks at two things:
Does it express a "stream" of emitted events (usually with a plural form of a noun)?
Does it work well with other parts of rx java methods chain, and especially the subscribe method?
Both of the above can be usually simplified to trying to put the name of the method in this sentence:
This code subscribes to {name_of_the_method}.
Examples
A) getUserName
This code subscribes to getUserName.
👎 The sentence does not really make sense because getUserName does not express the stream. Quite on the contrary, it suggests that there is one value that you can get.
getUserName().subscribe()
B) observeUserName
This code subscribes to observeUserName.
👎 Although the method kind-of expresses the stream of events, it does not work well with subscribe. Method exposing the Observable is not a place for information about observing. The consumer of the method will be observing what that method returns.
observeUserName().subscribe()
C) userNames
This code subscribes to userNames.
👎👍 This might work in some cases. It nicely expresses a stream of userName items being emitted and works well with subscribe. It really depends on a particular scenario, because it suggests that you can expect multiple userNames while you really want to observe how a single userName changes.
userNames().subscribe()
C) userNameChanges
This code subscribes to userNameChanges.
👍 This method nicely expresses that there is a stream of items ("change" events) and it works well with subscribe method.
userNameChanges().subscribe()
Return to previous screen
As far as your returnToPreviousScreen case goes, I think I would end up using something like:
This code subscribes to returnRequests().
or
This code subscribes to previousScreenRequests().
or even a singular form as there can only be one event emitted in the stream:
This code subscribes to previousScreenRequest().
(not a topic of a question but I think I would use a Single<Unit> rather than Completable, to express a singular event emission rather than a completion... but maybe that's just me).

Using Dagger, is it ok to recreate an injected object?

A have code that is similar to this one:
class MyActivity extends Activity {
IStrategy mStrategy;
public void onCreate(Bundle data) {
if (someSpecificCondition) {
mStrategy = new StrategyA();
} else {
mStrategy = new StrategyB();
}
}
public void onUnsupportedState() {
// Will have to switch strategy
mStrategy = new StrategyB();
}
}
I would like to inject IStrategy here. But I have two problems:
It is an interface and the concrete implementation changes dynamically.
Even after a concrete implementation is chosen, there is the possibility that it will need to be recreated.
I could overcome (1) by creating a provides method with the decision logic (not sure if it is the best approach though).
But I am not sure what to do with (2).
Is it ok to manually create an injected object in this case? Does anyone see another solution?
As you said, adding logic to provider method is not a good design decision. Manually instantiating the object is valid in some cases, but only as a last resort.
In this case, the best approach (IMHO) is to inject abstract factory that instantiates IStrategy implementations on demand.
In the current state of the matters, the factory method will need to accept additional parameter that allows you to specify which strategy you're interested in. While it is not the end of the world, the fact that the client controls which strategy it uses is a bit unclean - the client knows how many strategies are there.
Depending on the specific use case at hand, you might be able to refactor the code and extract the logic that differentiates between strategies out of the client. That way your client will be asking for IStrategy while being completely agnostic of both the specifics of the implementation, and the number of available implementations.

Drawback of MVP over MVVM design pattern in android

Hi I am reading this post https://news.realm.io/news/eric-maxwell-mvc-mvp-and-mvvm-on-android/ where they explained very well about mvc, mvp, mvvm. I undertood how mvp design pattern works.
I don't find any drawback in MVP over MVVM. As they suggested this is issue
Presenter Concerns -> Maintenance - Presenters, just like Controllers, are prone to collecting additional business logic, sprinkled in, over time. At some point, developers often find themselves with large unwieldy presenters that are difficult to break apart.
Can anyone explain what does it means with an example & how it can be resolved using MVVM ?
I'm a big advocate of MVP and haven't really tried MVVM. The drawback of the possibility of a Presenter getting out of control is something I've had experience with but it can be mitigated.
In the example from the post the business logic will be relatively simple. There is likely only one model to deal with and not too much complex logic.
Let's think of a more complicated example though. Say you have an app that sells flowers. Once the user has chosen their bunch of flowers they get taken to the order options screen where they can:
add a message to the flowers
choose a gift vase
select postage addresses
choose a delivery date
Then add some domain requirements:
you can't add a message if they're delivering abroad
some areas have different lead times on delivery
some vases are only available with some flowers
This might not be the best UX but putting that aside you now have a Presenter that has to deal with many different Models (account, address, vases, orders) and can very quickly start taking on many responsibilities beyond simply telling the View what to display and passing events to the Model. This violates the Single Responsibility Principle. Also any time a class starts getting beyond 500 lines I start getting upset.
The solution is relatively simple though. You separate all your separate bits of logic out into UseCase classes. I use a relatively simple base class as follows:
public abstract class UseCase<I, O> {
public static final int NO_STATUS = -1;
public Observable<Integer> getStatus() {
return Observable.just(NO_STATUS);
}
public abstract Observable<O> getAction(I input);
}
You specify an input & output type and inject all the models you need in the constructor in the concrete implementation class. The Presenter takes events and input from the View passes this to the appropriate UseCase, this then does the complex logic with the Model and returns the appropriate data to the Presenter to update the View.
You can send periodic status updates back to your Presenter using the status if needed to update the UI state.
This way your Presenter returns to being a simple conduit for transferring data & events between the View and the Model and the business logic is nicely contained in a separate class for each action.
As in the MVVP introduction in the article said:
MVVM with Data Binding on Android has the benefits of easier testing
and modularity, while also reducing the amount of glue code that we
have to write to connect the view + model.
Main differences of MVP and MVVP are:
View layer: In MVP, your View is totally a dumb and passive View. But in MVVP, your View is more flexible because it can bind to observable.
In MVP, your Presenter takes care almost everything because of dumb View, so it will become really big and complicated gradually. Meanwhile, in MVVP, ViewModel have support from View (its a little bit smart :D), especially Data Binding, you can reduce a part of logic codes.
Therefore, you will write a lot of codes for Presenter and they are logically related in which you will find it difficult to break down.
However, many developers prefer MVP because they do not want some business logic codes being part of XML layout.

What does the annotations do exactly in Android at compile time?

#SuppressWarnings("unsued")
#Override
#SuppressLint({ "InflateParams", "SimpleDateFormat" })
I don't get why we need to declare annotations.
We want to facilitate the writing and the maintenance of Android applications.
We believe that simple code with clear intents is the best way to achieve those goals.
Robert C. Martin wrote:
The ratio of time spent reading [code] versus writing is well over 10 to 1 [therefore] making it easy to read makes it easier to write.
While we all enjoy developing Android applications, we often wonder: Why do we always need to write the same code over and over? Why are our apps harder and harder to maintain? Context and Activity god objects, complexity of juggling with threads, hard to discover API, loads of anonymous listener classes, tons of unneeded casts... can't we improve that?
How?
Using Java annotations, developers can show their intent and let AndroidAnnotations generate the plumbing code at compile time.
Features
Dependency injection: inject views, extras, system services, resources, ...
Simplified threading model: annotate your methods so that they execute on the UI thread or on a background thread.
Event binding: annotate methods to handle events on views, no more ugly anonymous listener classes!
REST client: create a client interface, AndroidAnnotations generates the implementation.
No magic: As AndroidAnnotations generate subclasses at compile time, you can check the code to see how it works.
AndroidAnnotations provide those good things and even more for less than 50kb, without any runtime perf impact!
Is your Android code easy to write, read, and maintain?
Look at that:
#EActivity(R.layout.translate) // Sets content view to R.layout.translate
public class TranslateActivity extends Activity {
#ViewById // Injects R.id.textInput
EditText textInput;
#ViewById(R.id.myTextView) // Injects R.id.myTextView
TextView result;
#AnimationRes // Injects android.R.anim.fade_in
Animation fadeIn;
#Click // When R.id.doTranslate button is clicked
void doTranslate() {
translateInBackground(textInput.getText().toString());
}
#Background // Executed in a background thread
void translateInBackground(String textToTranslate) {
String translatedText = callGoogleTranslate(textToTranslate);
showResult(translatedText);
}
#UiThread // Executed in the ui thread
void showResult(String translatedText) {
result.setText(translatedText);
result.startAnimation(fadeIn);
}
// [...]
}
Java annotations bind specific conditions to be satisfied with code. Consider a scenario where we think we are overriding a method from anther class and we implemented code that (we think) is overriding the method. But if we somehow missed to exactly override one (e.g. we misspelled name. In superclass it was "mMethodOverridden" and we typed "mMethodoverridden"). The method will still compile and execute but it will not be doing what it should do.
So #Override is our way of telling Java to let us know if we are doing right thing. If we annotate a method with #override and it is not overriding anything, compiler will give us an error.
Other annotations work in a very similar way.
For more information, read docs Lesson: annotations
Annotations are basically syntactic metadata that can be added to Java source code.Classes, methods, variables, parameters and packages may be annotated .
Metadata is data about data
Why Were Annotations Introduced?
Prior to annotation (and even after) XML were extensively used for metadata and somehow a particular set of Application Developers and Architects thought XML maintenance was getting troublesome. They wanted something which could be coupled closely with code instead of XML which is very loosely coupled (in some cases almost separate) from code. If you google “XML vs. annotations”, you will find a lot of interesting debates. Interesting point is XML configurations were introduced to separate configuration from code. Last two statements might create a doubt in your mind that these two are creating a cycle, but both have their pros and cons.
For eg:
#Override
It instructs the compiler to check parent classes for matching methods.

Categories

Resources