Monday, May 06, 2013

On "Testing and Refactoring Legacy Code"

I finished watching Sandro Mancuso's "Testing and Refactoring Legacy Code" excellent coding kata on InfoQ and I saw there a couple of practices which I can hardly wait to use in real (legacy) projects.

Although that the overall movie quality is not so good, I had no problem understanding the code and the incremental refactorings.

What I liked the most were the practical pieces of advice that are meant to transform developers in real software craftsmen.

On my TODO list:

  • split editor when writing (or reviewing) test code
  • add tests from shortest to deepest branch
  • refactor from deepest to shortest branch
  • use coverage tools when adding tests
  • introduce builders quickly
  • use MockitoJunitRunner 

Sunday, April 21, 2013

Code Review Goals

I did a huge number of code review sessions in the passed years, gathered a lot of experience from my mistakes and I thought now it's a good time to share my findings with the world!

Finding 1:  Code reviews must be taught and learned


It doesn't seem obvious that a simple code review needs to be learned. If you have an intermediate or senior developer in your team, he or she should be capable without too much effort to do a "proper" code review, right? 

Well, from my experience this is not always true! Becoming a good reviewer like becoming a good coder takes time and practice. Although good engineers have a good sense of how a good code should look like, they are not always comfortable with the review process itself, it's underlying goals and benefits, approaches, etc. Same thing applies also for the ones that have their code reviewed.

For one of the projects in my current company I started to teach people how to do reviews by themselves and the results were simply outstanding: from a team of people highly reticent to have their code reviewed, the team arrived at a point where reviews were asked remotely by people working from home being in sick leaves, reviews were ranked as "properly made, with serious benefits, with a lot of discovered bugs" in team's retrospectives.

How did I do it? I invited as a first step in each review an additional developer to assist me, than in time I became the assistant and afterwards I didn't have to participate at all.
After a while everybody knew what they needed to do. I must admit I had my share of good reviews after that moment, a lot of bugs were prevented also in my code by my pear reviewers.

Finding 2: Review goals need to be defined and agreed


When trying to teach people how a good review should be performed, discovered that problems exist in understanding the purpose of various review activities. The easiest way to overcome this problem was to create a shared document that contained the goals of the various code review activities.

The goals and underlying review tasks looked like bellow:

Review Code

Goal: Reviewer must gain understanding on the reviewed part and be able to continue working on it if necessary

Reviewer must know what the code should do.
Reviewer must understand all changed code.



Goal: Reviewer must make sure that the code can be easily maintained

 
Reviewer should focus on naming and spotting bugs.
Check changes using "show differences" option



Goal: Reviewer must make sure that new changes are well integrated with the existing code.

Have a look over the entire class (maybe some refactoring can be done)

Review Tests

Goal of test review: Tests are more important than the code itself, they are our safety net!


Goal: Reviewer must make sure that tests will avoid bugs

Check that Not Only “Happy path” is covered


Goal: Reviewer must make sure that tests will help preventing "maintenance hell"

Check if integration tests can be replaced by unitary tests

Finding 3: Face to face reviews are priceless


Although there are a lot of tools that can be used for reviews (and used myself for quite a while ReviewBoard), discovered that at least in the early stages of project face to face reviews are priceless! 

When a team is forming, when the team members don't share a common language and the same set of values, the face to face reviews could become a real benefit. 

In these early stages it doesn't even matter if a review session discovers a bug, or not. What's most important here is that the team members have an extra chance to share their visions and set of values!

I know that you can loose some benefits when doing face to face reviews without using any review tool - collaborative reviews are no longer possible, reviewer has not enough time to try thinking out of the box, etc. But nevertheless, I will always opt for "face to face" if I'll have a choice! 

The real benefits


The real code review benefits? The shared language between developers, seeing my team growing, seeing that there is no difference in terms of quality and standards between our code and existing famous open source code, and so on!

Thursday, January 31, 2013

On leading teams

I recently saw a presentation that opened my eyes on some points I probably should have known about long time ago. For me it was a breakthrough, and I apologize I wasn't aware of them sooner.

First of all, regarding the question: "What is my top responsibility as a team lead? What should be the No. 1 in my TODO list?". The simple answer is:

