HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

A button, as a "Clean Architecture" plugin

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
pluginarchitecturebuttonclean

Problem

You can call it ports and adapters or hexagonal architecture. Regardless, what's facinated me about this picture isn't the layers. It's the Clean Architecture UML diagram over in the corner of a plugin that looks like an upside down, folded over version of the Dependency Inversion Principle:

So while the original DIP only showed how to descend into layers this shows how to come back out without creating dependencies that point in the wrong direction.

If I were to color this to follow the clean architecture diagram it would look like this:

Some like to think of an interface like it's owned by the class that implements it.

Some like to think of an interface like it's owned by the client that uses it.

For the first time I'm starting to think either can be true. Both interfaces are really owned by the red inner layer. Rather than ownership of interfaces happening vertically or horizontally here it's happening diagonally. At least until you rotate around the "mechanism Layer" to get back to the clean architecture UML. Then ownership is vertical.

By ownership I mean what gets to dictate change. Neither Presenter or Controller designers get to dictate that the Input or Output port interfaces need to change. The Interactor designer gets to make that call. Which is why browser plugins are at risk of breaking every time a new version of the browser comes out.

I've written some example code that is just supposed to show how these layer plugins might look. Please check it for clarity. It's just a button push without much transformation or useful indirection so it might not be the best example yet. Ideas to improve that would be most welcome. One thing that's completely missing is an Entity.

Code listing presented in an order that follows the flow of control:

```
package candiedOrange.plugin.adapters;

import candiedOrange.plugin.usecases.ButtonUseCaseInputPort;

public class ButtonControler {
ButtonUseCaseInputPort button;

public ButtonControler(But

Solution

Some like to think of an interface like it's owned by the class that
implements it.

Some like to think of an interface like it's owned by the client that
uses it.

For the first time I'm starting to think either can be true.

It is true. The difference lies in semantics.
Interface owned by its own class

The core is: EVERY class has an interface aside the language construct "interface". The problem is: Sometimes it is not beneficial.

If you have a class in JAVA sometimes it is hard to ensure encapsulation. Therefore you hide the class behind an "interface" language construct.

The separate interface of a class is only an extraction of the interface the class already implicitly has. You can compare it to the header file in the programming language "C" where it provides perfect encapsulation.

In JAVA it is a helper construct which is not enforced. So nothing hinders you to use the concrete class implementation instead of the interface. In "C" you only make the header files known to other compilation units (I hope so, as I am not a C-developer).
Interface owned by the framework

The other way around: A framework provides functionality. To let your object cooperate with the framework they have to meet some requirements that are formulated as "interface" language constructs.

Here comes the complicated thing:

You may have a class with an extracted alternative interface AND you want to have a contract to work together with a framework. Then you have two interfaces with different semantics to handle.
The clean architecture

If you consequently follow the SOLID principle it will guide you to exact this architecture. You have no chance to miss it.
Your code

In general I do not think that pressing a button is a usecase but I think you have a correct reference implementation of clean architecture.

Context

StackExchange Code Review Q#148809, answer score: 8

Revisions (0)

No revisions yet.