Liskov vs Hibernate

Development, Java 2 Comments »

In Data Abstraction and Hierarchy, SIGPLAN Notices 23,5 (May, 1988) Barbara Liskov wrote;

What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.

and the Liskov substitution principle (LSP) was Born.

Applied diligently the LSP is one of the more powerful modeling techniques in an application designers bag of tricks. Unfortunately it’s also one of the most frustrating and difficult to grok because it seems so simple and intuitive.

When applying the principle it should be seen from the interface clients point of view. So “the behavior of P is unchanged”, doesn’t mean that the program has the same effect on the world, it means that the caller doesn’t have to condition its interaction with the subject based on whether they are o1 or o2. To the client both objects fulfill the contract and the client can ignore the differences between them.

Lets say I’m asked to provide a list interface (let’s pretend that java.util.List doesn’t exist for now). The client requires three operations; get an item at a specified index; put and item in a specified index and size that returns the greatest value for index. I create my interface and an implementation or two and deliver it to the world to great fanfare.

    +------------------------------+
    | List<T>                      |
    +------------------------------+
    | <T> get(int index)           |
    | <T> put(int index, <T> item) |
    | int size()                   |
    +------------------------------+

Another group requires a similar interface, the only difference being that they don’t want the list to be modifiable. Seeing as the original List interface was so successful I’m asked to create the new ImmutableList without the put operation.

    +------------------------------+
    | ImmutableList<T>             |
    +------------------------------+
    | <T> get(int index)           |
    | int size()                   |
    +------------------------------+

Several months later I’m reviewing my library and I notice that the two list interfaces share a common set of methods and I decide to redefine List to inherit from ImmutableList and unthinkingly violate the LSP.

    +------------------------------+
    | ImmutableList<T>             |
    +------------------------------+
    | <T> get(int index)           |
    | int size()                   |
    +------------------------------+
                   ^
                   |
    +------------------------------+
    | List<T>                      |
    +------------------------------+
    | <T> put(int index, <T> item) |
    +------------------------------+

You see from the standpoint of an ImmutableList client a List isn’t an ImmutableList as it can be modified. The inheritance relationship allows a List to be used wherever an ImmutableList is specified. Thus a client expecting that the list will not change may function incorrectly if when a List instance is supplied.

So how does this relate to Hibernate? Hibernate allows you to specify persist your java model with minimal impact on your code (this is grossly simplified view but will allow me to illustrate my point). It manages the relationships between objects and can be configured to either load an object graph completely, lazily or a combination of both. This is achieved by substituting the referenced classes with Hibernate proxies. These proxies will then load an objects details as required. Hibernate also allows you to detach and reattach and object from it’s data source. When an object is detached attempting to access parts of the object graph that haven’t been loaded results in an exception being generated.

Not so long ago I was involved with a project that used Hibernate to persist it’s state. The model was relatively small but the data set was very large. The data was organized into hierarchies. A node could have many children, these children could also have children (think massive XML document). A single node could literally have millions of descendants. Eager loading the complete graph for any node simply wasn’t an option and as the objects needed to be sent over the wire lazy loading was out. The team had developed a number of queries that would load part of the tree to a specified depth to suite the callers purpose. The problem was that the caller had to know which query had been used to load the object and adjust their behavior accordingly, violating the LSP. The team had effectively created derivative classes that behaved differently. This manifested itself in subtle (and not so subtle) defects, the solution to which was often to add additional queries to service the specific client needs.

To be fair the problem wasn’t really hibernates fault, but by the way it was being used (give someone enough rope …). Developers must be constantly vigilant to ensure their im implementation choices don’t introduce subtle design flaws.

The Lost Art of Separating Concerns - Noise & Misinformation

Development 2 Comments »

I feel somewhat frustrated when I read articles like Mark Barkers ‘The Lost Art of Separating Concerns‘. SOA is one of the most over used and under appreciated acronyms in our industry today. It’s unfortunate, because underneath the fluff, hype and vendor promises are solid architectural principles. Worst than the hype is the plethora of noise and misinformation, Marks article falls into this group. The intent of his article is to show how REST separates interface from implementation, while SOA/WS doesn’t. What it does is make the false assumption that in the SOA world services equal application interfaces.

