Showing posts with label design. Show all posts
Showing posts with label design. Show all posts

2009-10-01

Should I put that logic in my Grails domain class, service class, or a controller?

I don't honestly know. I do have a feel for when this is appropriate and when it isn't. For example I think Anemic Domain Model is a valid anti-point. It completely jibes with how I feel the benefit of an Object Oriented Programming (OOP) system should work... in that I don't think domain classes should be just a representation of data.

The whole point of OOP is to encapsulate data and methods in a modular way keeping logic bundled together with the data it operates on. Let's work on a concrete example... assume this is a domain class in a Grails project.


class Person {
String firstName
String lastName
Date birthDate
}


So far so good. So if I want to figure out a person's age... where do I put that? The class seems like a good place...


class Person {
String firstName
String lastName
Date birthDate

def getAge() {
def now = new Date()
now[Calendar.YEAR] - birthDate[Calendar.YEAR]
}
}


... in fact anything that operates on the domain data in the object seems like it fits well here. If we run generate-all on this class we get a UI that looks like this...


Marking non-persistent services as transient keeps them from getting sent to the database should we need them... for example if I had a "fooService" then I would get this injected in my domain class like so...

class Person {
transient fooService

// ... snip ...
... but I'll not bother with an example just now.

So when does the logic belong in a service or a controller? Well, when it stops being directly driven by the domain model. For example things could get messy if we start injecting security checks into the domain model. I would find that a bit messy to maintain.

Similarly if there was a Person to Person relationship that required some logic that checked states of both objects...


class Person {
Person spouse
//... snip ...
void marry(Person other) {
if(!other.spouse || other.spouse.id == this.id ) {
other.spouse = person
}
else {
throw new Exception("These two cannot wed")
}
}


... while this works it feels a tad clunky because I have to do this bit ...


if(!other.spouse || other.spouse.id == this.id )

... and since we have to somehow modify the other class too and it feels odd to have the this person object modify the other person object.

... but if there was a minister service I could write this...


class MinisterService {
//... snip ...
void marry(Person left, Person right) {
if(!left.spouse && !right.spouse) {
left.spouse = right
right.spouse = left
}
else {
throw new Exception("These two cannot wed")
}
}
// ... snip ...
}


... and this feels a tad better since the Person class no longer needs to carry around the knowledge of all the possible marriage rules that a lawyer might enact. This also models real life better since people visit ministers, justices, or captains to get married in real life... and we cleanly avoid the issue of people modifying each other.

There's other rules that I could probably explain if I was more articulate. Has anyone else thought about this? What tweaks would you put on these ideas? How would you express this rule?

Note: this is a quick reply to this tweet.

2009-09-08

A Programmer's Isogloss

One of my coworkers has a degree in linguistics and this idea comes from talking with her about language and isolation. Call it my you should really go to that conference rant if you like. The topic of conversation give me a stark realization that I think anyone that is responsible for the care an feeding of programmers should be cautious of.

Naturally, computer programmers use programming languages and the more complex the language and free form it is the more likely it is to have dialect, idiom, and isogloss just like natural languages.

In particular if a speaker or group of speakers live in isolation long enough they will develop their own little quirky habits. These quirks start off as innocent inside jokes which include conventions that we recognize in API. Given time the isolated group can start to invent new idioms which approach an unintelligible complexity to an outsider. The divisions between various frameworks that share Java as a base language and their definitions of terms is a good example.

So how do you break this cycle of main languages fragmenting and breaking up into new languages? You go out and regularly talk to others about your code, your architecture, and you get a feel for how others say words or convey meanings. You make your community of language larger. Every company needs to get its programmers out there and talking to other developers. One of the best ways is through conferences.

The benefits will be that your corporate architecture will stay closer to the wider world's interpretation of the language and idioms you use (think: style, practice, and API). Your developer's will be more creative and valuable as they benefit from the exchange of ideas. And you will know that you have a pool of similarly talented consultants and developers to seek out when you need them.

Other good ways to let your programmers get out there and learn more is to encourage the use of social networking in responsible and applicable ways. I used this recently to help think about const versus final in our code base.

Another idea I've been toying with is to have at least one small company backed Open Source project that your people are encouraged to contribute to that you can also use for getting outside feedback and perhaps to recruit new people into your company from. This is a novel idea but I think with some sensible boundaries it can pay off even for closed source companies.

Those are just some of my thoughts on the topic. But essentially you want to avoid putting your programmers in the position that all they ever do is "talk" (via programming) to the computer and themselves. You need to talk with other people whether in code or English to keep your skills sharp and to avoid drifting off into your own strange dialect. The dangers to both the company and the employee of drifting off into your own little world are profound. It can mean obsolescence for both parties and that doesn't help anyone ... except maybe your competitors.

2009-09-05

Configuration Best Practice

So rattling around in my head is this idea of configuration. When should you configure? What should you configure? How much should you configure?

As a rule of thumb I need to perform a software task in three relevant contexts to spot the important patterns for the system. That is to say I need three unique implementations of a system to spot how to generically implement a framework around the problem domain. The same is true for configuration.

Until I see three distinct scenarios where a system will be used I usually can't rightly discern what is going to need to be configurable and what isn't. I can usually make a good guess as to what will be needed by the time I'm working on two implementations ... but it really takes the third one for things to gel.

So if I were to number from best to worst case for configurations... I would put them in this order:

  1. configuration by convention (as we see in Grails)

  2. dynamic configuration by environment

  3. explicit configuration by administrator



Once you figure out that part of a system is going to actually need to flex then you should refactor for just enough modularity to reach the changes you need see. When doing this work the best thing to do is to make your system self configure by convention. This way we provide the necessary configuration without increasing the load on the end developer or administrator.

Next best we can do configuration by picking up things from our environment and working out the values we might otherwise need configured. This allows the administrator of our application to merely move the application code base to the correct place in the "cloud" or the correct server.

The last thing we want is for the administrator to have to open a dialog and enter data about the environment for your system to use at run-time. This can be an error prone process and it is possible that the environmental factors will change forcing the administrator to always be conscious of additional variables in the system.

In the perfect world our software systems would have enough intelligence to ask the environment for what they need and the environment would be intelligent enough to compute those dependencies as they occurred.

Of course the real world is a long way from perfect.

2008-11-03

It is all UI even API

It is all UI and UI leads us down certain paths.

This is an idea I've had for a long time but it hasn't been posted here before so let me lay down for you the why behind the tag line of this blog: "The power of software is the power of thoughts and ideas."

These are important concepts: The purpose of the UI is to aid the user in thinking about what they are doing inside their machine. The UI should match what they are thinking about as closely as possible.

This is all well and good for users. It gives them pretty looking sites that are easy to use and understand. It leads to ideas about making user customization of content a certain flavor of easy that involves allowing for graphical interaction with the system.

But, the programming language is UI too.

I have recently graduated into a tier of programmers that write programs for other programmers to use. But, I have always known that unless you are building the system from nothing then you are the user of another person's UI. It may be called an API but it is still UI.

Programming languages are UI too, they are UI with a limited audience, developers. Just as EE folks design CPU with a "programmer's model" in mind so too should library developers develop software with application developers in mind.

The best way to do this is through "dog-fooding" which is to say that a developer should be forced to eat their own dog-food. When you develop something you should have to use it. If you can't use it you can't really make well informed decisions about how that product should work.

As a developer I try to get inside the minds of the people who use my products. I try to anticipate what they will do, how they will do it, and what ways they may want to do things differently. I can operate this way because after nearly two decades of working with computers in one fashion or another I am convinced there is no right or wrong intrinsic in the machines themselves.

Any meaning, purpose, or sense of working or brokenness is determined by the user. To make a system that is bug free you have to know the user. The technology therefore must be designed from the user back to the machine.

The problem is compounded by the fact that there are multiple types of users. You can build classifications for each of them profiling what their expectations are and building their view of the system around that. Working for one user is broken for another. To design a truly beautiful system you need to account for as many of your user classes as possible.

Often what system designers and developers leave out of their design consideration is themselves. Developers are users too. The must live with their own design choices over time and are prone to the same flaws that other user classifications are prone to as well.

The reasons technologies succeed and fail are tied up in the intersections of actual functionality and perceived function and value. These are emotional decisions as much as logical ones. Very technically speaking any Turing complete language is capable of any task that any other Turing complete language can do.

So the power we find in expressive software is actually the ability to cleanly express some thought or idea. We are attempting to communicate both to the machine and the user some expression of action, computation, art, or logic that will achieve the goal of the user. The software is most effective when the developer and the user understand each other through the lens of the software.

This is true for your web application, mobile application, programming language, or your developer API.

The web framework developer is working for their user which is the web application developer. The persistence layer developer is working for their user which is both the framework developer and the application developer. The application developer is working for the end users of their system.

The most effective developers will be the ones that realize this and deliberately cross as many disciplines as appropriate for their application space. This kind of renaissance developer will be most effective at knowing how what they will write will be received. This kind of developer will know implicitly that it is all about user interface and developers are users too.

Just as architects have known for generations that a building must be beautiful both on the outside and the inside yet still respect the laws of nature so too must computing grow up. So in my phrase "the power of software is the power of thoughts and ideas" is nestled the concept that not only power but beauty and value of software is the beauty and value of thoughts and ideas.

The metrics of our beauty in software is the cognitive dissonance we create in attempting to enable our users to create their art with our tools. When you create software you are implicitly directing the thoughts of another person or machine. Just as an Orwellian language could forbade certain thoughts your API could forbid a design or direct users down a path. The challenge is to match your design to the users' thoughts and direct them toward good solutions without imposing a mental fascism.

The converse is side of this is that you want to direct your users toward maintainable and workable designs. The goal should be to guide not to force. So working out an good design is a balancing act.

Just some thoughts that I've had while looking at possible improvements to an existing development framework.

Edit: Oh yes, I saw this shiny "follow" gadget and added it to the upper right hand corner. Won't you do me a favor and click it a few dozen times so I don't feel too bad about having "0" followers. Thanks.

2008-01-19

the vessel of ideas

Earlier I said:
The word is the vessel of ideas. The written word is the preservation of ideas. The computerized word is the execution of ideas.

Programming is about thinking. It is nothing else. Programs only execute the rules we believe to be true as we have written them down. What do we know? What do we believe?

Take the idea of person, parent, or child these are very basic ideas on the surface but surprisingly few people understand in context the ironic trap that the idea of an
Object then introduces. In the sense of a program...

An Object is a thing.

An Object may have things.

So it seems natural that a parent is a person and a child is a person. That makes sense. A parent has children. A child has parents. That all makes perfect sense. In the now.

We might say:

class Person {
def name
def birthday
def gender
}

... to say a person has a name, a birthday, a gender...

class Parent extends Person {
static hasMany = [children:Person]
}

... to say a parent has one or more children ...

class Child extends Person {
Person mother
Person father
}

... to say a child has one and only one mother and one and only one father... (in the real world we would probably fold Child attributes back into Person)

The terms I've used so far are more or less permanent. Once you become a parent you are never not one. Once you become someone's child that status is never removed. But sometimes there are statuses that are more flexible that aren't modeled correctly by using the "is a" idea. This becomes more apparent when dealing with a term such as employee.

A person is an employee as long as they are employed. You might be employed, unemployed, and re-employed multiple times with the same employer. So should "person is a parent" be modeled the same as "person is an employee" or is being an employee different?

Could it be that ...

class Employee extends Person {
static hasMany = [employers:Employer]
}

... such that we we would add and remove employers over time to an employee?

But that doesn't really get at the idea of being an employee. You are one from one date to another and you might be again. So really you would want to say:

class Employment {
Person employee
Employer employer
Date start
Date end
}

So that a person is an employee if a person has an employment that has a start before now and an end after now. So many other relationships turn out share this same kind of temporal basis. Sadly, marriage does too... some of the data I have to model deals with people who have children and get divorced. The parent-child relationship is unbreakable and begins on the date of birth of the child. However, marriages don't work that way and at least once we've had the problem of modeling a marriage, divorce, and re-marriage. The systems can't handle that idea because they weren't built to hold it. They are poor vessels for these ideas.

It stands to reason that the attribute of being something when it comes to people is not in fact the same as being something when it comes to objects. People are objects in every sense but the being is not the same. A person has attached to them attributes ... like tags more than attributes ...which makes them one thing or another.

The relationship itself is an entity or an object.

The person is an employee by the virtue of possession of a relationship. Once in existence the relationship of employment carries its own being. It has its own data, attributes, and validity independent of the employee or employer.

Likewise the idea of a relationship between people carries similar intrinsic existence independent of the people. For example parent. The person as an object is not really modified but rather a new external relationship is created. In this case a child is created that then points back to the parent.

That means the "class Parent" is actually redundant. A person is a parent if any other people point back to them as a mother or father. If you wanted you could add a deceased date that would remain unused inside the person class and leave it undefined during life and set after death. But that's getting into the morbid.

Consider the employee again. This is a person object who has a record of employment. The employment is distinct and independent of the person. The relationship itself can have attributes without involving the people.

This is all pretty basic but if you continue to expand these ideas shifting your attitude about what an object is you find that mapping objects and relationships starts to get easier. You get to a model that has fewer impedance mis-matches with a relational database for example.

If the vessel will not hold your ideas change the vessel not your ideas.

2007-11-15

The Fallacies of Distributed Computing

I'm working a SOAP heavy project right now so I thought I'd look up the 8 Fallacies of Distributed Computing. These are 8 assumptions people often make in designing network based systems such as a SOA or ESB that simply aren't true.

The following is NOT true:
1. The network is reliable.
2. Latency is zero.
3. Bandwidth is infinite.
4. The network is secure.
5. Topology doesn't change.
6. There is one administrator.
7. Transport cost is zero.
8. The network is homogeneous.

Designs should allow for the network to drop in and out, run slowly, take a while to move data around, change with out notice, or deal with multiple operating systems, langauges, or data representations. How often to we just think about the 'best case' scenario and fail to build in allowances for problems?

2006-12-14

Database Design

Let's say I want a screen that displays a list of MP3s with Genre, Artist, Album, Song Name, Play Length. What would the database table for this look like? Many neophytes would design a table that looked like:

MP3Files
Column
Typedefault
MP3ID
int
auto increment
Genre
varchar(255)NULL
Artist
varchar(255)NULL
Album
varchar(255)
NULL
Song Name
varchar(255)
NULL
Play Length
varchar(255)NULL

... and amazingly never see the problem with this.