Keep asking myself how my team has improved in the past interval: how my team has improved in becoming a team, how my team has improved in doing things, how my team has improved in becoming a super team, how each member of my team has improved himself/herself, how did I improve myself for my team, how did I improve myself for myself...

If I am not at least thinking about that, I am just a programmer with special attributions!

Secondly, I realized that nothing can improve out there in the comfort zone. If I'm leaving you in your comfort zone, and I stay in mine, we might be more comfortable with each other, but we won't in any way progress in anything.

So If I don't have the guts to challenge somebody or myself out of his/her/mine comfort zone, I am just a programmer with special attributions!

Thirdly, I realized that I can easily become an impediment for my team. Yes mister Scrum master, you can easily become an impediment for your team! If somebody comes to you complaining about the WiFi in the meeting room and you don't ask him "what will you do about it?" but just forward the question, you're on the right track in becoming impediment.

Fourthly, I realized that broken window theory doesn't apply just to failed unit tests but to any practice you would like to have in your team. Skip a code review once, and code review will become optional, skip a retrospective, and all the retrospectives will become optional or nice to have, just break the window and everybody will know it's save whatever they want.

So if you have an hour, enjoy the movie, it contains also other cool stuff: Code Leaders and Beautiful Teams

The guy's site is pretty helpful too: 5whys.com












Sunday, January 27, 2013

Bye Eclipse, Hello Intellij!

I know it's a religious war out there with thousands of followers on each side, that's why I won't just say that Intellij is better than Eclipse or the other way around.

I always tried to replace the tools that slow me down and unfortunately Eclipse started to become such a tool for my current projects where Maven and Git are used intensively. Between me and you, m2e and eGit eclipse plugins still need a little work in order to become really useful.

So, how do you replace your favorite IDE with a different one? What are the steps, does it really pay off?
I can tell you what worked for me, I hope it will be helpful.

Stop using Eclipse if you want Intellij

I tried for a while to use both tools in parallel and it didn't work at all. Each time I had a "problem" I went back to my good old Eclipse to solve it. This way the amount of time spent with the new tool was reduced and no progress seemed to happen. 

I only started to become productive with IntelliJ when I decided to quit using Eclipse!

Start by learning one aspect at a time

How do you enter a new Universe if not one step at a time? 

I first started to read code using IntelliJ - focusing on view elements and shortcuts that helped me to navigate between various classes and code fragments. 

After that I started to write code so I only focused on editing, code completion, refactoring aspects.   

Then I focused on build system, debugging, and so on...

Pair programming

If you have someone out there using IntelliJ, start pairing with him! I learned a lot of things very quickly just by sitting near somebody who knows the tool. It takes minutes to learn a new trick visually and hours to find it by reading documentation!

Use tools

There are tools out there that help you do anything. Even learning IDEs.

I started to use Key promoter and I am very happy with it! It really helps you learn shortcuts you didn't even know exist.

Does it pay off?

In terms of productivity certainly yes, I feel it everyday. It really makes my life on my current projects easier.
I started to use it also for my home Android project - the UI Designer is quite cool!


 

Friday, September 03, 2010

ExceptionHandling

Although java constructs used in exception handling are well known to almost everybody that has some java experience, I discover each day that a lot of people know too little about how java exceptions should be used.

Instead of using them as allies in producing more elegant and robust code, I see that a lot of people treat exception like an unnecessary evil that comes along with the java modules they use. They treat this evil in no time: a simple catch is enough in almost any situation!

Useless to say that interacting with Java's exception handling mechanism in a catch the evil as quickly as possible manner usually leads to long hours (days, weeks) of debugging, frustration and in general to not so elegant solutions to problems.

So, if you intend to build your super-elegant java module, reduce the if statements in it, make it more readable, or simply want to see typical mistakes performed with java exceptions, you might have a look at the following exception crimes and practices. As their names suggest, the exception handling behaviors are scaled from big mistakes to reasonable approaches:

biggestCrime() -> bigCrime() -> ...
-> towardsExceptionHandling() -> basicExceptionHandling()

There are situations when biggestCrimes are justified, therefore the names only apply to 99.99% of situations!

1. Biggest Crime

