Monday, February 26, 2007

ORMs are not just about objects

It seems most of my professional career has been built around using java to pull and put stuff in a database of some sort. Whether we are talking about an eGovernment web interface or a content management system I've done a lot of work with java and databases. The past few years I have grown to use and love Object Relational Mappings (ORMs), specifically Hibernate.

ORMs in the software development world are almost a religion, you either love or hate them. I love them because they take a lot of the "Busy" work out of working with databases. Plus they allow you to stay in an object oriented world rather than moving from java to JDBC, which is much more functional.

Usually when I come across someone who is against ORMs they say "Well it doesn't fit with what we are trying to do" or "Its overkill" or "It adds complexity to a simple interface like SQL". And its true, it can be overkill for some projects and it is another thing to learn and manage. Some people would feel more comfortable pulling fields out of a result set than working with the Hibernate API.

However, I think a lot of those people don't fully appreciate what ORMs give you. Of course the most visible is the java object to sql mapping. But another HUGE benefit is persistent lifecycle. I've seen JDBC code that passes a connection through multiple paths, updating a row here, then updating it again, and so on and so on. From an outsider it becomes almost cryptic what is happening and where. And if you change your schema at anytime, you may not know the implications until the actual code is run.

In ORM land lets say I have a User class, that maps to a table some where. Lets say I do the folowing:


User user = new User("Jon");
session.save(user);
....
user.setAge(18);
session.saveOrUpdate(user);
...
user.setAge(22);
sesion.update(user);
...
user.setIsMaleGender(true);
session.update(user);
...

session.commit();


Now in JDBC land this would end up sending several SQL statements to the database, each being processed, locking rows, etc. The code who set the users's age as 19 may not know that later some other code has set it to 22 unless they queried the db again in the same session. If some logic was later performed with the assumption that the age is 19, that could be a problem.

In Hibernate (or most ORMs) the session would keep track of that user object once it is associated with the session ( after the first session.save()) and keep track of updates and even retrievals. Periodically throughout the lifetime of the session hibernate my flush the user object to the db or it may wait until the end. Doesn't matter, however you do know that throughout that session you are not dealing with stale data.

This is an incredibly efficient, complex and useful function that you get for free just by using an ORM. As your code gets more complex and is re factored a few times, problems that can arise from using stale data that can be very difficult to track down (I should know, I've done it for a while).

So whats the moral? ORM just isn't about objects and abstracting SQL statements. Its about treating persistent data as actual entities in your program. If you think an ORM isn't for your app, I challenge you to look again. The complexity of the added layer may simplify things in other places.

Tuesday, February 20, 2007

Paradigm shift

Moving into Objective-C with Cocoa requires a whole paradigm shift when talking about OOP. Rather than objects having methods, they respond to messages. And rather than calling methods, you send messages. The interesting thing is you can send any message you want to an object, the question is they may not respond. Take the following class:


#import

@interface MyClass : NSObject
{
NSString * name;

NSMutableArray *items;
}

- (void)setName:(NSString *)aName;

@end



Lets assume I've implemented the rest of this. The following code will compile




MyClass * test = [[MyClass alloc] init];

[test someMethod];



Now, notice that there is not a method called "someMethod" in the class MyClass, however I'm still able to "call" it in my source and compile it. The reason is, I'm not really calling "someMethod", but rather sending a message. When this runs it throws an exception but thats still very different than other languages I'm use to. One cool thing is you can ask an object if it would respond to a message before sent. A model that is very much like inspection in Java.

Sunday, February 11, 2007

NSStatusItem

I've been playing with Cocoa on my MacBook and I really wanted to create a Status Item on the "System Menu bar." Translated, I wanted to create a menu on the top-right of the menu bar that was displayed even when another app was brought to the front. When using Interface Builder I really couldn't see a graphical way to do it. After some searching I figured it out. In one of my controllers, I did the following:


NSStatusBar *bar = [NSStatusBar systemStatusBar];
NSStatusItem * theItem = [bar statusItemWithLength:NSVariableStatusItemLength];
[theItem retain];
[theItem setTitle:NSLocalizedString(@"Menu Title", @"")];
[theItem setHighlightMode:YES];
[theItem setToolTip:@"Menu ToolTip"];
[theItem setEnabled:YES];
[theItem sendActionOn:NSLeftMouseDownMask];
[theItem setTarget:self];
[theItem setAction:@selector(showInterface:)];
[theItem setMenu:nil];


And boom, I now have a status item called "Menu Title" on the top right that is always displayed. Awesome!

Friday, February 9, 2007

Love your loops and let them love you

I'm not a language freek, but I can appreciate an improviment when I see it. One of the new features in Java 5 is their new and improved for loop. Lets say I want to iterator over a Vector of Strings.


Vector list = new Vector();


The old way (pre java 5)

Iterator<> iterator = list.iterator();
while (iterator.hasNext())
{
String s = iterator.next();
System.out.println(s);
}


And the new way (Java 5+)

for (String s : list)
{
System.out.println(s);
}


Enjoy!


UPDATE: I just noted that my collection generics was removed by blogger's posting thingy. Weird! Just so everyone knows, I was using Java 5 generics on the vector to strongly type it with Strings.

Wednesday, February 7, 2007

Java 5 Annotations and You

I was able to introduce Java 5 annotations to a few people at work today and I think I hit a cord. I've always had a feeling that most people don't really understand the point of annotations, I know it look me a while. One of the big uses of annotations is try remove the restriction on defining your structures based on interface implementation.

Current Practice:

A good example is the swing api. Lets say you have a JButton and you want to receive events when that button is pressed. Current practice is to write an Class that implements EventListener and register your class with the JButton. You then will receive Event objects and you can inspect them and figure out what event occurred and if they occurred on the button you are interested. What happens is now in every EventListener you write you are now duplicating the code to inspect events, and route to the specific business logic.

Throw in Reflection:

To me this is weird, Java is one of the few languages that has inspection and reflection however it is still common practice to force concrete implementation on the users of our apis. What would make more sense is to tell a JButton "When this particular action occurs, call this method on this object." Your controllers then become POJOs with the methods containing specific segments of business logic.

One Step further with Annotations:

Now lets take that a step further and add the concept that I just want to give JButton my object and JButton will figure out what methods to call for what events and when, but still not requiring my controller to implement an interface. This can be done with annotations. Rather than giving the users of my API a set of interfaces they have to extend, I can just give them a set of annotations they can use to annotation their classes and the API will do the rest behind the scenes.

Example:
Lets take this annotation.

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

enum EventType {BUTTON_PUSHED,MOUSE_OVER}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface EventCallback {

EventType value();

}


Here I create an annotation that can decorate a method and takes an enumerated value of either BUTTON_PUSHED or MOUSE_OVER (example actions that could occur on a Button).

Now, lets say I'm writing my own GUI library, I can write a Button class to inspect any objects registering themselves for this annotation and remember them. In my Button class the registerActionListener method looks like this now.


public void registerActionListener(Object object)
{
Method[] methods = object.getClass().getMethods();
for (int i=0;i < methods.length;i++)
{
if ( methods[i].isAnnotationPresent(EventCallback.class))
{
EventCallback annotation = methods[i].getAnnotation(EventCallback.class);
EventType eventType = annotation.value();
if ( eventType == EventType.BUTTON_PUSHED)
{
// remember to call this method on this object if the button is pushed
}
else if ( eventType == EventType.MOUSE_OVER)
{
// remember to call this method on this object if the the mouse if over
}
}
}


}


Here is where you will really see the advantage. Our Event Listener (or controller) now looks very clean and simple.


public class MyController {

MyButton button = new MyButton();

public MyController()
{
button.registerActionListener(this);
}

@EventCallback(EventType.BUTTON_PUSHED)
public void myButtonWasPressed()
{
System.out.println("My Button Was Pushed");
}

@EventCallback(EventType.MOUSE_OVER)
public void aMouseIsOverMyButton()
{
System.out.println("A mouse if over my button");
}

}

Notice that I can now name my callback methods whatever I want. Also, if I'm not interested in a event type, I don't have to even annotation a method for it. This means I get the methods I want called for only the events I'm interested in.

I really think this is the way all Java APIs are going and for a good thing.

Friday, February 2, 2007

Memory Leak Solved!

Thanks to Chris for having more follow through than I do. Here is his comment on my last post.


I was curious myself, so I googled "cocoa exception leak", and found this:

"Exceptions are effectively out-of-band return values; in Cocoa, this means the exception object itself is autoreleased."

Full details here:

http://chanson.livejournal.com/126035.html


Memory Leak??

As I've stated in previous posts, I'm trying to learn Cocoa. I'm amazed that with all my mac experience I really have a very basic knowledge of it. I've been hitting a lot of tutorials and I have one big question. I see variations of the following code a lot


Cup *cup = [[Cup alloc] init];
 
@try {
    [cup fill];
}
@catch (NSException *exception) {
    NSLog(@"main: Caught %@: %@", [exception name], [exception  reason]);
}
@finally {
    [cup release];
}

Lets assume that [cup fill] throws the exception and its caught here. Isn't the fact that the exception is never released a memory leak? I know I'm being picky but I really see this in a lot of tutorials. I would think that in the catch block I should see [exception release]. Cocoa programmers let me have it.