Yes, another question on separation of responsibilities in an MVC architecture for a web application - I think this one has a subtle difference however...
My existing implementation looks like this:
Controllers: Very 'thin'; ASide from calls to Models & Views, Routing & Presentation Logic Only
Models: Very 'thick'; All Business Logic
Views: Very 'thin'; Aside from Content & Markup, Code is limited to Loops & Data Formatting
Additionally, the project utilizes an ORM as an abstraction layer above the database and 'Connectors' as wrapper classes to external services.
My question concerns the separation of responsibilities between models. For the most part, our Models mimic the 'things' within our system - 'Users', 'Products', 'Orders', etc.
I'm finding that this works quite well for serving simple data retrieval requests - the Controller(s) instantiate(s) the proper Model(s) & calls the relevant 'getter(s)'.
The issue arises when more complex processes are initiated such as 'PlaceOrder' or 'RegisterUser'. Sometimes these processes can be implemented within a single model, other times they require communication or coordination between models to implement.
As it stands, the Models communicate with each other directly in these cases rather than the process being managed by the Controller. Keeping the process within the Models seems proper (the Controller needn't be aware that a business rule of 'RegisterUser' requires a confirmation email to be sent, for instance).
What I'm finding with this implementation are two issues which concern me somewhat:
Models often seem to know too much about other Models - Models seem too tightly coupled in this implementation.
Methods within the Models are of two general types: 'getters/setters' and what I've taken to calling 'Process Methods', methods which manage a process, calling other methods within the Model or other Models as appropriate - these methods seem 'un-model-like', for lack of a better description.
Would it be appropriate to implement two sorts of Models - 'Data/Object Models' (populated primarily with 'getters/setters' and perhaps simple 'Process Methods' which are exclusively internal and 'Process Models' (populated with 'Process Methods' which require the collaboration of multiple ('Data/Object') Models)?
In this implementation, we'd have Models representing 'Users, 'Products', 'Orders' as well as 'Registration', 'Ordering', etc.
Thoughts?
The solution to this problem is to have a separate layer, a thin layer on top of Model. This layer is sometimes called the Service Layer or Application Layer. This layer does not too much of state, it rather calls various model methods and Data Access Methods.
For example, you may have one service class for managing orders.
class OrderService {
placeOrder(Order order) {
order.doModelStuff();
orderDao.save(order);
}
removeOrder(order){
order.cancel();
orderDao.delete(order);
...
}
or
class UserService {
registerUser(User user) {
if(userDao.userExists(user)) {
throw exception: user exists;
}
user.doRegistrationStuff();
userDao.save(user);
}
The methods in service layer are not confined to manipulate a single entity. In general, they can access and manipulate multiple models. For example,
placeOrder(Customer customer, Order order) {
customer.placeOrder(order);
save customer, if necessary.
save order, if necessary
customer.sendEmail();
Shipper shipper = new shipper;
shipper.ship(order, customer.getAddress());
...
}
The idea of this layer is that, its methods do a unit of work (typically corresponding to a single use case). This is in fact more of a procedural nature. You can read more about this layer from Martin Fowler, and others.
Note: my point is to show what a service/application layer is, not to show implementation of order, customer etc.
Martin Fowler, in his "Refactoring" book, seems to have the opinion that a "Data" model consisting of data, accessors, and nothing else, is a good candidate for refactoring into another class. He calls it "Data Class" in his library of "bad smells" in code.
That suggests it may be better to look at simplifying interactions between different processes, but allowing a process to be closely coupled to its own data
e.g. PlaceOrder and OrderData can be tightly coupled, but PlaceOrder involves a minimum of interactions such as AddOrderToCustomerRecord with the Customer process.
In design pattern terms, separating your model objects into simple objects (with getters and setters) and process objects (with process logic) would be turning your Domain Model into an Anemic Domain Model with Transaction Scripts.
You don't want to do that. Model objects telling each other to do things (your process methods) is good. That kind of coupling is preferable to the kind of coupling you get from using getters and setters.
Objects have to interact with each other, so there has to be some level of coupling. If you limit that coupling to methods that are meant to be exposed to the outside world (the object's API if you will), you can change the implementation of the object without side effects.
Once you expose implementation details (getters and setters expose object internals, which are implementation specific), you can't change the implementation without side effects. That's bad coupling. See Getters and Setters Are Evil for a more thorough explanation.
Back to your process methods and excessive coupling, there are ways to reduce coupling between model objects. Check the Law of Demeter for some guidelines on what is reasonable and what should be a red flag.
Also take a look at Domain Driven Design for patterns for reducing coupling. Something like an Aggregate Root can reduce coupling and complexity.
The tl;dr version: don't separate your data and methods, hide your data and only expose your API.
Related
In book 'Patterns of Enterprise Application Architecture', following is stated:
When thinking of a system in terms of layers, you imagine the principal subsystems
in the software arranged in some form of layer cake, where each layer
rests on a lower layer. In this scheme the higher layer uses various services
defined by the lower layer, but the lower layer is unaware of the higher layer.
On other hand, in book 'Agile Principles, Patterns, and Practices', following is stated on Dependency-Inversion Principle:
High-level modules should not depend on low-level modules. Both should depend
on abstractions.
This sort of confuses me. Am I mixing two different things here?
I suppose that it could speak to some the same principles, but at different levels of granularity. I would still view Dependency Inversion as something that stands on its own, however.
In the first instance, consider this example - in a simple layered architecture, you might have a presentation layer built in JavaScript, a business logic layer built in Java, and a data layer in SQL Server. These layers could be developed by different teams of people. The presentation layer knows how to make API calls to the business logic layer, but not the other way around. The business logic layer knows how to read/write to and from the database layer, but not the other way around. The distinction here happens at a high-level - you might even call it conceptual.
In the second instance, you want to prevent scenarios where supposedly generic code depends on specific implementations - and at this point, I see it as a relatively low-level concern that falls within the scope of a particular application (i.e. in code, not conceptually as in the previous example). If you have code that writes to a database, but you want to support different implementations - e.g. MySQL and SQL Server, where each of those might have some specific intricacies, don't make the calling code explicitly depend on either of those - abstract away the complexity through an interface. This is what the Dependency Inversion Principle addresses (see below).
public class UserService {
public UserRepository repository;
public void setUserRepository(UserRepository repository) {
this.repository = repository; //Is this a MySqlRepository or a SqlServerRepository? We don't care - the dependency is managed outside and we can change it without changing this class.
}
public void persistUser() {
this.repository.persist(user); //We just care about the abstraction - the interface.
}
}
Am I mixing two different things here?
Yes.
The first case is about dependencies at run-time while the second case is about dependencies at compile-time.
For example, at run-time, business layer can call the functions/methods implemented in database layer. But at compile-time, business layer code does not mention any code in database layer. This is usually achieved with Polymorphism.
I was trying to find tutorials and good examples which would explain difference between those two, but not able to find any information.
Pure fabrication and indirection acts to create and assign responsibilities to intermediate object, so could anyone explain what is difference between those design patterns?
Thanks!
You use Indirection if you want to create a lower coupling between components. The example Larman suggests in Applying UML and Patterns is a class TaxCalculatorAdapter. In order to shield clients from having to know inner workings of a possible adapter, he hides them with an indirection, only exposing the required API. This Indirection will be highly coupled to the adaptees, but only loosely coupled to the clients.
The PersistentStorage from Pure Fabrication is indeed an Indirecton (Larman states so in the book) in that it provides lower coupling. Pure Fabrication goes beyond that though in that it creates objects that are not part of your Domain Model.
The example Larman gives is a domain class Sale. Since Sale has all the data to save, it would be a candidate to hold the logic for saving a Sale as well (Information Expert). However, persistence logic is not related to the concept of a Sale, hence the class would become incohesive. Also, by coupling the Sale to a particular DB API, you limit reuse (Indirection to the rescue). And because saving is a general activity, you would likely also duplicate code in objects which also need to be saved. To avoid this, you make something up (the pure fabrication), meaning you create something that is not part of the Domain model (here: a PersistentStorage), but still captures an essential activity in your application.
As such, Pure Fabrication it is a specialization or rather a variant of Indirection.
Pure fabrication and indirection both are principles from GRASP.
Following examples in this dzone article might clear your concept about pure fabrication and indirection.
Pure Fabrication:
We know the domain model for a banking system contains classes like Account, Branch, Cash, Check, Transaction, etc. The domain classes need to store information about the customers. In order to do that one option is to delegate data storage responsibility to domain classes. This option will reduce the cohesiveness of the domain classes (more than one responsibility). Ultimately, this option violates the SRP principle.
Another option is to introduce another class which does not represent any domain concept. In the banking example, we can introduce a class called, PersistenceProvider. This class does not represent any domain entity. The purpose of this class is to handle data storage functions. Therefore PersistenceProvider is a pure fabrication.
Indirection:
This principle answers one question: How do you cause objects to interact in a manner that makes bond among them remain weak?
The solution is: Give the responsibility of interaction to an intermediate object so that the coupling among different components remains low.
For example, a software application works with different configurations and options. To decouple the domain code from the configuration a specific class is added - which shown in the following listing:
Public Configuration{
public int GetFrameLength(){
// implementation
}
public string GetNextFileName(){
}
// Remaining configuration methods
}
In this way, if any domain object wants to read a certain configuration setting it will ask the Configuration class object. Therefore, the main code is decoupled from the configuration code.
If you have read the Pure Fabrication Principle, this Configuration class is an example of pure fabrication. But the purpose of indirection is to create de-coupling. On the other hand, the purpose of pure fabrication is to keep the domain model clean and represent only domain concepts and responsibilities.
Many software design patterns like Adapter, Facade, and Observer are specializations of the Indirection Principle.
Pure fabrication class is a type of class ,which does not concept in a problem domain designed ,This class is assigned with high cohesion ^,low coupling & reuse.
Indirection
It solves the problem of assigning the responsibility of avoiding direct coupling between things.it also ensures low coupling between the objects & maintains higher reside capabilities.
We are taking a long, hard look at our (Java) web application patterns. In the past, we've suffered from an overly anaemic object model and overly procedural separation between controllers, services and DAOs, with simple value objects (basically just bags of data) travelling between them. We've used declarative (XML) managed ORM (Hibernate) for persistence. All entity management has taken place in DAOs.
In trying to move to a richer domain model, we find ourselves struggling with how best to design the persistence layer. I've spent a lot of time reading and thinking about Domain Driven Design patterns. However, I'd like some advice.
First, the things I'm more confident about:
We'll have "thin" controllers at the front that deal only with HTTP and HTML - processing forms, validation, UI logic.
We'll have a layer of stateless business logic services that implements common algorithms or logic, unaware of the UI, but very much aware of (and delegating to) the domain model.
We'll have a richer domain model which contains state, relationships, and logic inherent to the objects in that domain model.
The question comes around persistence. Previously, our services would be injected (via Spring) with DAOs, and would use DAO methods like find() and save() to perform persistence. However, a richer domain model would seem to imply that objects should know how to save and delete themselves, and perhaps that higher level services should know how to locate (query for) domain objects.
Here, a few questions and uncertainties arise:
Do we want to inject DAOs into domain objects, so that they can do "this.someDao.save(this)" in a save() method? This is a little awkward since domain objects are not singletons, so we'll need factories or post-construction setting of DAOs. When loading entities from a database, this gets messy. I know Spring AOP can be used for this, but I couldn't get it to work (using Play! framework, another line of experimentation) and it seems quite messy and magical.
Do we instead keep DAOs (repositories?) completely separate, on par with stateless business logic services? This can make some sense, but it means that if "save" or "delete" are inherent operations of a domain object, the domain object can't express those.
Do we just dispense with DAOs entirely and use JPA to let entities manage themselves.
Herein lies the next subtlety: It's quite convenient to map entities using JPA. The Play! framework gives us a nice entity base class, too, with operations like save() and delete(). However, this means that our domain model entities are quite closely tied to the database structure, and we are passing objects around with a large amount of persistence logic, perhaps all the way up to the view layer. If nothing else, this will make the domain model less re-usable in other contexts.
If we want to avoid this, then we'd need some kind of mapping DAO - either using simple JDBC (or at least Spring's JdbcTemplate), or using a parallel hierarchy of database entities and "business" entities, with DAOs forever copying information from one hierarchy to another.
What is the appropriate design choice here?
Martin
Your questions and doubts ring an interesting alarm here, I think you went a bit too far in your interpretation of a "rich domain model". Richness doesn't go as far as implying that persistence logic must be handled by the domain objects, in other words, no, they shouldn't know how to save and delete themselves (at least not explicitely, though Hibernate actually adds some persistence logic transparently). This is often referred to as persistence ignorance.
I suggest that you keep the existing DAO injection system (a nice thing to have for unit testing) and leave the persistence layer as is while trying to move some business logic to your entities where it's fit. A good starting point to do that is to identify Aggregates and establish your Aggregate Roots. They'll often contain more business logic than the other entities.
However, this is not to say domain objects should contain all logic (especially not logic needed by many other objects across the application, which often belongs in Services).
I am not a Java expert, but I use NHibernate in my .NET code so my experience should be directly translatable to the Java world.
When using ORM (like Hibernate you mentioned) to build Domain-Driven Design application, one of good (I won't say best) practices is to create so-called application services between the UI and the Domain. They are similar to stateless business objects you mentioned, but should contain almost no logic. They should look like this:
public void SayHello(int id, String helloString)
{
SomeDomainObject target = domainObjectRepository.findById(id); //This uses Hibernate to load the object.
target.sayHello(helloString); //There is a single domain object method invocation per application service method.
domainObjectRepository.Save(target); //This one is optional. Hibernate should already know that this object needs saving because it tracks changes.
}
Any changes to objects contained by DomainObject (also adding objects to collections) will be handled by Hibernate.
You will also need some kind of AOP to intercept application service method invocations and create Hibernate's session before the method executes and save changes after method finishes with no exceptions.
There is a really good sample how to do DDD in Java here. It is based on the sample problem from Eric Evans' 'Blue Book'. The application logic class sample code is here.
Should entities have behavior? or not?
Why or why not?
If not, does that violate Encapsulation?
If your entities do not have behavior, then you are not writing object-oriented code. If everything is done with getters and setters and no other behavior, you're writing procedural code.
A lot of shops say they're practicing SOA when they keep their entities dumb. Their justification is that the data structure rarely changes, but the business logic does. This is a fallacy. There are plenty of patterns to deal with this problem, and they don't involve reducing everything to bags of getters and setters.
Entities should not have behavior. They represent data and data itself is passive.
I am currently working on a legacy project that has included behavior in entities and it is a nightmare, code that no one wants to touch.
You can read more on my blog post: Object-Oriented Anti-Pattern - Data Objects with Behavior .
[Preview] Object-Oriented Anti-Pattern - Data Objects with Behavior:
Attributes and Behavior
Objects are made up of attributes and behavior but Data Objects by definition represent only data and hence can have only attributes. Books, Movies, Files, even IO Streams do not have behavior. A book has a title but it does not know how to read. A movie has actors but it does not know how to play. A file has content but it does not know how to delete. A stream has content but it does not know how to open/close or stop. These are all examples of Data Objects that have attributes but do not have behavior. As such, they should be treated as dumb data objects and we as software engineers should not force behavior upon them.
Passing Around Data Instead of Behavior
Data Objects are moved around through different execution environments but behavior should be encapsulated and is usually pertinent only to one environment. In any application data is passed around, parsed, manipulated, persisted, retrieved, serialized, deserialized, and so on. An entity for example usually passes from the hibernate layer, to the service layer, to the frontend layer, and back again. In a distributed system it might pass through several pipes, queues, caches and end up in a new execution context. Attributes can apply to all three layers, but particular behavior such as save, parse, serialize only make sense in individual layers. Therefore, adding behavior to data objects violates encapsulation, modularization and even security principles.
Code written like this:
book.Write();
book.Print();
book.Publish();
book.Buy();
book.Open();
book.Read();
book.Highlight();
book.Bookmark();
book.GetRelatedBooks();
can be refactored like so:
Book book = author.WriteBook();
printer.Print(book);
publisher.Publish(book);
customer.Buy(book);
reader = new BookReader();
reader.Open(Book);
reader.Read();
reader.Highlight();
reader.Bookmark();
librarian.GetRelatedBooks(book);
What a difference natural object-oriented modeling can make! We went from a single monstrous Book class to six separate classes, each of them responsible for their own individual behavior.
This makes the code:
easier to read and understand because it is more natural
easier to update because the functionality is contained in smaller encapsulated classes
more flexible because we can easily substitute one or more of the six individual classes with overridden versions.
easier to test because the functionality is separated, and easier to mock
It depends on what kind of entity they are -- but the term "entity" implies, to me at least, business entities, in which case they should have behavior.
A "Business Entity" is a modeling of a real world object, and it should encapsulate all of the business logic (behavior) and properties/data that the object representation has in the context of your software.
If you're strictly following MVC, your model (entities) won't have any inherent behavior. I do however include whatever helper methods allow the easiest management of the entities persistence, including methods that help with maintaining its relationship to other entities.
If you plan on exposing your entities to the world, you're better off (generally) keeping behavior off of the entity. If you want to centralize your business operations (i.e. ValidateVendorOrder) you wouldn't want the Order to have an IsValid() method that runs some logic to validate itself. You don't want that code running on a client (what if they fudge it. i.e. akin to not providing any client UI to set the price on an item being placed in a shopping cart, but posting a a bogus price on the URL. If you don't have server-side validation, that's not good! And duplicating that validation is...redundant...DRY (Don't Repeat Yourself).
Another example of when having behaviors on an entity just doesn't work is the notion of lazy loading. Alot of ORMs today will allow you to lazy load data when a property is accessed on an entities. If you're building a 3-tier app, this just doesn't work as your client will ultimately inadvertantly try to make database calls when accessing properties.
These are my off-the-top-of-my-head arguments for keeping behavior off of entities.
I have some event handler on a boundary class that manages a persistence mechanism for a given generic transaction:
void MyBoundaryClass::MyEventHandler(...)
{
//retrieve stuff from the UI
//...
//declare and initialize trasaction to persist
SimpleTransaction myTransaction(.../*pass down stuff*/);
//do some other checks
//...
//declare transaction persistor
TransactionPersistor myPersistor(myTransaction, .../*pass down connection to DB and other stuff*/);
//persist transaction
try
{
myPersistor.Persist();
}
catch(...)
{
//handle errors
}
}
Would it be better to have some kind of TransactionManager to wrap SimpleTransaction and TransactionPErsistor objects?
Is there any useful rule of thumb to understand if I need a further level of encapsulation?
At the moment the rule of thumb I follow is "if the method gets too big - do something about it". It is hard sometimes to find the right balance between procedural and object oriented when dealing with boundary event handlers.
Any opinion?
Cheers
Considering that:
the concept of encapsulation is about defining a container, and
object-oriented design is based on the concept of message passing (invocation of methods)
I would argue that the API is a good indication about the pertinence of a new high-level encapsulation (I.e. the definition of a new object)
If the services (i.e the API) offered by this new object are coherent, and are better exposed to the rest of the program when regrouped in one special object, then by all means, use a new object.
Otherwise, it is probable an overkill.
Since you expose a public API by creating a new object, the notion of test may be easier to do within that new object (and a few other mock objects), rather than create many legacy objects in order to test those same operations.
In your case, if you want to test the transaction, you must actually test MyEventHandler of MyBoundaryClass, in order to retrieve data from the UI.
But if you define a TransactionManager, that gives you the opportunity to lower coupling of different architecture levels (GUI vs. data) present in MyBoundaryClass, and to export data management into a dedicated class.
Then, you can test data persistence in independent test scenario, focusing especially on limit values, and database failure, and not-nominal conditions, and so on.
Testing scenario can help you refine the cohesion (great point mentioned by Daok) of your different objects. If your tests are simple and coherent, chances are that your objects have a well-define service boundary.
Since it can be argued that Coupling and Cohesion are two cornerstones of OO Programming, the cohesion of a new class like TransactionManager can be evaluated in term of the set of actions it will perform.
Cohesive means that a certain class performs a set of closely related actions. A lack of cohesion, on the other hand, means that a class is performing several unrelated tasks. [...] the application software will eventually become unmanageable as more and more behaviors become scattered and end up in wrong places.
If you regroup behaviors otherwise implemented in several different places into your TransactionManager, it should be fine, provided that its public API represent clear steps of what a transaction involves and not "stuff about transaction" like various utility functions. A name in itself is not enough to judge the cohesiveness of a class. The combination of the name and its public API is needed.
For instance, one interesting aspect of a TransactionManager would be to completely encapsulate the notion of Transaction, which would :
become virtually unkown by the rest f the system, and would lower coupling between the other classes and 'Transaction'
reinforce the cohesiveness of TransactionManager by centering its API around transaction steps (like initTransaction(), persistTransaction(), ...), avoiding any getter or setter for any Transaction instance.
Elaborating on VonC's suggestion, consider the following guidelines:
If you expect to invoke the same functions elsewhere, in the same way, it's reasonable to encapsulate them in a new object.
If one function (or one object) provides a set of facilities that are useful individually, it's reasonable to refactor it into smaller components.
VonC's point about the API is an excellent litmus test: create effective interfaces, and the objects often become apparent.
The level of encapsulating should be directly linked to the cohesion of your object. Your object must do a single task or must be divided in multiple class and encapsulate all its behaviors and properties.
A rule of thumb is when it's time to test your object. If you are doing Unit Testing and you realize that you are testing multiple different thing (not in the same area action) than you might try to split it up.
For you case, I would encapsulate with your idea of "TransactionManager". This way the "TransactionManager" will handle how transaction works and not "MyBoundaryClass".