The Designer’s Block: The Database Guy…

We have been ignoring this guy for quite sometime now and the poor fellow is burdened with a lot of work. Line count check for the Database Guy – 317 lines right now!  Lets give him a helping hand, some attention like we did for the MyStashService. You shouldn’t find the approach we start of with surprising. Lets make MyStashDB the central point of focus and try doing things based on our learning(s) so far.

As seen over the course of the evolution of MyStashService, we landed up creating an interface IMyStashService which we then further exploded into modular cohesive interfaces (Interface Segregation) that were easy to locate and consume by client programs.  Instead of reaching this point at the fag end of rewriting the Database Guy, lets attempt it first, so that we can worry about its implementation later!

How did we come up with the IStashService, IUserService & ITransactionService? We started wearing the hat of the client program and the focus was to provide an API that was intuitive and easy to use for him. This need for stepping out of what you are designing, and wearing the “caller’s hat” is really true for any Class you write.  It is the heart of what leads to good “Interface Segregation” – knowing what each client program really needs and catering to those needs. It does become quite challenging when you are the person writing the code on both sides, due to implicit assumptions you start making – being in the know of the internals of the other side. Hence, its probably a good idea to do this role play before you have written any code.  It also ties into the notion of TDD – Test Driven Development – the subject that the industry and developers keep raving about. Write your tests first, they say.  Aside from all the other benefits of TDD – it also ensures you first come up with an intuitive client friendly API, assuming that you want to make your tests clean and easy to write and understand.

So, who exactly are these client programs for the Database Guy? That hopefully is a straight forward question to answer – of course the various services. The CreditService, the TransferService, the CreateStashService – that need support from him.

But firstly, lets introduce the IMyStashDB interface so that we don’t really worry about the implementation yet. Quite frankly – am not too keen on using raw SQL over JDBC as my primary data access technology and for that matter, a relational database as my database technology. There are far more powerful, better and easier data access and database technologies out there, I hear. My friend recently mentioned Hazelcast to me – and why not? – this is a learning site – lets learn some of these cool new technologies on the side?

Needless to say – as part of introducing the interface, we should be refactoring all the services (clients) to use the new interface reference rather than the class reference. This would give us the flexibility of changing the implementation – i.e. the kind of database – be it a relational one, a document one or a more generic in-memory one at a later point in time. So, this is what IMyStashDB looks like right now….

public interface IMyStashDB {

    double fetchBalance(
            @NotNull final String stashId)
            throws MyStashDBException;

    void saveBalance(
            @NotNull final String stashId,
            final double balance)
            throws MyStashDBException;

    void saveCredit(
            @NotNull final CreditInfo theCredit)
            throws MyStashDBException;

    void saveDebit(
            @NotNull final DebitInfo theDebit)
            throws MyStashDBException;

    void createStash(
            @NotNull final String name,
            @NotNull final String description)
            throws MyStashDBException;

    void createUser(
            @NotNull final UserInfo userInfo)
            throws MyStashDBException;

}

I wonder where those neat, big super-market sign boards and racks are at? ….. but do we even know what the “needed” signs are? So the question is, how do we go about organizing and simplifying this clutter?

Hey hold on a second! Before we proceed on that line of thinking, did you realize that you just incorporated the Open-Close principle by introducing IMyStashDB? – it just made common sense – you did it so matter-of-factly – “Oh! Lets just put an interfaces so that we worry about implementations later” – read – without having to change any of the service code. You really didn’t need to read up on a more perfect definition of the principle. In fact you didn’t need to read up at all. You just did it naturally. You just made all the services Open-Close with regards to the kind of database that we will eventually use by introducing this new interface for the database guy. Of course, also giving me the much needed breathing space to decide what I shall eventually use for my persistence implementation – we can always just swap out the current one with the one we land up implementing eventually, if we do decide to change it further. The service classes are “Closed” to modifications in this regard, but open to extension, by accepting different implementations of the interface. I say in this regard because, I dare say that making a class “Absolutely Closed” or “Fully Closed” to modifications is probably a myth. There may be exceptions, but who is to say that they will NEVER need to be modified. Someone is going to come along after you and have a different take on the design that is implemented. So the key goal is to keep revisiting it over time as you gain these nuggets of insight and refactor, making them more and more closed. If you recall the post in which we converted the increasing number of arguments of the credit and debit methods into data-structures, that is a step towards making them Open-Close as well. I should say here that, classically examples of Open-Close rely on demonstrations of inheritance, rather than the usage of interfaces. Am sure we will get examples of that as well over the course of time.

Incidentally, what we just did by introducing an interface for the database guy, is also a step towards the Liskov’s Substitution principle or a varied interpretation of it – i.e., being able to send an instance of an implementation/sub-class into code that relies on an interface/base-class. But more on that later ;-).

Okay, coming back to the super-market signs. If you step back, as we always do, and think about it a bit, at a higher level of….. “abstraction”, what really does the database guy really need to help out with?

You could say that the guy is like a store room with shelves of different dimensions, for items of different sizes! Does he really care what the item is? Hmm….may be some aspects of it, like its dimensions and weight so that he can put it on the right shelf that suits the item – any aspect of the item that has to deal with the storage of it.

You can almost imagine an interface something like the following:

public interface IMyStashDB {

    fetch(...) something from the database;

    void insert(...something...) into the database;

    void update(...something...) in the database;

    void delete(...something...) from the database;
}

Going by tradition, lets apply the needs of the CreditService. This would look something like:

public interface IMyStashDB {

    fetch(...) “the balance” from the database;

    void update(...”the balance”...) in the database;

    void insert(...”the creditInfo”...) into the database;
}

Lets do the DebitService next:

