I would suggest doing neither.
Trying to enforce a technical layering with a package structure leads to a lot of entanglement in your application. Not to mention the fact that we try so hard to hide everything behind a service interface and the first thing we do (mostly due to packaging) is make everything a
public class. This becomes painful when there is a technical separation between a
x.y.z.repository package, now everything can access the repository. Boom there goes your encapsulation inside the service layer.
Instead you should follow a more functional and onion based approach (clean architecture, hexagonal architecture). This is also nicely in line with the Single Responsibility Principle (when applied to a package) and also in accordance with the packaging principles
- Things that change together are packaged together
- Things that are used together are packaged together
Oliver Gierke has written a nice post on packaging components together in Java. Simon Brown has written a more general story on the subject.
I would strive for a core package structure like the following to hold the core of your application:
Now if you have a web interface you add, for instance, a
web subpackage, for webservice a
rest package to hold only that. It basically connects to the core.
Now you could consider reusing the objects from inside your core into the other layers, but IMHO it is better to use a specific domain for that layer. As, just as with Object to SQL mapping there is (often) a mismatch in what we want show on the screen or use as XML in the webservice and how the business logic is implemented. Depending on the complexity of the business and web domains you could consider them as seperate problem domains to solve which need to be connected, basically 2 different bounded contexts.
To use a quote from a CQRS resource
It is not possible to create an optimal solution for searching, reporting, and processing transactions utilizing a single model.
Don't try to put everything into a single (domain) model, separate the responsibilities. You probably end up with more (smaller) classes but a cleaner separation between the layers of your application.
Remember creating a architecture is deciding on the trade-offs of one solution to the other. It depends highly on the complexity of the domain and should mainly be driven by the functional requirements of your application. However it is influenced by the non-functional (performance, security) and environmental constraints (language to use, platform, experience). And architecture, like coding, is never finished each new requirement can (and maybe should?) lead to a redesign of the application.
Yes I also tried to put everything in a single model, and yes I also tried to use a technical separation in my applications. However after a couple of years of experience in creating entangled application layering (at first it seems a good idea, then the application starts to grow...) I figured there must be another way.
- Clean Architecture, Uncle Bob Martin
- Hexagonal Architecture (aka Ports and Adapters), Alistair Cockburn
- Whoops where did my architecture go, Oliver Gierke
- Principles of OOD, Uncle Bob Martin
- Mistakes when applying DDD, Udi Dahan
- Bounded Contexts, Martin Fowler
- Architecturally Evident Coding Style, Simon Brown
- Growing Object-Oriented Software, Guided by Tests
- Java Application Architecture: Modularity Patterns with Examples Using OSGi (Robert C. Martin Series)
- Domain-Driven Design: Tackling Complexity in the Heart of Software
- Software Architecture for Developers
- Implementing Domain Driven Design