OO Nomenclature Demons

Object Orientated design has made code reuse and design a lot simpler in recent times, but there are times when a coherent naming standard becomes quite a challenge!

This article looks at some of the issues you can hit, and does some soul-searching to try and find a work around.

Introduction

We've heard it all before - OO is a silver bullet, Java rocks, yada yada yada. Whilst I am very much in love with OO design, there reaches a point in a developers life where he looks at the methods (s)he's just scrawled out (because hey, we ALL go and write out full class interfaces before we sit down to code them... right???) and thinks to themselves "What the hell is that..."

Sure, you hit times in non-OO design when method names, variable names, even comments, can just look so twisted and confusing that you really can't be sure whether you are coming or going. I'm going to share with you a few recent confusions I have personally had in this department.

The RemoteDocument class

Our test case is that of a class to make dealing with remote files easier. Pretty much it needs to be able to get documents from a remote server, send them back, and allow you to edit their content locally. Sounds easy - which really, it is - but the naming can become a bit of an issue.

Firstly, lets take the example of a perfectly innocent method name, like getDocument. Really simple. Not quite... Does this method get the document from the class (if you subscribe to the standard of using "get" for accessor methods, this would seem correct) or does this "get" the document from the server? (Which would make the method a mutator, or arguably an imperative method - so not really worthy of a "get" prefix).

So, we have a problem - get/set is ambiguous. So how are we going to fix this problem?

Solution?

At first, it appeared easier to use get/setDocument to talk to the server, with get/setDocumentContent (or even just get/setContent) to be used for the local copy. Although this does provide a better idea of how the classes work, by a string nomenclature standard, the server naming is wrong. In other cases I've found that fetch/updateDocument style naming works better for remote operations, but even still that is somewhat abstract too.

It simply doesn't make sense to say that setDocument sending the document to the server is a mutator for the class. Then again, setDocument being a mutator that gets the information from the server just doesn't sit right. So it's going to "set" data to the class from a remote site which we have no idea (from the name) where this comes from?

What we need to do, is look at just how this class has been set up.

The Crux

Essentially, we have a problem not with our naming, but with our class. The class is trying to do too much - It's trying to manage a local file in memory, as well as remote file. Sure, it might be the same file, but essentially they are two completely different subjects. What we need, is to separate these two documents logically.

Trying to slice up a piece of crux

There are many ways we could demarcate the problem. One of the most logical is to change the system into two more generic classes, something like a RemoteServer class and a Document class.

Now, the problems goes away. RemoteServer.get/setDocument clearly deals with Document objects from the server. Document.get/setContent clearly deals with the content of the Document.

Oh, the ironing...

The irony of this article is that at this point I started writing why this approach caused extra problems, and ended up convincing myself otherwise. Save one very real problem with more classes :

More Management

We now have two classes we need to deal with, rather than one

We now have to keep track of the Document class' class fields in two places - the RemoteServer object to populate the object, and the Document object to provide the accessors/mutators. More code to change means better chances of bugs when you add that "last modified date" field. Of course, this does have its benefits - the way the server works can change, with the changes being more transparent to the user of the Document class (it should be anyway). If the server starts using a DB to store the files rather than the filesystem, the Document class doesn't even need to know about the change.

However, adding new fields that are handled by the Document class becomes twice the work.

Trade-off

Of course, the trade-off here is that we have slightly higher maintenance, but our code and API is cleaner, more documentable and easier to work with. The trade is also that to perform a simple task like writing a new file to the remote server, we now have to create two objects rather than one. Something like :

More classes example

//Previously on the OC^HO
RemoteDocument myDocument
myDocument.setDocumentContent("Hello World")
myDocument.setDocument()

//With two classes involved
RemoteServer myServer
Document myDocument
myDocument.setContent("Hello World")
myServer.setDocument(myDocument)

In this case, it doesn't appear much different - which is a good thing, considering the method names are obviously much clearer. It is more objects though, which is more memory and more code, which is a negative. However, consider the case of a much more complex example :

Longer RemoteServer example

//With a single class
RemoteDocument myDocument
myDocument.setServerURI("http://local-division.my-test-company.com/remote/")
myDocument.setServerUser("j_stirk")
myDocument.setServerPassword("foobar")
myDocument.setDocumentContent("Hello World")
myDocument.setModifiedDate("20041021202059")
myDocument.setDocument()

//With two classes to share the load
RemoteServer myServer
Document myDocument
myServer.setURI("http://local-division.my-test-company.com/remote/")
myServer.setUser("j_stirk")
myServer.setPassword("foobar")
myDocument.setContent("Hello World")
myDocument.setModifiedDate("20041021202059")
myServer.setDocument(myDocument)

This example also allows us to see just how much extra work the single RemoteDocument class is taking on. The class has to not only deal with the internals of managing the document and its relevant metadata, but also has to deal with the communications with the server, and all of the information about that too! It becomes quite apparently that the RemoteDocument class is trying to do too much.

Conclusion

This article was originally intended to be a examination (/ rant) on the standard nomenclature of OO based design using "get" to denote an accessor and "set" to denote a mutator, but turned out to be quite different. It appears from this brief article that get/set are indeed extremely suitable - but only when the classes are designed in a clean manner.

I would suggest that at the first sign of ambiguous or difficult method names, you take a look at your class and make sure it isn't biting off more crux than it can chew...

This goes true too for commenting, and even imperative methods - if you need a 64 character long method name to say what its doing, or a 6 line comment before you make a call, perhaps something isn't quite right.

Even if not for code management purposes, who wants to see Document.setServerRemoteProcedureCall("Documents.setDocument") in the middle of their code... That line is sure to wrap with a bit of indentation. Make your Vim session look a mess!