The Corporate Developer
Application versus Business Requirements
First and foremost, I don't think there is any emphasis on being able to seperate business requirements and application requirements. To most developers, they are all lumped as one and efficiently categorized in layers and facades. For example, requirements that dictate the validity of orders must be carefully scrutinized so that you can draw the line between what is required for some purchasing application and what is actually intrinsic to the company's operation.
The reason for splitting business and application requirements is for reusability. What behaviors are global and can be reused on other projects while what behavior only helps define the application you are currently writing. I've seen too many programs written that put business logic in their Struts actions (I'm at fault too), then re-written in other applications. If business rules suddenly need to be changed, you now have to maintain these rules in two or more deployed applications.
The corporate developer must be very aware of the differences and seek out their company's business analysts for the answers. The other resolve is that requirement specifications should be categorized into application and business requirements. Some may argue that simple facades are the solution, but we are not talking about layers, we are talking about domains and deployment-- issues that are really only discussed at the enterprise level.
In the following, I will try to describe a bit on how to handle business requirements, and then application requirements, followed by a small rant on persistence solutions.
I can't help but to use cliché terminology from here on out, but hopefully some of my opinion will make some sense. In the business domain, the key is reusability. This is done though by creating stateless services that offer procedural behavior and beans that only provide state.
I want to start with business rules and behavior. The new hot topic is Service Oriented Architecture. The idea is to build stateless services, modeled as functions that reflect business rules or expose business data. The goal is not only to serve behavior to the innards of your applications, but also provide data to desperate systems where the protocol may be RPC, SOAP, CSV, or just XML. In this case, providing a service layer (that acts like a DAO) would now be useful in a case by case basis (I don't care for DAO's which I will get into later).
Since services now model business rules and behavior, how do they work with data? My suggestion is to keep behavior out of the beans your persistence mechanism works with. Since services may work with both Java beans and SQL datasources, try not to add complexity by having services be dependent on behavior provided by the beans they recieve or gather. Another reason to have services work with behaviorless beans is that behavior can't easily be transferred in a CSV file or XML. To sound like a broken record, the goal is reusability and protocol independence.
In summary, there are few points:
- Stay away from writing lots of DAO services that encapsulate your relatively static database models. Again, more on this in the section on persistence.
- Within the business domain, data objects are behaviorless. This is so the same object can be exposed through other protocols and business services are never dependent on behavior offered by objects during service collaborations.
- Define simple services in Java code that could theoretically be tested in a number of deployments. This means accessed directly within Java applications, or deployed with Axis for use with SOAP RPC, etc. Another rule of thumb is that services should only take in a single parameter to encapsulate change
The business domain offers us behavior through stateless services and beans that represent the state of our datasources. It is now the application's job to script collaborations between behavior and state. The best pattern to handle this is the domain model. Notice I've pushed the use of a domain model out of the business domain and into the application domain. Core J2EE patterns calls these Business Objects, which is kind of a misnomer in my humble opinion. In collaborating state and behavior, there are other issues that arise such as stale data and transaction management to name a few. A lot of these requirements are often defined on a per application basis and cannot be modelled globally for all concerns within the business domain.
An example would be pulling up and working with a purchase order. The controller layer accesses a service or persistence layer in order to gather an object reprentative of "OrderData". To now provide application behavior, the "OrderData" is wrapped in a domain object called "OrderSession". Within "OrderSession", it collaborates between business services and the state it was provided or gained in order to serve the requirements of the application.
Another requirement would be now validating that order. How and when does it get validated? The 'how' is probably a primary business requirement that defines what the business requires to be able to process an order. This means you may want to create an OrderValidation service that can be exposed or deployed with applications. The second issue was 'when' does the order get validated? This is going to be an application requirement. The when and how together are dictated by your domain model, or to use the example above, within the "OrderSession".
Applications should be free define their own services. These application services often use the transaction script pattern to collaborate between business services in order to serve an application requirement in a procedural manner. Even within domain objects, application behavior should be delegated to services or procedures that aren't locked within a single object.
To summarize the application domain:
- The application domain relies heavily on domain objects to model collaboration between business services and state in order to serve the application's requirements on a case by case basis.
- Domain objects themselves should delegate state to reusable, purely stateful objects and behavior to reusable, stateless services.
One of the biggest wastes of time developers get into is trying to model the whole business in a series of reusable objects. I did mention using behaviorless objects within the business domain and application domain, but no where did I discuss the importance of a single object model. The reason? Can an order from your handheld application always be the same order that's used in your web sales application? Do all services require the same data from an order? Some parts of your applications may only require an account number, while in other cases an order would be expected to have an account object. Get over trying to model the business in a beautiful collection of aggregate objects, it doesn't work for large companies.
Often times the solution for persistence is a layer of DAOs. I'm actually not a big fan of DAO's. DAO's could be considered a subset or type of service in implementation, and to have a all DAO calls done through a seperate service facade is unecessary for the most part. Also, since DAO's define procedures (representative of a single requirement), they lead not only to bloat but also can add unecessary restrictions to your databases intrinsic business model and the data it contains.
The solution is to examine technologies like Hibernate or JDO and to work with them directly in an "open" manner. These technologies are basically an alternative to straight JDBC, and let's be frank, database's information is where most business make all their money. Why restrict access to it with DAO's and extra facades? The goal is to be able to openly gather the data you need on a case by case basis that most optimally suits the requirement.
You may be thinking about encapsulation at this point, which I'm not saying is bad, just don't try to encapsulate all database access into a golden object model. We want to find a solution that freely allows you to discriminate data without a Java model to conform to everytime, and that's the key point here. Re-evaluate the logic of taking the database model and conforming to an aggregate object model only to produce composite objects for some other application model that's probably a truer representation of what could have been done with a single SQL query.
Fowler has written a bit on Java and SQL collaboration. Fowler is right in saying that there's been a growing seperation between databases and applications. Again, my simple point is to find a flexible solution like Hibernate or JDO. By allowing your code to freely work with an open framework like that, you can gather just the right information you need at any point. Configuration files for JDO or Hibernate are just as easy to maintain as lots of procedural methods on DAOs.
I've followed up this part with an entry on dual persistence strategies.
Corporate developers must think about the big picture in assessing requirements. What is a global requirement of the business and what is required by this one particular application? Implement business requirements in a transient/stateless manner and use domain models only within the specific requirements of each application.
For those apprehensive about committing to a persistence framework without using a facade, trust me, it's just as likely that your application framework will become outdated way before then. Where I find DAO's and persistence facades useful is where there is a specific requirement to handle any multitude of datasources, but always keep in mind that I'm talking about corporate environments with legacy mainframes and server farms.... but I wouldn't hesitate to model simpler projects the same way.