The rationale: Developers are in a hurry, they must deal quickly with the evil exception to have more time for the important matters.

The code:
public void biggestCrime(){
try {
complexCodeBlockThrowingSeveralExceptions();
} catch (Exception e) {
//no time for this now, I'll deal with it later
}
}
The consequences:

Developer usually forgets to come back to the block of code. As a result, sometime later when a exception will occur, the system won't crash in the obvious place or form, but usually in an unrelated part like one the following :
  • when reading some strange values from the database
  • when displaying some info on the screen
  • when saving the project, etc.
Useless to say that fixing a bug like this could take hours and sometimes days or weeks.

2. Biggest Crime Variation

The rationale: Developers overestimate their knowledge about the raised exceptions or just blindly trust the specs they are implementing. The "I know this won't happen in our case" scenario.

The code:
public void biggestCrimeVariation(){
try {
complexCodeBlockThrowingSeveralExceptions();
} catch (Exception e) {
//I guess that this won't happen to me
}
}
The consequences:

Only the comment differs from the previous case: same consequences!

3. Big Crime

The rationale: Like in the scenarios above developers overestimate or are in a hurry. They do have still some doubts about their behavior.

The code:

Logger log = Logger.getLogger(ExceptionCrimes.class);

...

public void bigCrime(){
try {
complexCodeBlockThrowingSeveralExceptions();
} catch (Exception e) {
//I know that this won't happen,
//but I log something "just in case"
log.error(e.getMessage());
}
}


The consequences:

A big improvement as opposed to the previous cases. When an exception will be raised, if you have eagle eye you will see a small line in the big fat log file saying that something might be wrong somewhere in the code.

The log line will be prefixed with the precious ERROR keyword, the message itself will be usually completely useless: "null pointer exception", "file not found exception", etc.

4. Big Crime Lazy Variations

The rationale: This scenario is very similar with the one above. There are still two differences: developers are lazy (they like CTRL + F1 - quick fix - editor options like "Surround with try catch"), developers are not lazy (they are never lazy for copy-paste operations!)

The code:

Logger log = Logger.getLogger(ExceptionCrimes.class);

...

public void bigCrimeLazyVariation(){
try {
complexCodeBlockThrowingSeveralExceptions();
}
catch (IllegalArgumentException e) {
//I know that this won't happen,
//but I log something "just in case"
log.error(e.getMessage());
}
catch (FileNotFoundException e) {
//I know that this won't happen,
//but I log something "just in case"
log.error(e.getMessage());
}
catch (NullPointerException e) {
//I know that this won't happen,
//but I log something "just in case"
log.error(e.getMessage());
}
}


The consequences:

Same behavior like for the previous case: We have the same code, but in a less readable and maintainable form!

5. Regular Crime

The rationale: This scenario is very similar with the ones above. The important difference is the stack trace: the developers know what it is, that it saves time when maintaining code and how to include it in the log!

The code:

Logger log = Logger.getLogger(ExceptionCrimes.class);

...

public void majorCrime(){
try {
complexCodeBlockThrowingSeveralExceptions();
} catch (Exception e) {
//I know that this won't happen,
//but I log everything "just in case"
log.error(e.getMessage(), e);
}
}

The consequences:

Massive improvement from the maintenance point of view. When the system crashes, the log file will record a long (and easily identifiable) stack trace prefixed by an useless error message.

The major improvement consists in the fact that the log signals the system's failure when the failure occurs. (Fails fast)

6. Still A Crime

The rationale: Developers still don't do exception handling, but they don't like useless error messages either!

The code:

Logger log = Logger.getLogger(ExceptionCrimes.class);

...

public void stillACrime(String param){
try {
complexCodeBlockThrowingSeveralExceptions();
} catch (Exception e) {
//I know that this won't happen,
// but if something will happen, I'll add a better message!
log.error("Could not access my desired module", e);
}
}

The consequences:

Massive improvement from the maintenance point of view. When something wrong happens in the system, one will know what happened from the system's point of view!

7. Minor Crime

The rationale: Developers still don't do exception handling, but they know information needed for effective exception handling!

The code:

Logger log = Logger.getLogger(ExceptionCrimes.class);

...

