Showing posts with label domain-driven design. Show all posts
Showing posts with label domain-driven design. Show all posts

Wednesday, November 10, 2010

Is Open Session in View an AntiPattern?

A friend of mine pointed me to a willingly provocative article that describes Open Session in View as an AntiPattern. After sharing some thoughts with him, I've decided to post them here.

I agree on the N +1 queries problem, but unless (and until) you have devastating impacts on performances I would not worry about it, applying a YAGNI approach. On the other hand, if a view requires a lot of fetches maybe DTOs come in useful (and I would suggest Dozer). This also semplifies the objects exposed, thus hiding from the "high" layers of the application all the complexities that exist within the domain.

Personally, one of the reasons for which I found Struts 1 frustrating - yet much better than the proprietary framework we were using at the time - was the need for form beans, which lead to tons of duplications (no Dozer yet, a long time ago in a galaxy far far away we only had some Commons Beanutils) which is normally bad. OK, forget the "normally" part.

As a general rule I think that exposing domain objects can be accepted if and only if they are true domain objects, not beans with a bunch of setters and getters and transaction scripts in disguise, otherwise you could bypass many of the application logics and end up with an unmanageable mess.

And, talking about layers leaking, I would also like to quote a couple of sentences from the Domain-Driven Design Using Naked Objects book which I suggest as a very interesting and useful reading:

It takes real skill to ensure the correct separation of concerns between these layers, if indeed you can get an agreement to what these concerns really are. Even with the best intentions, it's all too easy for custom-written layers to blur the boundaries and put (for example) validation in the user interface layer when it should belong to the domain layer. At the other extreme, it's quite possible for custom layers to distort or completely subvert the underlying domain model.


The leaking of the persistence layer is not good per se, but if it does not become a problem you can live with it. As always, it depends on circumstances: why should a spend an incredible amount of resources (which means time and money) to obtain perfect isolation if I don't need it?

In general I think Open Session in View to be a good solution to manage database connections, but it would be even better leverage this strategy with join fetch queries for the most important relations. After all, when writing a service or a facade we know what objects will be needed: this does not mean that the domain or the controller should depend on the presentation layer (they must not!), but pretend that we don't know anything about it is just a waste of time. So, for example, if our facade has a result factory this could be a nice place to eagerly load all objects we know the presentation layer will need; if the view still needs more objects the open session can provide them on the fly: in this way we can optimize the most important parts and live with the rest.

Monday, September 27, 2010

On repositories

I was writing code for a (actually not so) massive data export in a legacy application and I needed to retrieve all objects of a certain type modified after a given date, so I started writing a repository.

The simplest test that came into my mind was something like this:
@Test
public void queryingWithDateInTheFutureReturnsEmptyList(){
DateTime tomorrow = new DateTime().plusDays(1);
List<MyObject> result = instance.findModifiedAfter(tomorrow);
assertTrue(result.isEmpty());
}
Some clickety-clack (SHIFT+CTRL+I, ALT+SHIFT+F, CTRL+s, CTRL+F6 for the most curious) and NetBeans gives me a red bar. That's good as there's no code yet :-)

The first implementation was really too easy to write it, but as a very few people believe I work this way and all the rest think I'm wasting time I'll publish it anyway, saving my opinion for another occasion:

public List<MyObject> findModifiedAfter(DateTime startDate){
return Collections.emptyList();
}
So far, so good. Now, in the framework used in this project all persistent objects inherit from MyPersistenceObject (names have been changed to protect the innocents), which is a sort of Active Record with a hint of Row Data Gateway. Persistent object may also be managed by a MyPersistenceObjectController object, which is a sort of DAO that also manages transactions. Should you wonder, the class is not a controller at all, but the original developers thought that the name would fit. Before we go on, let me say that the framework works pretty well under many circumstances.

Not having a dedicated database that gets populated for each test end cleaned afterwards (did I mention the fact that this is a legacy application?) the next test tried to retrieve some data:

@Test
public void queryingSinceLastMonthReturnsAtLeast5kObjects(){
DateTime lastMonth= new DateTime().minusMonths(1);
List<MyObject> result = instance.findModifiedAfter(lastMonth);
assertTrue(result.size() > 5000);
}

I know it's not great, and that it breaks if someone truncates the corresponding table, but we must start from somewhere, right? Reading the tests also suggests that the method should probably be named findModifiedSince, but that is hardly the point now - even if it shows another useful feature of writing tests.

A little lookup on the existing code easily gave me a first implementation based on the "glorious" copy-paste-fix pattern:

public List<MyObject> findModifiedSince(final DateTime date) {
if (date == null || date.isAfterNow()) {
return Collections.emptyList();
}

try {
Object[] values = new Object[]{date.getMillis()};
String[] orderBy = null;
Criteria criteria = new Criteria("tms", "MyObjectImpl");
SimpleCondition simple = new SimpleCondition("tms", SimpleCondition.GE);
criteria.add(Criteria.NOP, simple);
Vector objects = new MyObjectImpl().retrieveByAlternateKey(
criteria,
values,
orderBy);
List<MyObject> result = new ArrayList<MyObject>();
result.addAll(objects);
return result;
} catch (Exception ex) {
return Collections.emptyList();
}
}
Clickety-clack, CTRL+F6...

