Friday, November 27, 2009

Four Bits Worth of Dev Advice: Last Half a Bit

This the 5th and final post in my series about my 16 pieces of developer advice. In the previous post I listed the 16 pieces in headline form ([1]), and briefly explained the first 12 pieces ([2], [3], [4]). In this post I go through the last four pieces. Enjoy!

1100: Write change friendly code
This piece of advice is about a mind set: Keep in mind that the code your writing will most likely be changed a lot of times in the future. Therefore you need to write code that can be changed without too much pain. This mind set leads to a lot of the common coding best practices like using symbolic constant, like avoid unnecessary dependencies, like keeping functions short and the list goes on and on. These things brings readability to the code, and they enable changing the code later on. On the other hand you should (of course) avoid over-designing software, so this nugget is really mainly about the small code level things. And those small code level things make a huge difference when it comes to the modifiability of software.

1101: Dry
Don't repeat yourself. Or DRY. This piece of advice has been re-iterated so much, that I will leave at a reference for you to follow, the C2 wiki entry on DRY.

1110: Don’t stay stuck
You sometimes get stuck when coding, in fact some days coding feels like this:

Getting into situation where you are stuck and can't see what the next step is, is normal and something you need to accept as part what it's like to write code. The important part is what you do about it. Some developers start thrashing; they run around in circles without really getting anywhere. Others start surfing for cartoons (or ... well, you get the idea). That doesn't help. To get out the situation your stuck in you probably need help - I know, I usually do - so seek help. Ask a team mate to pair with you. Ask your project manager for that tool you need. Ask a senior colleague to take a look at your problem. Read up on the relevant literature. Just don't stay stuck.

1111: Be curious
The final piece of advice on the list is simply to be curious in your work. And use that curiosity to gain technical insight. For instance ask yourself how the frameworks or libraries you use are implemented. Maybe read some of the code, step through it in a debugger, or read the documentation (yes, it said read the documentation :-) ). Or take a look at the code your compile generates, be assembler, bytecode, MSIL or something else. That generated code can tell you a lot about how the platform and language you're in actually works. Just try to stay curious about how things actually works, and spend a bit of time and then satisfying that curiosity.


So that was my list of 16 pieces of developer advice. I had fun compiling the list. I started out with a much longer list, but it was fun to boil it down to 16. What do you think is missing from the list, and do you think should be taken out?

Friday, November 13, 2009

Four Bits Worth of Dev Advice: Half a Bit More

This is the fourth post in my series of four bits worth of dev advice the first three ([1], [2], [3]) covered the sixteen pieces of advice in headline form and the first eight pieces in a bit more detail. This post goes through another four pieces of advice.

1000: Use symmetric interfaces
When designing an interface we have to decide which methods the interface contains. If you know exactly how the interface will be used - e.g. you're the guy developing the code that uses the interface - deciding what's in an what's out of the interface is pretty straight forward. If, on the other hand the interface will be used in unknown ways - e.g. you're developing a library that others will use - the decisions are harder. In the later case symmetry can be an excellent guide: If an interface has method A that has a logical inverse operation B, the interface should probably have B method. For instance, consider this code from the Rotor project:


class CClassFactory :  public IClassFactory
{
CClassFactory() { }

public:
CClassFactory(const COCLASS_REGISTER *pCoClass) : m_cRef(1),m_pCoClass(pCoClass)
{ }

// snip

virtual HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid,
void **ppvObject);

// snip

private:
LONG m_cRef;
const COCLASS_REGISTER *m_pCoClass;
};


This is a typical factory: It can instantiate a certain type of object through the CreateInstance method. Since this is C++ those objects have to be deleted (or at least logically freed, if some sort of pooling is in place) at some stage. But the factory interface does not help us there, so we can only guess how deletion is supposed to be done. This is a case where introducing the symmetric method DestroyInstance might make sense. That makes the code look like this:


class CClassFactory :  public IClassFactory
{
CClassFactory() { }

public:
CClassFactory(const COCLASS_REGISTER *pCoClass) : m_cRef(1),m_pCoClass(pCoClass)
{ }

// snip

virtual HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid,
void **ppvObject);

virtual HRESULT STDMETHODCALLTYPE DestroyInstance(void *ppvObject);

private:
LONG m_cRef;
const COCLASS_REGISTER *m_pCoClass;
};

Adding symmetric operations to interfaces is not a fast rule. That DestroyInstance method might not be necesarry in the case above - I haven't diged deeply into the Rotor code, so I don't know. But if you're in doubt, and including the symmetric operation(s) doesn't seem un-economic, make the interface symmetric.

1001: Use one abstraction level per method
This a classic from Martin Fowlers Refactoring book: In order to write nice readable methods use only one level of abstraction within any given method. If a method contains some code that operates on a higher level of abstraction, and some code that operates on a lower level of abstraction, the lower level code should be extracted to a separate method.
Operating on only one level of abstraction in each method allows the reader to stay on that level of abstraction when reading the method, which is a lot easier than mentally jumping between levels of abstraction. Furthermore the reader knows that he is going down to a lower level of abstraction when going into the implementation of a method, B, which called from another method, A.
To illustrate take a look at this lovely piece of (in-production) Java code:


private void init() {
try {
server = new ServerSocket(Integer.parseInt(PersistentData.getStringValue(PersistentData.UDP_PORT_MLPI,
PersistentData.UDP_PORT_MLPI_DEFAULT_VALUE)));

javavendor = System.getProperty("java.vendor");
System.out.println("Java vendor: " + javavendor);
if (javavendor.startsWith("Sun ")) {
m_DatagramThread = new
DnDatagramThread("localhost",Integer.parseInt(PersistentData.getStringValue(PersistentData.UDP_PORT_WCTRL,
PersistentData.UDP_PORT_WCTRL_DEFAULT_VALUE)));
}
//snip
} catch (java.net.BindException e) {
System.err.println("A previous instance is already running...." + "\nCannot run application: " + e.getMessage() + "\n" + e);
System.exit(1);
} catch (final java.io.IOException e) { // an unexpected exception occurred
System.err.println("Cannot run application: " + e.getMessage() + "\n" + e);
System.exit(1);
}

m_properties = new HashMap();
m_splashScreen = new SplashScreen();
ErrorDialog.instance().setInitialWindow(m_splashScreen);
ErrorDialogCheck.instance().setInitialWindow(m_splashScreen);

progress(5);
setupDebug();
progress(10);
}
This code opens a socket - one level of abstration - then creates and sends a datagram over that socket - another, lower, level of abstraction - and goes on to display a splash screen - a third, higher level of abstraction. Having those three levels of abstraction means that the reader has to think about sockets, protocol specifics and GUI simultaneously to grasp what is going on in the code. That's not separation of concerns. That's spaghetti.

1010: Grow GUTs
Grow some GUTs while developing software. That is grow some Good Unit Tests. Good unit tests express and test the intended functionality of the code under test. It covers not only the different paths through the code, but all the requirements that the code under test is supposed to fulfill.
Most of the unit tests I see revolve around the implementation details of the code under test rather than the actual functionality. Lots of test suites are build by creating one test method per public method in the code under test. Each of these test methods try to cover one method from the code under test. This usually means that most of the tests only check very superficial things, and then one or two of the test methods test an awful lot of things all at once because try to cover the one or two central public method of the code under test. These large test methods become unwieldy, while still not covering the entire functionality of the code under test. Basically the public interface of the code under test is bad unit test template - a BUTT. And who wouldn't rather grow their GUTs than their BUTT?
For a thorough write-up on good unit tests I recommend Kevlin Henneys StickyMinds series ([1], [2]) on the subject.


1011: Prefer use over reuse
Writing re-usable software is something lots of developers want to do. Writing re-usable software is also really hard. In fact, writing usable is hard. And if software isn't even used it certainly won't be reused.
Moreover aiming for reuse in the first iteration over a software design tends to make the design bloated and unclear (i.e. un-economic), because the requirements to the software are unclear, and because there are multiple scenarios in play that the design tries to accommodate. That sort of bloated software will just end up sitting unused on your hard drive. To counter that, focus on one scenario that you're sure of. Prefer to make something that is used in just that one scenario. Then go on to build something that is used in one other scenario. Then go on to build something that is used in a third scenario. Only then, after a number of instances of use, think about reuse.

That's it for now.

Thursday, September 24, 2009

Four Bits of Advice: Another Bit

This is the third post in a short series of post about developper adivce ([1], [2], [4]). The first one listed 16 pieces of advices in the form of headlines. The second post briefly explained the first 4, and this post is about the next 4:


0100: Consider infrastructure orientation
Where should infrastructure code go? Well, what is infrastructure code? It's code enabling domain objects to be used by the infrastructure parts of an application, like data persistence parts, the serialization parts, or the remoting parts. Often such code is added to domain objects in a vertical manner via inheritance, resulting in something along the lines of:















This works fine in a lot of cases, but there is the alternative of having the domain objects contain references to infrastructure objects, and letting them delegate to the infrastructure code when needed. That alternative results in a horizontal arrangement of domain and infrastructure code, which looks something like this:


The point is not that orienting infrastructure code horizontally is better than vertically. The point is that it is worth evaluating both option when designing a piece of software.

0101: Use role based interfaces
Interfaces, as in C# or Java interfaces, should define a single role an object can play. An object, on the other hand, can play several roles, and therefore it is perfectly all right for a class to implement several interfaces. This opposes a style of programming often seen in both C# and Java: Given a class called Foo, there is an interface called IFoo. The only class that implements IFoo is Foo, and all the public methods of Foo are implemtations of IFoo methods. An interface like IFoo does not add much value: It does not express or define anything that the public interface of Foo does not already express and define. The only thing IFoo adds is a test seam. Granted test seams are important and valuable, the same seam and more seams are available if Foo implements a number interfaces each defining a role. These roles make sense in terms of the application and its domain. Therefore they make the software easier to read, and with any luck more flexible.
For more on this I recommend Martin Fowlers post about role interfaces.

0110: Be economic
Do waste resources unnecessarily. Specifically: Do not make interfaces larger than they need to be. Do not add extra features to interfaces "just in case", or "because I can". The same goes for larger designs. Adding that extra stuff is wasteful, because you have to spend time writing it, because other programmers have to spend time reading and understanding it, and because it needs to be tested. Furthermore the shorter more concise implementation is usually the more elegant.
For more on this read through Kevlin Henneys slides on economy and elegance.

0111: Prefer code over comments
Comments can and do lie. Comments become obsolete and out of date. Comments are overlooked by programmers. By contrast, code is actually read by programmers, code is and stays current, and code with good naming can often express what would otherwise have been written in comments.
Thats it for now.