While I was at ThoughtWorks I was ‘fortunate’ enough to work with Jim Webber, SOA proponent and all round nice guy. Jim is a fountain of knowledge and opinions on all things SOA. Until I met Jim I really wasn’t interested in the whole SOA phenomenon. There were just too many vendors offering it up as some form of silver bullet. Jim convinced me otherwise. Through conversations, careful guidance and the judicious use of his backhand (never suggest that SOAP and Web Services are CORBA wanna-bes) I came to an understanding of where an SOA fits in the development landscape.

A service-oriented architecture is not about using tools to create WDSL definitions from application interfaces defined in java or c#. It’s not about using tools to create application interfaces from WSDL. In fact it’s not about application interfaces at all. It’s about exchanging messages. These messages may be logically combined to form protocols and services.

In the current corporate world, for better or worst, the accepted message form is SOAP and WSDL is most often used to describe services. Unfortunately there is also a vendor supported tendency to blur the distinction between service definitions and application interfaces. Vendors (open source and commercial) tout the ability to ‘transparently’ enable web services from application interfaces or to generate application interfaces from WSDL definitions. In both cases we end up with service architectures that are tightly coupled to application implementation. An alternative approach is described by the proponents of MEST. MEST attempts to describe service-oriented architectures in terms of services, messages and architectural principles. It moves the focus from application interfaces to protocols built on patterns of message exchange. This focus allows you to design message protocols in line with business services. Because the focus in on the messages the services naturally exist independently of application interfaces. This disconnection allows application and service interfaces evolve independently. There is a small price to be paid in the form of adaptors but frameworks like Spring Web Services make this task quiet a bit simpler by focusing on message processing rather than service generation.

Retrospective

Development, Random thoughts 1 Comment »

I bumped into an old friend in the pub the other day. We started talking and she told me about a retrospective she’d recently been involved in after the project she was working on had been suspended due to yet another management restructure (there have been several in the last twelve months). A large number of people from the business and the development group were in attendance. Her team of four developers was there along with the architect who had created the solution architecture and the non-functional requirements and the project manager. There where one or two people in the room she didn’t recognize and she assumed they were from the business side.

Introductions were made and she was surprised to find that “John” had worked on the project reviewing the architecture. She had never encountered him and had worked closely with the solution architect, who’s eyes seemed to roll when John introduced himself. Still, she knew that the architecture had been through a number of reviews. She’d bounced a couple of architectural decisions that had sprung from these as non-functional requirements for business approval as they had had the potential to significantly increase the amount of effort required to produce the system without adding any direct business benefit.

As in most retrospectives the meeting was an attempt to extract lessons learned while delivering the project in order to improve the process in the future. The meeting was going well. Many of the positive items where directed directly at her team and she was proud of the work they had done. She was surprised when one of the people she didn’t recognize began to raise issues around the clarity of the projects purpose. She’d been working with the business on a daily basis and, although the requirements had been subject to some change and clarification, she had never felt that the projects final goals were unclear. “How can you even begin to develop a piece of software without a vision statement?” True she’d never seen one, but the project wasn’t really rocket science and she thought the objectives of the project were clear.

True, they were running behind scedule. This was due, in the majority, to the restructure and a freeze on resources. She had a project team half the size she’d been promised with a higher proportion of junior developers than had been agreed. Another contributing factor had been the toolset mandated by the architecture team. When early on in the project she’d queried the reasons that they needed to use a particularly painful tool. She was told that it was vendor “A”s product in the space and we only use vendor “A”s products.

John continued to insist that the project didn’t have enough governance. He insisted that the project needed more rigid processes. He failed to understand that the project delivery team hadn’t failed and my friend took offense at the assertion they had because there wasn’t a huge paper trail of ill-informed sign offs.

The business side of the project had been very happy with aspects of the system they had been able to preview. That the project had been put on hold due to a restructure was not in any way a failing of the delivery team, but John continued to prattle on about roles, responsibilities, more detailed task reporting on time-sheets and an interesting observation that if you have half the number of development resources the spend rate would be 50%. “We’re not even CMU level 0” he exclaimed, confusing everyone until the project manager corrected the term.

We had a couple of drinks and laughed and wondered how far they would progress down the CMM track before they realized that people interacting was more important than process they employ. “No matter how rigid a process you have, a monkey will still play with its shit.”

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Log in