public void minorCrime(String param){
try {
complexCodeBlockThrowingSeveralExceptions();
} catch (Exception e) {
//I know that this won't happen,
// but if something will happen, I'll log all that I can!
String err = "Could not access my desired module. Used param: "+param;
log.error(err, e);
}
}

The consequences:

Massive improvement from the maintenance point of view. When something wrong happens in the system, one will know what happened from the system's point of view and in what context without looking at the code!

8. Exception Handling Crime

The rationale: Developers do know exception handling mechanisms, but they do not know the stack trace!

The code:

public void exceptionHandlingCrime(String param){
try {
complexCodeBlockThrowingSeveralExceptions();
} catch (Exception e) {
//this is a known problem I will deal with it in the upper layers!
throw new MyModuleAccessException("Could not access my module's configuration file");
}
}

The consequences:

Logging is not performed everywhere (in the lower and upper layers), but only in the upper layers.
The meaningless "null pointer exception" has become "cannot access my module" simply looking at the exception's name.
Some detail information is given - a configuration file is missing.

Still: hard to identify the exception in the log file, no context at all.

9. Towards Exception Handling

The rationale: Developers do know exception handling, do know the stack trace, but don't give enough context.

The code:

public void towardsExceptionHandling(String param){
try {
complexCodeBlockThrowingSeveralExceptions();
} catch (Exception e) {
//this is a known problem I will deal with it in the upper layers!
throw new MyModuleAccessException("Could not access my module's configuration file", e);
}
}

The consequences:

In addition to the previous case, we have the stack trace, but we still have to look at the code to see the exact context.

10. Basic Exception Handling

The rationale: Developers do know exception handling. They do know the basics of using custom exceptions and their benefits.

The code:

public void basicExceptionHandling(String param){
try {
complexCodeBlockThrowingSeveralExceptions();
} catch (Exception e) {
//this is a known problem I will deal with it in the upper layers!
throw new MyModuleAccessException("Could not access my module's configuration file on physical path: "+param, e);
}
}
The consequences:

When something wrong happens, we know and we know exactly what happened!


Epilogue

The consequences for the ten scenarios above should not be taken to strictly. Sometimes, usually from performance reasons, all scenarios above can be justified (input-output operations take time, evaluating expressions when logging is time consuming and potential source of programming errors, etc.).

But then again, premature optimization is the root of all evil: it's easier to optimize well organized, working code, than to follow, maintain, test, prematurely optimized code!

As a summary, the following rules of thumb helped me a lot when dealing with exceptions:
  • re-throw them if you don't know the fix
  • log them with stack trace and detailed context if they are unexpected
  • add more system related information when re-throwing (say more)

Thursday, August 05, 2010

Agile comunity growing in Timisoara!

Last week I had my first Meetup on the Timisoara Agile Software Meetup Group!

Although I was at first reluctant to go since I knew almost nobody from the Meetup's members, surprise - surprise, my general impression was surprisingly good!

Attended a well prepared, well structured and very interactive Unit Testing presentation together with experienced/un-experienced agile practitioners and wannabes. It felt good to see so many people there - all in their free time, the majority of them drove there simply by passion.

Another plus for the organizers were the cookies! We had free coffee, drink and cookies. Sharing food always creates magic.

What I missed was only "the beer after": some time dedicated to free and direct conversations, the real meet. A lot of persons approved - next time we'll have a beer after, so if you come, be prepared for half a day of agile discussions and beers!

Monday, July 19, 2010

Mini Super Search!

I am very pleased with my Google Search gadget on my blog, it is just great!

It helps me keeping up-to-date with new technologies, it helps me solve real problems, it became the friend that I can trust when I need to quickly do something great, it just beats Google itself!

How? Simple: It does not return all results like a regular Google, but filters the results through the hands I trust in: Martin Fowler, Uncle Bob, InfoQ, etc. This way I don't loose time filtering information, I let the gurus do the filtering for me!


The example here, pointed me perf4j on page 1 just when I needed it.

It rarely returns results on "This Blog" tab, but always returns valuable information on "My Followed Blogs" tab (aka Marin Fowler, ThoughBlogs, ObjectMentor, InfoQ).

Usually the desired result is in page 1 of the results!


Feel free to use it, use my acknowledged gurus to filter your information!