Skip to content

Instantly share code, notes, and snippets.

@pedrovgs
Last active August 2, 2023 16:53
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pedrovgs/61a8301a9952d195081edc989aa1fd41 to your computer and use it in GitHub Desktop.
Save pedrovgs/61a8301a9952d195081edc989aa1fd41 to your computer and use it in GitHub Desktop.
Interfaces for presenters in MVP are a waste of time!

##Interfaces for presenters in MVP are a waste of time!

It's been a long time since we started talking about MVP. Today, the discussion is about if creating an interface for the Presenter in MVP is needed.

This is the Model View Presenter pattern's schema:

MVP Schema

In this schema the Model box is related to all the code needed to implement your business logic, the presenter is the class implementing the presentation logic and the view is an interface created to abstract the view implementation.

Why the view should be implemented with an interface in this pattern? Because we want to decouple the code from the view implementation. We want to abstract the framework used to write our presentation layer independently of any external dependency. We want to be able to change the view implementation easily if needed. We want to follow the dependency rule and to improve unit testability. Remember that to follow the dependency rule high level concepts like the presenter implementation can't depend on low level details like the view implementation.

Why the interface is needed to improve unit testability? Because to write a unit test all the code should be related to your domain and no external systems as a SDK or a framework.

Let's go to put an example related to a login screen implemented for Android:

/**
* Login use case. Given an email and password executes the login process.
*/
public class Login {

  private LoginService loginService;
  
  public Login(LoginService loginService) {
    this.loginService = loginService;
  }
  
  public void performLogin(String email, String password, LoginCallback callback) {
  	boolean loginSuccess = loginService.performLogin(email, password);
  	if (loginSuccess) {
  	  callback.onLoginSuccess();
  	} else {
  	  callback.onLoginError();
  	}
  }
}

/**
* LoginPresenter, where the presentation logic related to the login user interface is implemented.
*/
public class LoginPresenter {
	
	private LoginView view;
	private Login login;
	
	public LoginPresenter(LoginView view, Login login) {
		this.view = view;
		this.login = login;
	}
	
	public void onLoginButtonPressed(String email, String password) {
		if (!areUserCredentialsValid(email, password)) {
			view.showInvalidCredentialsMessage();
			return;
		}
	
		login.performLogin(email, password, new LoginCallback {
			void onLoginSuccess() {
				view.showLoginSuccessMessage();
			}
			
			void onLoginError() {
				view.showNetworkErrorMessage();
			}
		});
	}
	
}

/**
* Declares what the presenter can do with the view without generating coupling to the view implementation details.
*/
public interface LoginView {

  void showLoginSuccessMessage()
  void showInvalidCredentialsMessage()
  void showNetworkErrorMessage()

}

public class LoginActivity extends Activity implements LoginView {

  .........

}

Please don't pay attention to the code syntax. I've written this from the scratch and it's almost pseudocode.

Why the View interface is needed here? To be able to write a unit test replacing the view implementation with a test double. Why is this needed in the unit test context? Because you don't want to mock the Android SDK and use the LoginActivity inside your unit tests. Remember that if you write a tets where the Android SDK is part of the SUT this is not a unit test.

At this part of the implementation is clear. We need an interface to do not depend on the view implementation.

Some developers have decided to add also an interface in top of the presenter. If we follow the previous example the implementation could be like this:

public interface LoginPresenter {

  void onLoginButtonPressed(String email, String password);
}

public class LoginPresenterImpl implements LoginPresenter {
  ....
}

or

public interface ILoginPresenter {

  void onLoginButtonPressed(String email, String password);
}

public class LoginPresenter implements ILoginPresenter {
  ....
}

What's the problem with this extra interface? IMHO this interface is not needed and is just adding complexity and noise to the development. Why?

  • Look at the class name. When the interface is not needed the names used become weird and don't add semantic to the code.
  • That interface is the class we have to modify to add a new method when the presentation logic has a new path and then we have to also update the implementation. Even when we use modern IDEs this is a waste of time.
  • The navigation in the code could be difficult to follow because when you are inside the Activity (the view implementation) and you want to navigate to the presenter the file where you are going to go next is the interface when most of the time you want to go to the implementation.
  • The interface is not improving the project testability. The presenter class can be easily replaced with a test double using any mocking library or any hand made test doubles. We don't want to write a test using the activity as SUT and replacing the presenter with a test double.

