Dahlia Bock

22Sep/101

Refactoring for the refactoring's sake

Imagine for a minute that you have inherited a legacy code base (According to Michael Feathers, a legacy code base is one that is largely untested, if at all) but also have a whole list of new features that you need to build upon the existing code with a deadline. What would you do?

Available options:
1. Rip the code apart and start the cleaning process before adding new features.
2. Pile the code for the new features on top of the existing ball of mud.
3. Is there a 3rd option?

The issue with Option 1 is that it might be a while before we can deem the code base ready for development of new features, and what is the proper acceptance criteria for refactoring stories anyway? I don't think Option 2 should be an option at all, because that would just mean we're shooting ourselves in the foot, screaming in pain, and doing it over and over again. I learned recently that another thing we could do is to tack refactoring on top of new feature stories, which means whatever existing code that you touch to make things work for the new stuff that you're writing, you should stop and clean it up and write tests for it. The problem, as with all refactoring tasks, is when do we stop? I don't think I've found a good answer to that question just yet, but just that it should be decided by the team.

16Jul/100

Setting up svn update in CruiseControl

It's been a while since I've had to set up CruiseControl from scratch because most of the time either the project is so deep into quicksand that continuous integration is the least of their problems, or there already is a CI server up and running, or the team has decided to use another CI tool.

One issue I had while getting it up and running is configuring CI to do an subversion update before doing a build. Make sure that the cruise config file has the following lines in a specific project:

<bootstrappers>
<svnbootstrapper localWorkingCopy="projects/${project.name}" />
</bootstrappers>

<modificationset quietperiod="0">
<svn LocalWorkingCopy="projects/${project.name}" />
</modificationset>

All the modificationset tag does is only check your repository if there are modifications but does not actually update the local working copy in your CI server. The svnbootstrapper is the one that does the actual update.

The documentation for svnbootstrapper was a little confusing because it says that it "Handles updating a single file (typically build.xml and/or build.properties) from a Subversion repository before the build begins" and doesn't specifically say that it would also be able to update entire directories.

I'd be curious to hear if people achieve the same results differently.

If anyone out there is on a Java project and starting to set up a CI build, I would actually recommend Hudson. It is free, and extremely easy to setup and you don't even have to worry about xml configuration files. You'll be up and running in 15 minutes or less.

9Apr/106

Why do I write tests?

It seems like I've been a testing nazi on the loose lately. I can't help it. It stresses me out when people say things like, "We've made a conscious decision not to write tests" or "Writing tests just takes too long. I don't see the benefit of spending my precious time doing that". So why do I do it? I'm sure I've spoken about one or more of the following points on previous posts but I shall do it again in (maybe vain) attempts to emphasize their importance.

1. Writing tests ensures me that what I'm currently developing works as expected.

2. Writing tests gives me the confidence to make changes in the code with little to no fear of breaking existing functionality. Change is inevitable in any software project and it's not fair to blame the appearance of defects on changing requirements. It's how we deal with change that matters. I think testing is one of the many ways of dealing with the risks and disruption that comes with change.

3. Tests (especially unit tests that run really fast) give me quick feedback. I don't want to have to write code, check it in, wait for a build to the QA environment and have someone else test it to verify that it works correctly. I wrote the code, I should be the one to test it.

It might seem longer to finish a story or functionality but in the long run, we'd be spending less time fixing defects, regression and otherwise, (and acquiring less heartache too) and more time building new functionality. It takes time to build up a comprehensive suite of tests and a lot of discipline amongst developers to keep up the practice but I believe it is worth it and I can't really work any other way.

10Nov/090

Book Review: Working Effectively with Legacy Code – Chapter 6

Working Effectively with Legacy Code (Robert C. Martin Series)

 

 

 

 

 

Working Effectively with Legacy Code by Michael Feathers

I've been carrying around this book with me for the past few weeks and I find myself going back and reading parts of a chapter again and again, trying to soak in the concepts. This particular chapter, titled: I Don't Have Much Time And I Have To Change It, struck me specifically when Feathers starts out talking about change and how often it happens in code bases and that steps should be taken to make every consequent change easier than the one before. When teams make it a point to only introduce changes to the code only if they have tests to cover that change, they find that their velocity slows down and people feel like they aren't getting as much done as they need to. Feathers emphasizes that this is normal but if they persevere, they slowly realize that they are revisiting better code and changes get easier and easier to make.

I think that it's important for teams to understand the benefits of testable code and how it eases the process of change so that they will invest the time and energy needed to get the code to that point. And I quote:

Ultimately, testing makes your work go faster, and that's important in nearly every development organization.

Having code that is testable is only possible if we do one of the following (If I remember correctly, I think this is according to Uncle Bob):

  1. Write the tests before writing the code
  2. Design for testability

