Thursday 30 August 2012

Some development tips and tricks


These are just some tips and tricks I learnt over my career that I'd like to share. This list does not contains silver bullets and it doesn't pretend to be complete or be an absolute truth. It's just a list that I hope may be helpful for someone.

1 )  Push the coding to the last

This point can be also be read as think before coding. I found myself, lots of times, especially in the beginning of my career, in rush of writing classes, methods, interfaces as soon as I was receiving a spec for a new functionality.
This impulse turned out 90% of the times into a PAINFUL situation. The spec was unclear and so unclear was my code; The spec was too "code oriented" and so blindly coding this was producing wrong design/ implementation that needed to be trashed out and completely re-designed;
Many other are the disadvantages of writing code straight away after receiving a spec. So, lesson learnt and this is what I'm doing now after receiving a spec/story to develop:
  1. I stay away from the keyboard!
  2. I print the spec (sorry amazonian jaguars ) and I take my time to read them carefully. Do not think that everything you will read there is exempt of mistakes or cannot be done in better and simpler ways. At the end of the day, people who wrote the specs, know little or nothing about the software, what they know is how to make more money with new functionality.
  3. If something is not clear to you, it will not clarify magically by itself if you start to code. Ask questions to other colleagues, to the business, clarify as much as possible and only when you feel confident, when you see the real pitcure of what they really want, then and only then you can switch the monitor on and click on the eclipse icon...

2 )  Simple = perfect

Make the 2 famous principles, KISS and YAGNI,   part of your blood, skin and bones. Strive for simplicity, forget about the trends,  focus on the most basic thing that will give you what is needed. Don't think straight about XML configuration, spring/seam framework, drools, aspects, multithreading solutions, ejbs, or whatever complex/cool technology you know or you heard out there, nobody really cares about the technologies you use.
What everyone cares is that your code does what is supposed to do, it is READABLE and it is MAINTAINABLE.
Pure java is enough to cover 90% or more of everything you need. Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live. Make him happy, write simple, clear straightforward code.
I remember I read somewhere that, if you read your code after 1 or 2 years and you immediately understand everything is doing and you cannot simplify it more, than your code is PERFECT.

3 )  Paper and pen

I never found a tool more useful than paper and pen to design software.
Before writing software I usually spend a bit of time trying to put the idea of the design down on paper.
I then , if in doubt, go through it with a colleague. Because it is on paper I can fast go to the point with my pair and he can quick tell me if I'm missing something.
Knowing that you are missing something in a piece of paper, it's far way better then knowing that you are missing something in the code!
So don't waste time using UML tools, unless what you are doing is big-fantastic-amazing-new  architectural prototype.

4 )  Don't leave for tomorrow what you can do today

If you are fixing a bug or adding new functionality and you notice in the existing code, DUPLICATION or BAD NAMES  or a POSSIBLE BUG then FIX IT IMMEDIATELY.
Don't wait for the next sprint and don't add a technical story in the technical backlog. Technical stories laid in the backlog for long time, when/if  it will be the time to work on it, it will be more complicated to re-understand the context of the problem and fix it.
The exception it's when the fix/refactoring is too complex and required long time, then it's appropriate to create a story in the technical backlog!

5 )  You have time!

Really, you have time! Don't rush. There is no competition and you are not at the programming Olympics.
Your job is to deliver good quality code. That's it. This is your job!
If you feel that a task takes longer that what you initially estimated, just make the team aware in the next stand up and that's it.
If a client/manager is screaming above your shoulders because he wants something faster than you can deliver, it's not your problem!!! When they say "I want this functionality to be ready asap" translated in Truthlish it means "I want this functionality to be PERFECT with NO BUGS asap". They will be happier to wait more and have less bugs than having a fast release full of issues.
So take your time and be intransigent on the quality level of your software and forget about external pressures!

6 ) Implement leaves first

So, you just received a brand new story to develop and you want to implement it right.
For example the story is about calculating item prices. One price for each item. Each price is obtained with a different calculation.
Choose one item price logic and as first thing write a unit test against this logic. Don't be stressed about implementing the whole design or writing interfaces, abstract classes etc. Focus on one small leaf per time!
When the first leaf is finished, start with a second test for the second small logic you want to implement. The design will come out almost by itself. The tests will tell you which direction is best to take.

7 ) Do Pair programming!

