Categories
Development

SOA Myths

I did tweet this, but it was just so spot on I had to put it up here. You can read the full 7 SOA myths article here. Some highlights:

  • SOA is a way of thinking about integration, not a product.
  • Semantic coupling will always be difficult regardless of the integration technology you use.
  • Discover the services through use of the systems, not by up front design.
  • SOA is a continuous process that will never get done.
Categories
Development

Repository pattern and the domain

Ever since I read the Domain Driven Design book by Eric Evans I have been wondering a bit about the Repository pattern. Especially the part where a domain object can communicate with a repository. In most Java systems today you will have Hibernate with lazy loading which enables you to think in domain objects, but there might be some situations where you can’t do that. That’s when you need to think about the Repository pattern and how to use it. Reasons for using it might be:

  • Large collections, you need to filter before loading for current operation
  • External data, it is only available through calling a webservice etc. meaning Hibernate won’t handle the lazy loading for you

So basically you will need to do this in most systems some time, how do you solve this? I had a discussion about this with Johannes a while back, and we didn’t really reach a conclusion. There are several ways to handle this and they all have their benefits and problems. Terminology and some more ideas borrowed from Ben Hutchinson in this post.

Independent domain

The domain has no notion about repositories, but navigate through properties in the domain. This can be achieved through:

  1. Always passing enough data into methods so the object can make it’s decisions. This can bloat the signature and be a bit of a hassle, but probably the way to go with least magic.
  2. AOP on the methods that retrieve the data. This enables you to have just plain Java for tests, but enable a different retrieval at runtime. Complicates the understanding and testing of the system, but eases unit testing.
  3. Events in your persistence layer. When Hibernate loads up an object for you it could inject the external object. Sort of  light weight AOP, but not something I think I would do.

Co-dependent domain

The domain knows that it must retrieve information through a service/repository and calls it when it’s needs the information. It can be achieved through:

  1. Passing the service/repository in with the method call. Again bloats the methods, but is explicit.
  2. Using a Locator to get the service/repository. The dreaded ServiceLocator from Java EE is back! 😉 But it might have a worse reputation than it deserves. A Locator that checks the ThreadLocal and knows how to retrieve the repository is quite flexible even in Tests. Not very expressive on how and where the information can be found.
  3. Passing the context in the method calls. Just about the same as passing the service/repository, just another level of indirection that I don’t like.
  4. Injecting the repository/service into the object before execution. Somewhat like a middle ground between the Locator and passing it in as an argument.

Choosing

It’s like everything else in computer science, you need to decide what works best in your project. I do however prefer the Independent Domain with passing in the required data in the method. I guess the reason for this is the uttrely horrible code I have seen before where domain and repositories/services are mixed together. A lot of programmers will tend to create integration tests when faced with testing domains that has dependencies to repositories. In many cases that means loading your Spring context waaaay too often, or mocking the repository. And neither are really good unit tests, as well as beeing harder to maintain. I hate mocking even though I have to do it often. I just try to avoid it if I can by designing logic that is independent of infrastructure.

Other references

Categories
Development

The new guy and his database

This is a followup to two previous articles about Agile databases and Migrations for Java. It tries to examplify some of the stuff I talk about in those two articles. Here we go again… 🙂

You won’t get a new developer each week, but the scenario will help illustrate how the tools I have been talking about works. The examples below are loosely based on the previous setup we had in a previous project, but should be general enough to give you an idea. This basically means SubVersion, Maven, Oracle and Ant.

So you have a new developer. Let’s call him John. He’s quite nervous the first day of work, and you wan’t to pair program with him to get him right into coding. Sure he could read the architecture documents, but you will touch upon most of the architecture by working together, so you’d rather just get started.

You sit down with the new developer, and tell him to check out the project from SubVersion.

svn co http://companyrepo/project/trunk project-trunk

The checkout pulls down several Maven projects, with a common parent POM. First things first, so you compile everything and make sure he can use it in Eclipse.

mvn install eclipse:eclipse -DdownloadSources=true

Depending on your location downloading dependencies can take a while. So showing him the coffe machine would probably be a good thing right about now. Everything compiles, and he imports it all into Eclipse.

Now he is eager to have a look at the application, but like most applications your application needs a database. You could probably have settled for HsqlDB or H2 in a test setting, but I prefer to do manual testing on the product that we are actually going to deploy to in production.

So you need to initialize a database. One of the sub-projects you checked out earlier is actually a separate database project. Inside this project is a folder where the scripts for the database resides. On your wiki he finds a description on how to initialize a new database. From the base project he does:

  1. cd dbproject/src/sql/baseline
  2. sqlplus sysadm/syspw@//db:1521/service @create_new_schema.sql johnuser testpw
  3. sqlplus johnuser/testpw@//db:1521/service @baseline_data.sql
  4. sqlplus johnuser/testpw@//db:1521/service @test_data.sql
  5. cd ../../ (takes him to the dbproject folder)
  6. ant dbdeploy-upgrade -Ddb.user=johnuser -Ddb.pw=testpw -Ddb.host=db -Ddb.service=service

Now John has a fully functional database that he can use as his local sandbox for development. I guess a little bit of explaining is in order. In the lines above with sqlplus commands, the first parameter is connection settings. The second parameter is the script to execute, and everything after that are parameters to the script. On line 2 the script uses the inputs to create a user and schema called johnuser and with the testpw password. It also creates tables, triggers, functions etc.

After creating the complete schema in line 2, the baseline data is inserted. I am not sure if this is a good term, but by baseline data I mean data that needs to be there for the system to operate, and don’t change during normal processing. You might have a admin interface to change it, but for most of the time they stay the same. This could be tables holding countries or postal codes.

After inserting some baseline data, it is time to insert some test data in step 3, such that John has something to experiment with right out of the box. This is separated in a script because not all environments will need those data.

The last step is done to upgrade the database to the latest version. See the migrations article for an explanation of the concept. This means that the baseline script is not updated with changes all the time. Every now and again we generate a new baseline from the production database, so we can delete some of the old migrations. Generating a new baseline is something I havn’t really found a good tool for yet, so I get the DBA to do it with some of his tools. It happens rarely enough that for now, I accept that it’s not automated.

That really is the last part of my database articles for now. It is a topic I will probably write more about later as it is something that has been handled poorly in most projects I haven been in. It is also an important part of what I like to call agile deployment that helps us reduce the time spent on deploying, and fixing all those pesky little errors we do when deploying.