Doing the latter isn't easy, and in fact it is so hard to achieve that people end up not doing it at all. So that leaves us with Option 1. But sometimes you come across code that doesn't have any tests AND doesn't look like it is testable, but you have to make some changes in a short amount of time. So what do you do? Michael Feathers suggests 4 approaches, and my colleague Mark documents it in a short and sweet way (basically he beat me to writing the post first).

  1. Sprout Method
    Advantages: Separating new code from old code. New code is testable.
    Disadvantages: You're giving up on the old code for now.
  2. Sprout Class
    Advantages: Allows you to move forward with more confidence.
    Disadvantages: Conceptual complexity - moving new code into a separate class disrupts the flow of how key classes in the code base work together.
  3. Wrap Method
    Advantages: A great way to introduce seams (this is a concept that Feathers talks about in a previous chapter, which we will visit in a later post) while adding new features.
    Disadvantages: This method requires you to rename the method that you want to change, and create a new method with the same name as the previous method before the rename was done. Sometimes this could introduce sloppy method names because we needed to do some renaming to make way for the new method.
  4. Wrap Class
    This method is pretty much the same as Wrap Method except you're extracting new behavior out into a new class. Feathers mentioned that 2 things push him towards choosing to use Wrap Classes and one of them is when a class has grown so large that he cannot stand to make it worse. Pushing behavior into a new class when the existing class is unmanageably large could also indicate that the original class might have too many responsibilities and thus needs to be gutted.

I like this chapter because it formalizes a lot of things that I try to do very often because of the large range of code bases that I work with, but find it difficult to nail it down to something that could be explained to someone else.

17Sep/092

Coding tip to self

Always leave your codebase in a better (or same, if you really can't make it better) condition that it was in before, never worse. Disregard for this rule is how codebases disintegrate, rot and die.

21Aug/090

Mocking: Mockito vs EasyMock example

Ever since I was introduced to Mockito about a year ago, I've been a big fan. I wrote a couple of posts about it and promised a long, long time ago that I would post an example of a test written in Mockito and one in another mocking framework. The lucky chosen one was EasyMock. My biggest plugs for Mockito would be:

  1. Test readability. Mockito tests are more concise and it discourages noise in test code.
  2. The ability to clearly distinguish test expectations from test verifications so that you know what exactly you're stubbing and what you're testing.

Here's an example of a class that I want to test: ProfileService.java. NOTE: Please ignore the design of the code itself. Let's just say that all I wanted to do was to test it's behavior without changing it. And I do know that it's not the best, in fact far from the best.

There is one method in that class which retrieves a Profile from the database and finds all the contacts associated with that profile and goes through all of them and if there is an application in a contact that is already Closed, an exception is thrown and I'm not allowed to close the profile. Otherwise, the status of the profile is changed to Closed and this is updated in the database through the repository.

ProfileService.java

Let's look at the EasyMock test first.

ProfileServiceTestWithEasyMock.java

Notice that test verifications, i.e. that profileRepository.updateProfile() was called at the end, are interchanged with test expectations, thus blurring the line between what you're setting up and what you're testing.

Now let's check out the Mockito version of the test.

ProfileServiceTestWithMockito.java

First thing you should notice is that the test is much shorter, yes, only by a few lines, but it's a few lines less confusing. The test is also easier to break into a logical given-when-then BDD-style scenario. There is also clear distinction between what you're stubbing (expectations and setup) and what you're actually testing (verifications).

I can't see how EasyMock promotes cleaner and clearer tests, I really can't.

21Apr/092

An interesting blog post about Mockito (and other mocking frameworks)

I've recently joined the mockito google group and this link was posted recently.

http://rrees.wordpress.com/2009/04/12/three-little-mockers

It mainly compares Mockito and JMock and how the author thinks that Mockito encourages developers to be lazy and allows classes to grow fatter in terms of functionality and collaborators. The author also thinks that Mockito encourages Test Driven *Development, while JMock encourages Test Driven *Design. Don't forget to read the comments too, that's where the drama's at.

What do you think? I haven't used JMock, so I can't speak myself. But to those who have, does JMock compel better code design because it increases the amount of noise in the code? Do you think there's a difference between Test Driven *Development and *Design?

Another interesting note is that there was a ThoughtWorks team in the same location as the author, and they were pushing for Mockito :)

6Apr/091

What about the small picture?

I saw this IBM ad at a bus stop today with the tag line, "Let's build smarter traffic" (or something along those lines).

smarttraffic

My train of thought went along these similar lines: "Hrm, that convoluted picture looks like the software that IBM churns out, i.e. Notes! Too often people are too caught up in the big picture, the architecture, the design, the little boxes and pictures on a piece of paper that represent a system but forget about the lines of code that the system is made of. If we dissect a millimeter of your system, would it still look like convoluted spaghetti code?"

When we are programming, do we follow the practices that make our code clean? i.e. meaningful naming for classes, methods and variables, small and testable classes, good error-handling, etc. I think these practices should be given as much attention as the elements of the bigger picture.