public interface IMyStashDB {

    fetch(...) “the balance” from the database;

    void update(...”the balance”...) in the database;

    void insert(...”the debitInfo”...) into the database;
}

It looks like the natural first step is to list the items that need to be stored in the MyStash application and have an interface per item that represents all the persistent operations involving it. In design pattern terms, this is the classic DAO (Data Access Object pattern). So lets list the items so far whose data we would like to insert (create), save, update and delete from a database. We have:

  • the stash – (includes its balance)

  • the credit record

  • the debit record

  • and finally the user

So, IMyStashDB can now be split and made:

the-db-guy-1

But really if you look at the pattern we were chasing up before mentioning the classic DAO pattern semantic – this probably does not make the cut. But for a long time this was the pattern adopted by many software projects alike – basically, have one DAO interface per “entity” that needs to be persisted, the implementation of which would take care of catering to its persistence functionality based on the database technology of choice. This provides some degree of separation between business functionality and persistence implementations. Although, this really results in quite a few similar looking interfaces with create, update, fetch, delete methods – and a lot of redundant code in the implementations.

The pattern we were chasing up was really leading to a single interface along the following lines below…lets however continue to use the pattern’s terminology and call the interface IMyStashDAO. The idea behind the below single interface is that “since we are combining DAO interfaces for various entities into a single one, the type of the entity would become a parameter to the methods in question. So:

public interface IMyStashDAO {

    <E> void save(
            @NotNull final Class<E> entityType,
            @NotNull final Object entity);

    <E> void update(
            @NotNull final Class<E> entityType,
            @NotNull final Object entity);

    <E, EID> E fetch(
            @NotNull final Class<E> entityType,
            @NotNull final EID idOfObjectToFetch);

    <E, EID> void delete(
            @NotNull final Class<E> entityType,
            @NotNull final EID idOfObjectToDelete);
}

Interesting? Breaking out of monotony of adding DAO interfaces every-time someone adds some new kind of data that needs to be saved or updated?

Lets take a look at one of the services – yes, the CreditService 🙂 – and see how this change would impact it. Before the change, with individual DAOs, it would have been something like this:

public class CreditService {

    @NotNull
    private final MyStashDAOServiceLookup myStashDAOServiceLookup;

    public CreditService(
            @NotNull final MyStashDAOServiceLookup dbServiceLookup) 
    {
        this.myStashDAOServiceLookup = dbServiceLookup;
    }

    // Record an income
    public void credit(@NotNull final CreditInfo credit) {

        // Lookup Required DAOs
        IStashDAO stashDAO = 
            myStashDAOServiceLookup.lookupStashDAO();
        ICreditDAO creditDAO = 
            myStashDAOServiceLookup.lookupCreditDAO();

        // Stash Id in question
        String stashId = credit.stashId();

        // Get Balance
        double balance = stashDAO.fetchBalance(stashId);

        // Increase the balance by the amount
        balance = balance + credit.amount();

        // Update Balance
        stashDAO.save(stashId, balance);

        // Save Transaction
        creditDAO.save(credit);
    }
}

After introducing the single DAO interface, it is now:

public class CreditService {

    @NotNull
    private final IMyStashDAO myStashDAO;

    public CreditService(
            @NotNull final IMyStashDAO myStashDAO) {
        this.myStashDAO = myStashDAO;
    }

    // Record an income
    public void credit(@NotNull final CreditInfo credit) {

        // Get Stash
        Stash stash = myStashDAO.fetch(
            Stash.class, credit.stashId());

        // Increase the balance by the amount
        stash.increment(credit.amount());

        // Update Balance
        myStashDAO.save(Stash.class, stash);

        // Save Transaction
        myStashDAO.save(CreditInfo.class, credit);
    }
}

Which is better and why? One clear benefit is to the implementer of the DAO – he does not need to worry about writing a whole bunch of similar interfaces and implementations and struggle to ensure they reuse code among themselves. But we have not talked about the implementation side yet. Lets keep the focus on the client programs – the services.

I would argue that unlike the service interface, this new single DAO interface is easier to use. The service has something he wishes to insert, save, delete or fetch, he just uses the singular interface with the same methods, irrespective of how the database guys takes care of it.

Notice the introduction of the “Stash” entity – in this case, to enable the unification of the DAO interfaces.

NOTE: If you have been doing OO design for a while now, you wouldn’t have waited until now to write a class called “Stash”, you would have had it all along – even by merely underlining the nouns and creating a class per noun, you would have landed creating it. One might argue that the existence or introduction of the “Stash” class is not merely to facilitate the unification of the DAO interfaces – that is true and I envisage we will be adding much more to it soon – it has its own SRP in its own right. Remember the “BalanceModifier” class (I think that is what we were calling it at the time) which we said would get a better name and place quite a few posts ago? Well, we could have named it “Stash” as we are doing now and made it stateful. We could have inferred this as we added multi-stash support, a name and description to a Stash, etc, etc – at that time we only decided to introduce the “CreditInfo” and “DebitInfo” classes and if you really think about it, the Stash class was really always there – it was just that we represented it as a “double” – the balance. Now it is a class in its own right, having fields like balance, name, description, etc.

I think we have reached a point where I am satisfied with the interface for the database guy we have converged on. I would leave it at that for now. Am sure it will need a revisit soon when we start doing a little more complex querying and start talking about transactions! Its is time we probably switched focus to worrying about how to implement this interface new interface – am sure we may get some bright ideas while doing that and evolve the interface further. Probably in the next post ;-).

To conclude, not sure if any of you realized the uncanny resemblance of our IMyStashDB with say, Hibernate’s Session interface. Take a look. It is heading in that direction I must say.

Leave a comment