سؤال

Michael Nygard writes in Release It!:

Have you ever checked in a commit that had bunch of new files like "Foo", "FooController", "FooFragment", "FooMapper", "FooDTO", and so on? That is evidence of bad layering.

This sounds pretty significant as almost every code base I saw so far looks exactly like this. For example a little web application (in Java implemented with Spring Boot - irrelevant):

com.example.foo
└ FooApplication.java
└ controller
  └ FooController.java
  └ FooDTO.java
└ model
  └ Foo.java
  └ Foos.java
└ repository
  └ FooRepository.java

Looks like what Nygard is talking about.

What is a better approach here?

  • Use the model object Foo direct in the controller's input/output to eliminate FooDTO? Sounds not correct.
  • Do the domain logic direct in the controller to eliminate domain objects? Sounds horrible.
  • Do the persistence direct in the domain object to eliminate the repository? Maybe.

I still don't see an option how to eliminate the controller as a representative of the application layer.

Nygard writes futher in the same paragraph:

What appears as a class in one layer should be mere data to every other layer.

Is this not what FooDTO is all about?

So what would satisfy Nygard's concerns? Or is that just my misconception?

هل كانت مفيدة؟

المحلول

The quote needs to be put in context.

  • Michael Nygard makes these claims to criticise the traditional layered architecture of enterprise software (he calls them UI/Session/Domain/Persistence);
  • His main issue is that the layers inhibit incremental change, probably because "Layers enforce vertical isolation, but they encourage horizontal coupling", the latter being a hindrance for incremental change.

The whole point is not about the packaging the files, nor about the naming of classes, but about the overall architecture of the application. And in particular undesired coupling that slows down incremental approach.

The drawbacks of the layered architectures in OOP are well known, and several other authors have addressed this topic, with new emerging architectures:

  • Domain objects (models), DTOs, repositories, and controllers all continue to be needed. For example DDD has proven to be a solid foundation to evolutive applications and it promotes the use of domain objects and repositories (in comparison, direct access to persistence layer would be counter-productive); as another example, DTOs are required in the context of distributed systems.
  • But the architecture models tend to become more concentric and avoid dependencies of the upper layers on the lower layers. The main challengers are nowadays the hexagonal architecture, and the clean architecture. Both put domain object at the core of the application, and see user interfaces, and database adapters on the (exchangeable) outer border of the system.

So in the end you will find the same kind of classes. But their dependencies are better thought and hence allow for more evolutivity. Finally, if you opt for breaking the monolith with microservices, you may end-up packaging a smaller amount of highly cohesive files, with fewer dependencies to the outside world.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى softwareengineering.stackexchange
scroll top