...
...
(yawn)
...
...
(wtf?)
...
...

Green bar. After an insane amount of time. A little logging informed me that the test took 16 seconds to run, excluding the time needed to start and stop the persistence container.

A little profiling confirmed that also the memory usage grew abnormally. And all this for a little more than 6000 objects...

Now, to quote Eric Evans, a repository is

...an object that can provide the illusion of an in-memory collection of all objects of that type.

Well, this framework cannot provide that illusion, at least not whithout freezing everything else. I must admit that lately I was quite in clover, as using Hibernate I could simply write the very same method like this:


public List<MyObject> findModifiedSince(DateTime date) {
return HibernateUtil.getSession().
createCriteria(MyObject.class).
add(Restrictions.ge("tms", date)).
setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).
list();
}
and get my list, which is actually a list of proxies, in about no time. Now Evans says that repositories

...return fully instantiated objects or collections of objects whose attribute values meet the criteria, thereby encapsulating the actual storage and query technology.

Proxies are not exactly fully instantiated objects, but as they pretend to be I'm prepared to live with that :-)

At this point all I could do was to revert to the old give-me-the-ids-and-I'll-get-the-objects-myself :-(

Wednesday, February 24, 2010

How to create a simple Naked Objects Application in NetBeans

Naked Objects is an open source application framework that lets you concentrate on domain objects and automagically generates a GUI for interacting with them. This sounds (and actually is) very interesting, as the domain is what we should most interested in, instead of boilerplate, as everybody who is fond of DDD knows.

Being NetBeans my favourite IDE, as you might have suspected, I'll try to jot down some notes on how to use it to create a very simple Naked Objects application.

First things first, you have to download the Naked Objects framework; you have various options, I chose to download the zip file for Ant. After unzipping the file you should find a folder named lib that contains - o great wonder and surprise - all the necessary libs.

As I suppose I could use all this stuff in more than one project, I created a new library in NetBeans:


Click on the New Library... button and you'll be prompted a library name and type


Then click on the Add Jar/Folder... button and add all the jars in the lib folder. You should get something like this:


Ok, now we can proceed to creating a new application. As a disclaimer, this is not necessarily the best way to do it, but it is how my inner cogs work (or don't work). If yours are different, you'll have to compose all the pieces of the puzzle in a different order.

Let's suppose we want to use the DnD GUI, so I go with a new Java Application:


Click on the Next> button and enter a name for your project; don't use a dedicated folder for libraries and don't have the IDE create a main class for you.


Click on the Finish button. Ok, now we should instruct our project to be a Naked Object Application. Right click the Libraries node to add all necessary references:


Select the library you've previosly created and you're almost ready to go.

Now, if you try to run the application NetBeans complains because you have not chosen a Main Class. Right click the project node and the Run node in the Categories tree, and insert org.nakedobjects.runtime.NakedObjects as the Main Class.


Click on the OK button. Ok, now we can try to run the application... just to get another complain


Exception in thread "main" org.nakedobjects.metamodel.commons.exceptions.NakedObjectException: failed to load 'nakedobjects.properties'; tried using: [file system (directory 'config'), file system (directory 'src/main/webapp/WEB-INF'), context loader classpath]

It seems fair... after all we have to provide some configuration. Create a new properties file, name it nakedobjects and put it in the config folder. Obviously this is not enough, and you can check it yourself trying to run the application: NetBeans will complain again (don't shoot the messenger) about the lack of services.

To define services, we have to write some code. Let's suppose we want to deal with all Walt Disney characters - I hope there are no legal issues with this - so let's create a class that represents one:


package it.moz.noapp;

import org.nakedobjects.applib.AbstractDomainObject;
import org.nakedobjects.applib.annotation.DescribedAs;
import org.nakedobjects.applib.annotation.MemberOrder;

@DescribedAs("Character")
public class Character extends AbstractDomainObject {

private String firstname;
private String lastName;

@MemberOrder(sequence = "1")
public String getFirstname() {
resolve(firstname);
return firstname;
}

public void setFirstname(String firstname) {
this.firstname = firstname;
objectChanged();
}

@MemberOrder(sequence = "2")
public String getLastName() {
resolve(lastName);
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
objectChanged();
}

public String title() {
return getFirstname() + " " + getLastName();
}
}

Notice how this class, that is a domain object, extends the class AbstractDomainObject provided by the framework. The annotation @DescribedAs tells you how the object will be referred to in the GUI, while @MemberOrder defines the order in which members are presented. You can find every detail on the Naked Objects website.

The next step is telling our application that such a domain object exists, so we'll add the following line in our nakedobject.properties file:

nakedobjects.services=repository#it.moz.noapp.Character

Ok, let's start the application...


uh oh... User name and password? ehrm... let's provide the application with them! The problem is that if you want to add an empty file - unlike for properties files - NetBeans asks you whether you want to add it to the src folder or to the test folder, i.e. the folders (already) defined in the project. As you want neither, you must manually add an empty passwords file to the config folder. Before complaining about NetBeans, keep in mind that you can always define the config folder as a new source package folder, but let's skip this option.

Fill in a username and a password...
user:pass
And that's it, you can start your application!


To create a new instance you right-click the Characters icon and select the appropriate item from the drop down list, insert the desired values and here's your brand new character. Rinse and repeat and you'll get something like this:


As you can see, you now have a Disney Character directory without having written a single line of code but your domain class.

Unluckily, if you close your application all your efforts have been vain, so you should add the support for persistence. But this will be the subject for another post...

Thursday, July 23, 2009

First Iteration in itinere

For the second time in the sprint - but the first one does not count because we merely cut funcionalities that were not needed anymore - our Burndown chart clearly express what everybody has felt in the last weeks, even if it was unsupported by facts (at least until yesterday): we will deliver.


Once more I'd like to stress the importance of such a tool: we always know what is going to happen, and we can take informed decisions.

As I said, the first big slope is a cut due to a modification of the contract; the second came after most architectural decisions had been tested and taken, just as expected. For this first iteration we choose the part of the system we knew best and that - not by chance - is the basis upon which we will build the whole system. Nevertheless, we mostly focused on architecture, even if we will deliver actual funcionality. The project follows a test driven approach and a domain driven design, and we just anticipated a little more than we needed at the time because we know we will need it within a couple of months (so the YAGNI thing does not apply here).

So the bar is green, our Hudson happily smiles and so do I; first demo next week, maybe more on this after the retrospective.

Friday, November 14, 2008

Stakeholders and Requirements

Use cases are a widespread adopted technique for recording requirements. One of the sections (in the Cockburn format) is named "Stakeholders and Interests", and it reports... stakeholders AND interests. ALWAYS use it. Forget a stakeholder and you'll miss his interests, and as you can guess this is NOT good.

Cockburn uses a candy machine as an example: you interact with a candy machine to get a candy, so you're the user. If the manufacturer did not hold into account the interests of the seller (make money out of selling you candies) the candy machine would not ask you any money, but would give you free candies. That would make you happy, but it would make the seller unhappy. It would be very expensive to recollect all the candy machines on the market, go back to design, build new machines and redistribute them, let alone all the free candies gone with the wind.

The same happens with software, and it is a worse phenomenon as it is much easier to forget a stakeholder.

I recently witnessed a situation in which the headquarter superimposed a software to other offices without taking into account the real needs of the final users (yes, it holds for both extremes) but oversimplifying the business model. That was not an act of power nor stupidity, it simply was what they thought was best - and they had their reasons. Unluckily now they're back to formula, and a meeting has been scheduled to gather more requirements that can satisfy these stakeholders. Everyone would have saved a lot of time, and a lot of money as well (as one of the latest activities was an almost pointless meeting with more than twenty managers).

The problem was magnified by the fact that the software was a tool to use in a change management process, namely the first step to computerization and standardization of workgroup activities, which is already noteworthy per se. And, as change management involves people, it is never easy nor simple, as people normally resist changes. This time the persons involved (that were stakeholders AND users) did not understand the message (one of the reasons for resistance) because it was not conveyed in their language, and that brings us to another consideration.

Eric Evans asserts that everyone involved in a project should speak the very same language (he calls it "Ubiquitous Language"), and that a great investment has to be done in discovering and defining it: it will definitely pay off. Do it. It is the language that drives development, understand the language and you'll understand the requirements, thus you'll deploy more suitable software.

So to summarize: do not forget any stakeholder AND find a common language.

Tuesday, July 8, 2008

Divide et impera

Following this ancient rule (and Uncle Bob's suggestions) we recently separated our new development effort into four subproject, each of which focuses on a particular aspect of the whole project. The separation is also based on the techniques for splitting the different domain aspects explained in DDD.

Everything has been integrated in Hudson, with the Cobertura, Open Tasks and Violations (with PMD) plugins.

We still have to reintroduce JDepend, but we'll do it in a short while.

Tuesday, March 18, 2008

To agile or not to agile?

Today I really feel the urge to quote what Uberto said in the JUG Milano mailing list - and forgive me if something gets lost in the translation process - the original had a deeper stroke on people's imagination.

"Blockheads, agile or not, will never produce good code, just as even if you can produce the best software in the world but you don't understand the domain your project is doomed: technical success is a foolish illusion."

Thursday, February 28, 2008

Domain-Driven Design? now you can have it quickly

Eric Evans is the author of Domain Driven Design, a text which explains the importance of having a software closely related to the real domain it models; the book presents best practices, principles and techniques based on real experience.

I found it challenging but very interesting, but one friend of mine found it thick as a brick. Luckily for M. (and I'm sure for many other people out there) InfoQ has released Domain Driven Design Quickly, which does not introduce new concepts but summarizes the essence of what DDD is, drawing mostly on Evans' book as well as other sources.

You can download a free online version, but you are invited to support the work and buy a print copy.