So...what is the LoginPresenter interface adding here? Just noise :)

But.....when should we use an interface? Interfaces should be used when we have more than one implementation (In this case the presenter implementation is just one) or if we need to create a strong boundary between our code and a third party component like a framewokr or a SDK. Even without interfaces we could use composition to generate abstraction, but the usage of an interface in Java is easier :) So, if you have more than one implementation of the same thing or you want to generate a strong boundary, then, add an interface. If not.....do not add more code. Remember, the less code to maintain the better. Remember that the usage of interfaces is not the only way to decouple our code and generate abstraction

But...what if I want to decouple the view implementation from the presenter implementation? You don't need to do that. The view implementation is a low level detail and the presenter imlementation is a high level abstraction. Implementation details can be coupled to high level abstractions. You want to abstract your domain model from the framework where it's executed, but you don't want to abstract in the opposite direction. Trying to reduce the coupling between the view implementation and the presenter is just a waste of time.

I've created this gist to discuss about this topic, please feel free to add any comment using code examples if needed :)

Extra ball: If you are thinking in different testing strategies for Android and the presentation layer I wouldn't use a unit test to test the presentation logic replacing the view with a test double. I'd try to use an approach like the one described here where the SUT is the whole presentation layer and not just the presenter (the test doubles are used to replace the use case).

@cesards
Copy link

cesards commented May 12, 2016

IMHO, and TL;DR I completely agree to all points mentioned at the beginning

Look at the class name. When the interface is not needed the names used become weird and don't add semantic to the code.

Correct, and Paul Blundell was talking about this a few days ago.

That interface is the class we have to modify to add a new method when the presentation logic has a new path and then we have to also update the implementation. Even when we use modern IDEs this is a waste of time.

I can imagine, saying "when the presentation logic has a new path" you mean you need to create new contracts/methods because the lifecycle of the activity makes you do that (onViewCreated()/onViewDestroyed/etc.). Since a while ago I try to divide presentation logic related to lifecycle, that way I don't mess up with my pure reactive implementation with view details. Here you are a simple example in order to have a clearer idea what I mean:

For the sample I'll use a reference from the SoundCloud guys repo

public class MyActivity extends LightCycleAppCompatActivity<MyActivity> implements View {
    @LightCycle LoginPresenterController controller;
    LoginPresenter loginPresenter;

    @Override
    protected void setActivityContentView() {
        setContentView(R.layout.main);

        loginPresenter = Application.getInstance().getPresenterModule(bla);
        presenterController = new PresenterController(loginPresenter);
    }

    // I try to think in a reactive way, so most of my views return observables handled by the presenter
    public Observable<Void> onRetryButtonClicked() {
        return RxView.clicks(retryButton)
    }

    //...
}

So this way I handle all my preseter details related to the lifecycle in a modular way:

public class PresenterController extends DefaultActivityLightCycle<MyActivity> {

   private final Presenter presenter;  

   public PresenterController(Presenter presenter) {
        this.presenter = presenter;
   }

    @Override
    public void onPause(MyActivity activity) {
        presenter.onViewWillHide();
    }

    @Override
    public void onResume(MyActivity activity) {
        presenter.onViewWillShow()
    }
}

and finally, my presenter handles all the subscriptions and do whatever it needs to do

@Override public void onViewWillShow() {
    super.onViewWillShow();

    loadUrl(signInUrl);

   addToAutoUnsubscribe(loginClicks.subscribe(view::selectAvatar));

   addToAutoUnsubscribe(view.onSelectionConfirmed()
      .doOnNext(ignored -> view.updateWhateverNeeded())
      .switchMap(this::updateUser)
      .observeOn(observeOn)
      .subscribe(ignored -> view.showSuccessfulUserUpdate()));
}

@Override public void onViewWillHide() {
    super.onViewWillHide();
    view.stopLoading();

    clearSubscriptions();
}

Do you get more or less my idea?

The navigation in the code could be difficult to follow because when you are inside the Activity (the view implementation) and you want to navigate to the presenter the file where you are going to go next is the interface when most of the time you want to go to the implementation.

Correct. It's easier creating a method directly in the implementation using the refactor tool:

