Archive for the ‘programming language’ Category.

Domain Driven Design, The Repository pattern

I’ve seen so many times a heated discussion about Repositories in Domain Driven Design, there is a kind of misunderstanding and/or confusion about what really a Repository is.

People usually disagree about the role of the Repository, if it should be a kind of  “Data Access Layer”, such as a DAO or if it must be something that is injected in the domain class, then it will talk to the DAO in the beneath layer.

I’ve always wondered why people had these fights, but now I can see why ! The thing is, as far as I read in the book (Chapter 10 : Supple Design),  the examples of Reposotory has been shown almost exactly as a DAO implementation. I even downloaded the source code examples from the Domain Driven Design Community, and the example IS a DAO implementation, as I’m showing below :

package se.citerus.dddsample.domain.model.cargo;

import java.util.List;

public interface CargoRepository {

  /**
   * Finds a cargo using given id.
   *
   * @param trackingId Id
   * @return Cargo if found, else {@code null}
   */
  Cargo find(TrackingId trackingId);

  /**
   * Finds all cargo.
   *
   * @return All cargo.
   */
  List findAll();

  /**
   * Saves given cargo.
   *
   * @param cargo cargo to save
   */
  void store(Cargo cargo);

  /**
   * @return A unique, generated tracking Id.
   */
  TrackingId nextTrackingId();

}

and the implementation

package se.citerus.dddsample.infrastructure.persistence.hibernate;

import org.springframework.stereotype.Repository;
import se.citerus.dddsample.domain.model.cargo.Cargo;
import se.citerus.dddsample.domain.model.cargo.CargoRepository;
import se.citerus.dddsample.domain.model.cargo.TrackingId;

import java.util.List;
import java.util.UUID;

/**
 * Hibernate implementation of CargoRepository.
 */
@Repository
public class CargoRepositoryHibernate extends HibernateRepository implements CargoRepository {

  public Cargo find(TrackingId tid) {
    return (Cargo) getSession().
      createQuery("from Cargo where trackingId = :tid").
      setParameter("tid", tid).
      uniqueResult();
  }

  public void store(Cargo cargo) {
    getSession().saveOrUpdate(cargo);
    // Delete-orphan does not seem to work correctly when the parent is a component
    getSession().createSQLQuery("delete from Leg where cargo_id = null").executeUpdate();
  }

  public TrackingId nextTrackingId() {
    // TODO use an actual DB sequence here, UUID is for in-mem
    final String random = UUID.randomUUID().toString().toUpperCase();
    return new TrackingId(
      random.substring(0, random.indexOf("-"))
    );
  }

  public List findAll() {
    return getSession().createQuery("from Cargo").list();
  }

}

This Repository is used by a class called BookingServiceImpl :

package se.citerus.dddsample.application.impl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.annotation.Transactional;
import se.citerus.dddsample.application.BookingService;
import se.citerus.dddsample.domain.model.cargo.*;
import se.citerus.dddsample.domain.model.location.Location;
import se.citerus.dddsample.domain.model.location.LocationRepository;
import se.citerus.dddsample.domain.model.location.UnLocode;
import se.citerus.dddsample.domain.service.RoutingService;

import java.util.Collections;
import java.util.Date;
import java.util.List;

public final class BookingServiceImpl implements BookingService {

  private final CargoRepository cargoRepository;
  private final LocationRepository locationRepository;
  private final RoutingService routingService;
  private final Log logger = LogFactory.getLog(getClass());

  public BookingServiceImpl(final CargoRepository cargoRepository,
                            final LocationRepository locationRepository,
                            final RoutingService routingService) {
    this.cargoRepository = cargoRepository;
    this.locationRepository = locationRepository;
    this.routingService = routingService;
  }

  @Override
  @Transactional
  public TrackingId bookNewCargo(final UnLocode originUnLocode,
                                 final UnLocode destinationUnLocode,
                                 final Date arrivalDeadline) {
    // TODO modeling this as a cargo factory might be suitable
    final TrackingId trackingId = cargoRepository.nextTrackingId();
    final Location origin = locationRepository.find(originUnLocode);
    final Location destination = locationRepository.find(destinationUnLocode);
    final RouteSpecification routeSpecification = new RouteSpecification(origin, destination, arrivalDeadline);

    final Cargo cargo = new Cargo(trackingId, routeSpecification);

    cargoRepository.store(cargo);
    logger.info("Booked new cargo with tracking id " + cargo.trackingId().idString());

    return cargo.trackingId();
  }

  @Override
  @Transactional
  public List requestPossibleRoutesForCargo(final TrackingId trackingId) {
    final Cargo cargo = cargoRepository.find(trackingId);

    if (cargo == null) {
      return Collections.emptyList();
    }

    return routingService.fetchRoutesForSpecification(cargo.routeSpecification());
  }

  @Override
  @Transactional
  public void assignCargoToRoute(final Itinerary itinerary, final TrackingId trackingId) {
    final Cargo cargo = cargoRepository.find(trackingId);
    if (cargo == null) {
      throw new IllegalArgumentException("Can't assign itinerary to non-existing cargo " + trackingId);
    }

    cargo.assignToRoute(itinerary);
    cargoRepository.store(cargo);

    logger.info("Assigned cargo " + trackingId + " to new route");
  }

  @Override
  @Transactional
  public void changeDestination(final TrackingId trackingId, final UnLocode unLocode) {
    final Cargo cargo = cargoRepository.find(trackingId);
    final Location newDestination = locationRepository.find(unLocode);

    final RouteSpecification routeSpecification = new RouteSpecification(
      cargo.origin(), newDestination, cargo.routeSpecification().arrivalDeadline()
    );
    cargo.specifyNewRoute(routeSpecification);

    cargoRepository.store(cargo);
    logger.info("Changed destination for cargo " + trackingId + " to " + routeSpecification.destination());
  }

}

Well, I cannot deny that I did not dig so deep into the code ( and I did not finish the book ) yet,
but what I can state for sure is that this architecture really looks like this sequence :

Repository Sequence Diagram
Also, the layering :

Layering Repository Diagram
Ok, I know I am over simplifying things here, but my intention is only to communicate my point of view about
the topic. I’m not saying that what is inside this code is wrong at all, I am just skeptical about how “new” or
effective this thing is, because I’ve been developing large scale software systems using the same approach, but with a
different name “DAO”, and so far I could not see anything different from this. I might let you guys twist my arms in the end of the book,
but so far I’m pretty sure the Repository and a DAO pattern are the same thing.

Any idea, suggestions, thoughts and counter-argument are very welcome ! :)

Code Quality

One kind of cancer in software development is undoubtedly the lack of code quality. I’ve seen a lot of simple and complex applications suffering with bizarre algorithms, crazy logic flows, anti-patterns, ugly & unreadable code, and something else I cannot remember right now :)

I believe that code quality must be one of top things a developer must bear in mind. Quality means a lot of different things, such as :

  • your code works perfectly.
  • it does exactly what it is supposed to do
  • it’s testable
  • it’s readable
  • it’s maintainable
  • it’s extensible
  • it has a nice design
  • and more…

Every software project started on earth is to solve a customer problem, and it implies deadlines, pressure, new requirements, more pressure again and so on. But, we can’t let things like business complexity or pressure to affect our code quality, because every little hack left behind will become a dragon in the future, ready to eat us when we are out of the blue. :)

To achieve quality, a software must be simple, that means we should do things as simple as possible, for the sake of these things above. But, unfortunately simple does not mean “easy”. I can show an example of “simple” and “easy” :

I can state a simple development, as a software that is well designed, that has passed through some analysis, that has a good architecture, where the developers use unit tests and so on. It may forces you to spend a little more time to do these things, but the ROI will be that your life will be very simple whenever you try to extend or change your software.

On the other hand, an “easy” way would be to put every code inside the JSP file, or create a strong coupling among your classes and components, don’t respect any design pattern, and all of this for the sake of a “false agility”. But in this case this developer will have a very hard life whenever he or she try to change the software.

So, let’s have a very nice code with high quality !

Why Ruby and Rails are so delightful

Since the first time I typed the first lines of code, Ruby and Rails made me feel good and comfortable. I fell comfortable about the language itself, the syntax, and the amazing simplicity, that I want to show here ;)

Starting with Ruby, I can say that it is a very nice, clear and concise language. Of course I had some hard time, because it’s a dynamic language, that has a different philosophy rather than Java and C#, that by the way are strongly typed languages. They It made me remember my old friend clipper :)

I’d like to show below some nice thing I like in this language, such as a kind of “for”, or manipulating arrays :

10.times do print “Hello, world!” end

resultado : Hello, world!Hello, world!Hello, world!Hello, world!Hello, world!Hello, world!
Hello, world!Hello, world!Hello, world!Hello, world!

x = []
x << “Word”
x << “Play”
x << “Fun”

As I told you before, Ruby is a dynamic language, so, there is no need to assign a type, but if we had to do the same thing in Java we would need it :

String[] x = new String[3];
x[0] = “Word”;
x[1] = “Play”;
x[2] = “Fun”;

Hmmm ok, somebody can ask me “but, what is the difference ?? they look similar !”. To answer this question I can say that they really seems to share the same idea, but it’s wrong. As I told before Ruby is a dynamic language, so, I can rest without having to worry about pre-defined types. Another good point about Ruby is that it provides me some “utility” methods that other languages don’t :

x = ["Word", "Play", "Fun"]
puts x.join(‘, ‘)
resultado : Word, Play, Fun

x = [1, 2, 3, 4, 5]
y = [1, 2, 3]
z = x – y
puts z.inspect
result : [4, 5]

The last thing I want to show today about Ruby is the Interpolation capability, as a piece of code can tell 100 times more than 200 pages, there we go :

x = 5
y = 7
puts “#{x} + #{y} = #{x + y}”
resultado : 5 + 7 = 12

This code blows up my mind ;)

Now, introducing Rails framework, it’s a web framework that was developed using Ruby language, and Rails implements the MVC pattern, and a persistence layer via Active Record. I can tell that SIMPLICITY was what made me love it. I was remembering what I need to develop a web application using Java : JSP, TagLibs, Struts ou JSF, Spring, Hibernate, configure a dozen of XML files and/or annotations, and a lot more, for sure, it’s too much !

It’s hard to deny that the below code is much more simple to write and mantain than all steps above :

class MyClass < ActiveRecord::Base

validate_presence_of :date, :value

validates_numericality_of :value

belongs_to :user

protected

def validate

errors.add(:value, “Should be positive”) if value.nil? || value <= 0

end

end

To summarize, the point here is neither try to prove that Ruby and Rails are the best things in the universe, nor, I’m saying that they gonna be the next plasma cannon to defeat any space invader :)

Instead, I’m trying to point out everything that makes this language and framework so great. Also, Ruby has limitations as any other language, and Rails doesn’t solve some problems, as pointed out by Martin Fowler on his Enterprise Rails post. Anyway, both Ruby and Rails deserve good attention, because they are easy, flexible and very comfortable. I strongly recommend you to try it if you haven’t so far !