Wednesday, March 7, 2012

Big Bugs, small bugs

It's...(>_>)...(-_-)...not the small bugs and mistakes that we should be so nervous about finding. It's the big ones.

Consequently, when a problem is found the response should not be "PANIC/BLAME, THERE'S A PROBLEM" but "Hmph. Problem. How long will it take to fix? What does the fix entail? What was the cause of the issue? How can we learn to minimize the recurrence of this problem in the future? How can we at least minimize the impact of its issue?"


...at least for the small problems. When a big problem occurs that's a compound sum of small problems where nobody bothered to ask those questions, I think it's perfectly logical to hold people accountable. Massive failure deserves its recompense.

I work in software teams where the managers become very uncomfortable with the idea of "bugs" being found in their code. I am too. I want my code to be "bug-free." Clean, beautiful, elegant. A work of art on par with the Mona Lisa and the perfect features of Angelina Jolie/Jessica Alba in her time...

But that's really hard, with software. It solves big, complex problems. The bigger and more complex problem you're dealing with, the harder it is to focus on doing the little things perfectly. There are many an abstract algebrician who may forget a sign or two as they're walking through a derivation, many a writer who may forget to use perfect punctuation as they're trying to espouse a greater point.

On one hand, I understand the frustration with this. As a student who's trying to learn calculus, you don't know enough about the material to tell the professor when he's wrong. You're just trying to keep up, and he should've done the little things right in the first place! As a reader of content, I judge a writer who writes things like "it was in there best interests to do that" or "In you're face!" If a writer is as intelligent as her or she thinks her or she is, he or she should've written the content of their piece correctly, in all it's glory, in the first place!

...and yes, that "it's" was intentional for humorous effect, in case your wondering. As was that "your". Gotcha. :P

On the other hand, the "it should've been done right!" argument can only go so far. Humans are not perfect. We will make mistakes, out of sloth, oversight, or just plain ignorance. The idea that we should always "dot our i's and cross our ts" is a good ideal, but difficult to do in practice.

Perhaps it's just harder for me. Some people might call me "sloppy." I argue there's a depth/breadth trade-off. The more varied or broad your concerns, the less time and energy you spend on the execution details of each of those concerns individually. Plus, the more things you try to do, the more opportunity there is for something to go wrong.

Some people may disagree, but this seems to mimic the realities of life.

Thursday, March 1, 2012

Inheritance and Composition: There and back again

I recently got an application request to provide a web interface for a mobile app. The would serve as a demonstration for the mobile app's features. Both apps connect to a cloud datastore that provides a REST API for content.


I've gotten to the point that, whenever I start a new app, I try to think pretty heavily about what could change. I could've hacked and slashed through it, but I wanted to take a few moments to follow the basic Gang of Four design principles.



  • Encapsulate what varies

  • Program to an interface, not an implementation


As cloud based services are still new, and a relatively unstable market, my immediate thought was:what if we switch from one to another? Should the entire app need to be re-written? I say No.


Consequently, I wanted to encapsulate the variation of datastore. Ideally, my Domain model could remain as free as possible from specific provider concerns. It should focus on just the application function interactions.


I decided to build the app quickly in a framework that I'm comfortable with and enjoy, Grails. Grails boasts an advanced application architecture that really takes the concepts of Fowler's Patterns of Enterprise Application Architecture such as a Service Layer (something Rails does not seem to have out of the box, though it supports something kind of similar in "Helpers"), Data Mapper, Domain Model, Template View, Front Controller, and many other pieces that enable a competent, enterprise level senior developer to comfortably focus on building a god application from solid software engineering principles without having to build everything from scratch.


My initial approach was to handle this encapsulation of concepts in the Service Layer. The controller should only know about a Facade DatastoreServicewhich internally delegates to the application provider API.



Seeking to follow the concepts of Clean Boundaries from Uncle Bob Martin's Clean Code , I defined my own application level interface for the datastore. I then define a subinterface that extends that interface for the specific application provider, augmenting it with methods to encapsulate the REST API calls. An abstract class implements invariants of that interface and provides an extension point for the implementing service.



At this point,I'm starting to get worried. I seem to be adding a lot of complexity to the application for a very basic desire. Especially when further implementation of functionality made me need to store the 3rd party library's unique indentifier for my subsequent querying. As I tested, built, and refactored, I found my application as internally at odds about how to do this as I was.



On one hand I've used an inheritance hierarchy to store the 3rd party API's object id in my Domain Model. On the other, I have such a slim Facade over the 3rd party API in the service layer that it's just noise. I have two options:



  1. Remove the Datastore service and have the DemoController directly talk to the ParseService.

  2. Refactor the Domain Model to tease apart the 3rd party API id.


At first, I wasn't comfortable with the concept of option 2. It seemed conceptually strange. A Zapper IS A ParseEntity, and so is a ZapCard. Until I realized that what I'm saying, within the concept of my application, is that Zapper HAS A ParseIdentity. In effect, I'm saying that my Domain Model exists outside the context of the datastore,but has a representation within it.


This is conceptually interesting. We are used to thinking about the world in terms of how things are. I am a Person. I am also a Student. All Students are Persons, hence a Student IS A Person. But I'm not just a Student. I'm also an Entrepreneur, Engineer, Activist...How can I reconcile all of this without multiple inheritance?


Instead, what if I am a Person, who HAS A Student identity, HAS A Engineeridentity, etc etc. Then I can have a single canonical representation, and assume different roles in different contexts. When I have to activate pieces from a different context (such as drawing upon my Student.study() within an Engineer context, this process is simplified. Instead of having to cast myself into a different role, my fundamental representation is invariant (Person) and calls for identity are delegated to the appropriate concept. Or, to flip this in reverse, when I am a Student I need to access information that I have as a Person, I access it from my internal Person representation. Like a Russian Egg. Hence,prototypal inheritance built from composition.