1

Hobby coder here, so please be gentle! My coding is taking me into the necessary realms of architecture due to increasingly complex apps. I'm wondering how to structure my solutions which will involve separating off layers to separate libraries whilst implementing the MVP model (specifically, the 'observing presenter style').

Following the onion model:

Onion model

I would have guessed that Views need to be in the Framework Layer? However, this would break the referencing principles of the onion architecture, as Interface.Presenters would have to reference Framework.Views given how the Observing presenter style works (that is inside outwards rather than vice versa). Or do I put Views in the Interface layer (which leaves me puzzled about what would actually go into the Framework layer).

Additionally, is there any benefit to splitting Presenters, Views and Repository into separate libraries, or just stick with sub-domains?

An example of how implementing MVP Observer style is the first answer here

My current Solution structure looks like this:

enter image description here

Would welcome any help getting my head around this. I'm invariably thinking about it wrong!

2 Answers 2

5

Interface.Presenters would have to reference Framework.Views

Have you seen this?

enter image description here

Clean Architecture by Robert Cecil Martin

This shows the static dependencies still pointing inward across the layers. This is despite taking references to things from outer layers. It just requires interfaces that are not owned by what they abstract. At least not in this case.

enter image description here

Here you see two interfaces. Input<I>* abstracts the Interactor. And they're both owned by Application Layer. But Output<I>* abstracts Presenter of the Interface Adapter Layer despite being owned by the Application Layer.

* I shortened the names so we could move on with our lives.

This 2nd diagram is good old DIP rotated into plugin form. The view can be considered half of the plugin. The other half is missing because the diagram doesn't bother to show you what is driving the controller. Uncle Bob left that part off.

The thing I'm struggling with is, if you check the link to the SO post, you'll see that the creation of the Presenter class requires that a View class is passed to it via dependency injection. Thus, the Interface layer Library would have to reference its outer Framework layer Library (where Views are stored), breaking the 'inward' referencing convention (e.g. Application Layer only referencing Domain, Interface only referencing Application etc)

stigzler

The dependency arrows aren't about where references can come from. They're about what the using code can understand about what those references refer to. The FinancialReportController code is forbidden from understanding what a ScreenPresenter is. But it can hold a reference to it. It just can only understand that reference to be some FinancialReportPresenter like thing. Which is what the ScreenPresenter is. Also the PrintPresenter.

class FinancialReportController {

    FinancialReportPresenter frp;

    FinancialReportController(FinancialReportPresenter frp){
        this.frp = frp;
    }
}

Notice that FinancialReportController has never heard of a ScreenPresenter or a PrintPresenter. Yet you can inject them into its constructer just fine.

This same pattern can be seen between the Presenter and the View:

class ScreenPresenter implements FinancialReportPresenter {

    ScreenView sv;

    ScreenPresenter(ScreenView sv){
        this.sv = sv;
    }
}

Just like before, ScreenPresenter has never heard of a WebView. Yet you can certainly hand it one in its constructor. It's free to talk to it through the ScreenView interface. It just has no idea what it's talking to.

It might be worth studying the Strategy Design Pattern. If you're curious I've talked about figure 8.2 before.

6
  • Thanks for the response. Do you have a reference for the first diagram? I need to study it more. The thing I'm struggling with is, if you check the link to the SO post, you'll see that the creation of the Presenter class requires that a View class is passed to it via dependency injection. Thus, the Interface layer Library would have to reference its outer Framework layer Library (where Views are stored), breaking the 'inward' referencing convention (e.g. Application Layer only referencing Domain, Interface only referencing Application etc). Hope makes sense - apols - I'm an amateur coder
    – stigzler
    Jan 6 at 10:32
  • @stigzler better now? Jan 6 at 13:34
  • Thanks for the addition. I'll come back to it with fresh eyes, as trying to translate your example code to Views + Presenters rather than Controllers and Presenters is hurting my head a bit! Fig 8.2 is awesome though as it encapsulates where my conceptualisation is at as I'd fallen naturally into have some for of Controller AND Presenters. What is it from?
    – stigzler
    Jan 6 at 22:21
  • @stigzler what is it from? It's from Martins book, Clean Architecture. I added a link to it. Jan 6 at 23:15
  • @stigzler that help with the translating? Jan 6 at 23:46
4

I'm going to take your questions in reverse order.

  1. How to structure your projects

    Don't have a project per layer. Make you projects individual components like a repository or a web front end, or a service.

    You can see in your diagram that each layer has multiple unrelated components in it. It's definitely better to separate out components by "feature" rather than "layer" once you get beyond an example project. You can use solution folders for your layers if it helps you organise things.

  2. How to reference an outer layer from an inner layer.

    I'm not 100% clear form your question exactly what you need to reference from what, but the general rule is if you need to do this:

  • make an interface for the component you want to reference
  • put that interface the inner most layer
  • reference the interface rather than the concrete class

This way you avoid referencing an outer layer from an inner layer. While still being able to make everything work.

So for example a controller needs to write to the db. You put the interface for the repository in the "Application" layer and reference that from the Controller in the "Interface" layer. then in the application you can inject the concrete instance of the repository and everything works, without breaking the rules.

With your specific case of views, I think I would just rearrange things a bit and put things in a layer which makes it easiest to implement the pattern you are using. The key thing is to be consistent with your direction of referencing not which layer you put presenters/controllers/viewmodels etc in or what you call them.

1
  • Great response. Thanks. Deffo food for thought + helpful. To check I understand: if I have Presenter in Interface Layer and the actual UserView in the Framework Layer, then I would just create IUserView in the Interface Layer and then instantiate the UserPresenter via new UserPresenter(UserView) from the Framework layer? Defining projects as functions rather than layers is a bit baffling though, and I'd worry I'd break the Onion 'inward' referencing rules. Just wonder whether it'd be easier to fall into circular referencing and also reference the 'wrong way' via this approach. Will reflect
    – stigzler
    Jan 6 at 22:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.