I fully applied this technique only recently (less than 1 year ago) and I have to say, it's powerful! It is twice productive than working alone, the quality of the code is superior, the development speed is increased.
A strength of this technique is the fact that is funny. being funny and so more stimulating means that you are more focused and you pay more attention to details.
You can learn a lot doing pair programming, so push for it as much as you can!

8 ) Rarely use checked Exceptions

Every time I use an API that force me to put around its method call the try and catch block, it makes me nervous, like a violent psychopath, but often I don't know where they leave. Especially if there is nothing I can do about the exception. What the hell I' m supposed to do with this error?
If you want to use checked Exception used them ONLY if the client can reasonably recover from it at run time! Remember that checked exceptions will spread all over your design in case you need to extend the behavior!

9 ) Say NO to Hacks

Programming is like sex. One mistake and you have to support it for the rest of your life. (Michael Sinz). And Hacks ARE mistakes!

Simply don't implement hacks. I did it in the past, for whatever reasons ( no time,pressure, desire to release a feature as soon as possible, managers screaming, Orcs, Leprechauns, whatever), and now after years we need to maintain them. Hacks are difficult to understand,they break the normal logic flow of your code and they are hard to die! You implement an hack today and tomorrow (1 year after maybe ) someone else will need to fix a bug on this hack and ..well good luck with that!
Spend more time on the spec if the hack is a business request, and explain why this will cost a lot to maintain. Propose other solutions, discuss it with your team, a better solution is on the way!

10 ) Forget about comments, just write proper names!

Write proper names when writing packages, classes, methods and variables.
Write names that make sense, ask a review before committing your code, but don't explain verbally what you have done, try first letting your reviewer read the code, and see how good you were in writing self explanatory code!
Comments need to be maintained, otherwise they are misleading. How often did you fix a bug in the code and you changed the class documentation?me, rarely!Use javadoc only if it is really necessary!and if you do,then remember to update them every time you change the code and enforce the same behavior in your team!

11 ) Reinvent the wheels

Read books, blogs, tutorial, etc as much as possible, but always with a critical and open mind! The same apply when listening to your team or leader. Don't be fooled by authorities, think always with your own mind.
If you decide to go for some approach it must be because you believe in it. Because you see good reasons to do so. If you feel that something could be done better or you see problems in the approach you are using , discuss it with your team and try to clarify your doubts. If after talking to the team you still feel that things should be done differently, then push for better approaches and fight for your ideas!
Sometimes, to progress, you need to reinvent the wheels or at this time we were all developing in FORTRAN.

Thursday 2 August 2012

A simple way to test distributed applications

So, testing distributed applications is not easy, we all know it.
Too many variants to take in considerations which usually lead to an high instability of the tests.

Let say we have a front end application sending messages to a distribution engine which then forward the messages to other remote destinations. Sounds familiar?

OK so, how you test that messages travelling correctly trough all the predefined servers?

What if I want to keep my tests independent from any integration framework?

My solution is in the logs.
Why not rely on the logs to prove that your application is working as expected?

Logs are often underrated for performance/acceptance/smoke tests, but if correctly written, they can provide all the information you need to measure the status of your software at any point of its execution.

Testing relying on logs is a non intrusive way to test and no performances or anything will be affected. Applying this concept to an hypothetical integration test it's easy (at least in UNIX environments :) ), thanks to libraries like Grep4j:


import static org.grep4j.core.Grep4j.grep;
import static org.grep4j.core.Grep4j.regularExpression;
import static org.grep4j.core.fluent.Dictionary.on;
import static org.grep4j.core.fluent.Dictionary.executing;
...

@Test
public void aCreateMessageShouldPassThroughAllTheFinalDestinations() {
  List profiles =  Arrays.asList(distributionServerLog(),
                                 destination1ServerLog(),
                                 destination2ServerLog(),
                                 destination3ServerLog());

assertThat(executing(grep(regularExpression("MessageId(.*)Received"), on(profiles))).totalLines(), is(4));

}


As you can see, in a very simple way you have an efficient end-to-end test across different machines.

I think this approach is also a good option when you want to build acceptance or regression tests around legacy applications. You can treat your legacy app as a black box and just test the expected output in the log. 

Finally, I reckon this way of test will force the developers to standardize and uniform the way to log in the code which is always good :)