@Override protected void onStart() {
  super.onStart();

  presenter.onViewWillShow(); // refactor (create) this method directly in the presenter
}

@Override protected void onStop() {
  presenter.onViewWillHide();

  super.onStop(); // refactor (create) this method directly in the presenter
}

The interface is not improving the project testability. The presenter class can be easily replaced with a test double using any mocking library or any hand made test doubles. We don't want to write a test using the activity as SUT and replacing the presenter with a test double.

TL;DR

YES

But.....when should we use an interface? Interfaces should be used when we have more than one implementation (In this case the presenter implementation is just one)

As I said before, I recommend all of you reading this article. Very instructive!!

@jmsalcido
Copy link

jmsalcido commented Oct 20, 2016

I know that I am late but I want to give my opinion because this is the internet.

I totally disagree. I dont get the "confusing" part of an interface, it is a contract, an abstraction, even interface code as a POJO (talking about Java) can be transpiled to any language, it is pretty simple, there is no internal knowledge, can be used as a POXX (POCO, POJO, PONSO, even a C struct, whatever domain model or "plain old X object")

That's the magic of the interfaces, not "being able to mock them", for the mocking framework it is the same if it is a class or an interface or even an enum (if you are on Java).

Of course you will probably not get a second implementation of a Presenter or View, or any type of class, Service, Repository, or any fancy name for your objects here living in the same runtime as other, but you can still create a _StubPresenter_ in order to return real values to your application, this lovely _StubPresenter_ can be returned in your UI testing instead of the real implementation, just use the Stub and develop quickly and have faster tests instead of hitting your real implementation (flaky tests, anyone?).

I remember now that I answered over the article discussion: http://blog.karumi.com/interfaces-for-presenters-in-mvp-are-a-waste-of-time/

back in the day of publication, this was my original answer:

The advantages of having the interface is that you can have your StubImplementation and always inject that in your tests, you can at least have 2 implementations (one the production and other is the test).

It can be seen as "noise" but it is actually a good understanding of the SOLID (D) principle, depend on the contracts, not the concrete classes, it might be only 1 implementation on the actual codebase, but in the future it could be a different one, also, it is just a simple interface... I would include the interface, but still it is a good explanation why it is actually not needed. It is just a good practice to think about the possible next implementation, instead of modifying the current one, just create a new one from scratch and delete the old implementation.

Then you will be using the O principle, you dont need to modify the source code of classes that use the "interface", because you will be deleting the implementation, not the contract and also the L principle, because you will be using subtypes and the program will continue working.

Had to comment about it, good article... but still I would leave the interface.

I still hold that answer, I would leave the interface all days, everyday.

I also read this thread: https://www.novoda.com/blog/better-class-naming/ some time ago and I dont agree with that too, Impl is the name that IntelliJ provides for default implementations it is not a "naming convention" just lazy developers who did not want to modify the default name and create a fast implementation using the magic of IntelliJ -> "alt/option/ctrl + enter"

Just name it... I dont know, ConcreteInterface or AndroidInterface or PlatformBeingUsedInterface or leave the Impl, there is nothing wrong with that.

Also... _we should not care about the concrete class names, the contract that we expose is what we care about!!!_

Also, if you program based on the interface, that contains the "good" name (based on the article), you dont care about the implementation, we should not care about the implementation, I dont care about logic of the Presenter if I am doing View logic, you care about the contract, if it says: "presenter.doSave()"... you know that you will save data, you dont care if it will be slow, fast or if it is really going to go to a database or if it is an empty subroutine, you know that it will call the save subroutine and if it is empty that's okay, you are hitting the presenter, your layer should not care about what will the next object/layer do, only its responsibility.

Sorry for reviving this thread I saw a question over this tweet:
https://twitter.com/donnfelker/status/788842213283274752

and an answer: https://twitter.com/Guardiola31337/status/788846661791547392 with a link to this discussion! :P

PS: if you really do TDD (tbh I dont.), just create the contract and then you will just following the contract, mock the interface and everything is going to be created progressively, you will create the test case for the user of the contract, then you will create the test for the implementation of the contract and mock any dependency using just an interface, you will not care about code. Even for lazy programmers that dont want to write a lot... it is even simpler to create an interface:

even if we go and compare workflows with shortcuts it is simpler to create the interface!! haha.

this would be my workflow in macOS and IntelliJ/Android Studio when doing some TDD:

  • write any unit test and the test case, add any service/layer/object name that is going to be an interface
  • cmd+1
  • cmd+n
  • type class
  • down arrow until "interface" is selected
  • type the return type (no public access method over interfaces, it is useless to write "public")
  • type that gorgeous name of the method that you need
  • add any param (and even if you have already implementations use your ide to add params and refactor correctly instead of doing it manually)
  • cmd-[ (back in IntelliJ)
  • continue with your lovely Unit Test

Come on, compared to:

  • write any unit test and the test case, add any service/layer/object name that is going to be a concrete class
  • cmd+1
  • cmd+n
  • type class
  • type the access type
  • type the return type
  • type that gorgeous name of the method that you need
  • add any param (and even if you have already implementations use your ide to add params and refactor correctly instead of doing it manually)
  • add empty ugly {} or { return null }
  • cmd-[ (back in IntelliJ)
  • continue with your lovely Unit Test

BTW: I love this kind of conversations over internet, please invite me :(

tl;dr in english:
to be honest, I would leave the interface, I dont see the "noise" on using a contract instead of a concrete class, if you use a simple text editor it is not an excuse to say: "that's noise" because you would see (probably because everyone else that is not a super hackyhackerhackman uses Android Studio or IntelliJ while doing Java) the same contract name and the suffix Impl or if you are not lazy just ConcreteInterfaceName or AndroidInterfaceName (or I prefix if you do C#), you would only go to the interface if you are looking for the contract.

"the tl;dr is tl;dr": https://en.wikipedia.org/wiki/Dependency_inversion_principle

tl;dr in spanish:
La neta, yo dejaria la interfaz, no veo el "ruido" en tener un contrato simple en lugar de una clase concreta. No es excusa tampoco que usas un editor de texto basico y que "confunde" por que verias el nombre del archivo seguido de "Impl" (por que todo mundo que no es un super hackity hack man usa IntelliJ o Android Studio) ó cualquier nombre como AndroidInterfaceAqui ó InterfazConcretaAqui ó el prefijo "IInterface" si usas C#... solamente irias a la interface si buscas el contrato.

"el tl;dr es tl;dr": https://en.wikipedia.org/wiki/Dependency_inversion_principle

@maxcruz
Copy link

maxcruz commented Oct 24, 2016

Hola a todos. He leído sus comentarios y antes que nada deseo agradecerles pues me han servidor muchísimo para cuestionar algunas decisiones de diseño que tomé en el pasado y evaluar mejor mi actual implementation.

Lo primero que me gustaría aclarar es que estoy completamente de acuerdo en que es un error llamar a las interfaces con el prefijo I o a su implementación con el sufijo Impl, en la mayoría de casos es una señal de sobre abstracción, usualmente estas interfaces no agregan valor y se pierde la oportunidad de nombrar el código con significado (nombrar es una de las partes más difíciles en el software, porque nombrar artefactos es diseñarlos)

Sin embargo creo que en el caso de MVP, la interfaz usualmente se utiliza con un propósito diferente al de simplemente abstraer un concepto. Pensando en las interfaces MVP como contratos entre los componentes, parte del valor que aportan a nuestro código es resaltar la relación que existe y el patrón que estamos siguiendo. Por ejemplo:

public interface LoginMvp {

    interface Model {
      ...    
    }

    interface View {
      ...    
    }

    interface Presenter {
      ...    
    }
}

Esta interfaz más que describir la abstracción de un concepto en particular (Login), está abstrayendo un sistema. Un desarrollador nuevo que se encuentra con el código al menos entenderá la intención de su predecesor de seguir el patrón MVP y le resultará simple identificar los componentes que se relacionan en esta parte del código. Por lo general tendremos muchos modelos, vistas y presentadores.

Creo que la mayoría estará de acuerdo en que uno de los problemas más grandes que tenemos los que trabajamos en Android es la falta de un playground o una arquitectura clara a seguir (uno rara vez se encuentra dos aplicaciones hechas de la misma forma). En este sentido pienso que vale la pena hacer esfuerzos que faciliten entender la arquitectura de la aplicación.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment