Archive for September, 2008

Beware The Evils Of Code Generation

20 commentsWritten on September 22nd, 2008 by
Categories: Opinions

We have this rather large project at work, one that's been in development for a few years now. This project has had many releases already, and from a business perspective, is quite successful. From a technical point of view, there were definitely some things that could've been better. The largest problem is that this project uses a very extensive code-generation process. This code generation process basically retrieves all of the database metadata and generates an entire Data Access Layer (based on basic ADO.NET), a shitload of automated tests to cover that entire DAL, a whole lot of extra classes which form a data-driven business layer (real business logic can still be added though), and again, a shitload of automated tests that cover the data-driven business layer.

Now, the people who originally came up with the code generation obviously had good intentions in mind. They wanted to maximize developer productivity so everyone could implement the required features as fast as possible. And that's pretty much the reason why people turn to code generation: to increase productivity. Code generation however, is not a good way to do that. In the short term, it definitely increases productivity though. But it comes at a terrible cost: an incredibly large technical debt. The thing about code generation is that it's basically a shortcut. When it comes to developing software, each shortcut brings some kind of technical debt with it, and sooner or later, you have to pay off that debt, or risk having your knee caps shattered (why yes, i am watching my Soprano DVD's again!).

Now, the technical debt you incur by implementing a certain feature in the quick-n-dirty way instead of doing it properly from the start is in most cases small and easy to pay back if you don't put it off too long (obviously, it's best to simply avoid having to incur any technical debt in the first place). Generating an incredibly large library of code, and then using that code all over the place has an impact that you simply can not recover from when the project has been in development for a long time. If you want to make serious changes in your generated code so you could, for instance, reduce coupling to concrete classes, you may be in for a rough ride.

In our case, most of the things you could do with the generated code could be done in more than one way. Every possible usage scenario was being used at least somewhere in the application's code base. And not just in a few places, but pretty much all over the code base. This made it pretty much impossible to make changes in the templates that would be used to generate the code, which would introduce compiler errors at least somewhere in the system. And not just a few of them, hundreds of them. Sure, you could start fixing them. And then you could start on your next change in the templates, and it would lead to a few hundred more compiler errors. If you'd simply have to change a bit of syntax here and there, it would be painful, but at least it wouldn't be something you couldn't overcome. But if you want to change the behavior of the generated code, you're in pretty big trouble. All of the code that uses the generated code expects certain behavior to occur. Changing the templates would mean changing a lot of the real code.

When you're in a situation like this, Michael Feathers (author of Working Effectively With Legacy Code) can't even help you out. Hell, even Batman would run away like a frightened schoolgirl. Which is basically what we did too. We decided to leave the generated code and the real code as is for now, and we came up with a new architecture (with no code generation) which we're going to use to develop the new functionality. The old code will slowly be migrated to the new architecture whenever we have room to do it, or whenever we need to make serious changes. It's not perfect, but starting completely from scratch is an approach that wouldn't make a lot of business sense anyway, and you have no guarantee whatsoever that the 'new' system will actually catch up with the 'old' system in a timely manner.

I think this serves as a nice example of how a code generation based approach can really come back to bite you in the ass like Jaws with a vengeance. Everything you gain in initial productivity costs you a lot of flexibility in the long term, which (also in the long term) ends up costing you more productivity than you ever gained in the first place.

Always keep in mind that code generation is usually a solution to a problem that wasn't solved properly in the first place.

When Commented-Out Code Is Acceptable

6 commentsWritten on September 21st, 2008 by
Categories: Opinions

My fellow Dutch ALT.NET member Jan Van Ryswyck wrote a post about how bad commented-out code is. I also truly hate it when i see code that is commented-out. It's such a waste of time because every time i see it, i immediately start wondering "is this something that we still need to add? Does it simply not work yet? And if so, why not? Who the hell did this? Why is he wasting my time?". Putting code in comments and leaving it there is generally a sin.

However, there are two situations where i do find it acceptable. Dare i even say helpful. The first situation is when you've made a very non-obvious performance improvement to a piece of code that was proven to be slow by a profiler. In those situations, i generally leave a comment saying something like "the following block of code was originally written as follows, but was proven to be a performance bottleneck". After that i have the original code in comments, followed by a description of what turned out to be the problem. After that, i put the modified code and then i'll have another comment discussing why the new code avoids the problem. I have to admit that this generally looks ugly. However, it does tend to avoid other people looking at the modified code and thinking "hey, i can make this much simpler" and then proceeding to write a more readable version of that piece of code which might re-introduce the performance problem.

The other situation is in a TestFixture for 'Learning Tests' (couldn't find a good link to describe this concept). Learning Tests are basically tests where you can experiment with a library that you don't have too much experience with. Learning Tests can be very valuable, but they generally don't need to be run after you've learned whatever it was that you were trying to figure out. But should you throw away the code after that? It might be useful to other team members. But i don't like to put it on Ignore either because each ignored tests feels like a leftover TODO to me. So in that case, i also put the code in comments.

Is Teaching TDD Worth It?

9 commentsWritten on September 21st, 2008 by
Categories: testing

There's a debate going on the ALT.NET mailinglist about whether or not teaching developers TDD for a project is worth the cost. I don't really like the way things are discussed on that list nowadays, so i'm posting my thoughts here.

First of all, it's definitely true that learning how to do TDD effectively takes some time and the learning curve is rather steep. If you need to bring people who are new to it up to speed, you definitely have to invest some time in that. So, is the time and effort spent on that worth it? I think it most definitely is. If you take the time to teach them how to do it properly, you can enjoy quite a few benefits.

For starters, the developers will improve their skills, not only in writing tests, but also in writing flexible and simple code. This can take some time, but if you're coaching them properly you should get this situation under control in a couple of weeks (somewhere between 2 and 4 weeks depending on the number of developers that need to be coached, and their general skill level). The quality of the code (and the tests) that they'll produce after this period can reduce your total future workload by a large quantity. I think most of us know what it's like to work with code that is anything but flexible, and what a negative impact such a situation can have on your team's productivity: things that should be easy to change, features that should be easy to add can become mind numbingly complex to implement without introducing bugs to existing code. I'll gladly coach a few developers for a few weeks if that means avoiding a code base where people are afraid to make changes or where change in general is lengthy and painful.

Also, during this period where you have to do intensive coaching, you can still make progress in the project. It's not like these developers have to learn these practices and principles on throwaway code. Have them work on real stories for the project. Double the estimates for those stories, and don't assign any stories to the person(s) doing the coaching. Make sure they have enough room to help the developers that need the help and that the code (and the tests) are up to standards before the stories are considered done. If you're coaching them right, you might be surprised how fast they'll pick up the pace. You'll definitely take a large productivity hit in the first couple of weeks, but after that your team's productivity will go up rather fast and before you know it, you'll have made up for all the lost time and with a healthy code base to boot.

Now imagine not investing that time and effort. Without even thinking about who's going to write the tests, or when they'll be written, suppose you decide not to spend the time and effort to teach them TDD. You start the project and everyone starts implementing features. Some people will write good, solid, flexible code. And some people won't. Their code might stay in this unhealthy condition, or it might deteriorate further. But hey, your team's productivity in the first couple of weeks sure is impressive right? Fast forward a month or two, then tell me how the productivity of your team is. It probably won't be as high as it was in the first couple of weeks. Oh, and keep an eye on team moral. Chances are that some developers will be terribly frustrated by some of their teammates' inability to write good code. The rest of the developers might be frustrated because some developers are too demanding and bitch too much about how bad their code is. All in all, chances are high that it's not going to be a fun team to work on.

Now, as for the teaching and the coaching... this can be a relatively easy job, or it can be a royal pain in the ass. It all starts with the developers' willingness to learn. If they are not willing, get rid of them. Yes really, get rid of them. You're only doing them, yourself and the rest of your teammates and your organization a disservice by keeping them on staff. If they are willing to learn, make sure that they realize that you are there to help them. If they are afraid or hesitant to ask questions, then you are definitely doing something wrong. They have to be certain that you will do the best you can to help them, and that they won't get ridiculed if they ask stupid questions. And let's face it, we all asked 'stupid' questions when we were learning these things so you sure as hell shouldn't make another developer feel bad when he/she is in the same position you were a few years ago. Also, when they do good, make sure you reward them by showing them more trust. You'd be amazed what kind of a positive effect that can have on a developer who's trying to learn a new approach. And never ever simply tell them what to do and what not to do. Make sure you explain everything! If they see you're taking the time to make sure they understand why you've given the advice that you've given, they will usually appreciate it and they will certainly learn a lot more than they would've if you had simply told them not to do something.

All in all, deciding against teaching people TDD is one of the worst decisions one could make IMHO. It may not always be fun and it may not always be easy, but in the long term, the quality of your project will benefit greatly from it. If teaching them TDD is painful, then you're either not doing it right, or you're working with people you probably shouldn't be working with anyway. But teaching TDD is generally not hard, as long as one party is willing to really teach, and one party is willing to really learn.

Recommended Books: Working Effectively With Legacy Code

2 commentsWritten on September 20th, 2008 by
Categories: Books

Just finished reading Michael Feathers' Working Effectively With Legacy Code. The book's main purpose is to teach you a lot of tricks on how to improve the testability of legacy code. As Feathers himself says, this book will not teach you how to go from bad legacy code to beautiful code in one go. That's not even possible anyway, unless you start rewriting the legacy code. Instead, this book shows how you can take small incremental steps to get your code into a solid test harness which will then allow you to start refactoring to good code more safely.

The book is divided in 3 parts. The first discusses the mechanics of making changes in code. The second part consists of very conveniently titled chapters that discuss common problems when changing legacy code. Chapters with titles like "I don't have much time and i have to change it", "How do I add a feature", "I need to make a change, what methods should I test?", "Dependencies on libraries are killing me", etc... You can quickly look at the table of contents and find the right chapter to help you with the problem you're facing at that time. The third part of the book contains a series of dependency breaking techniques that are referenced throughout the book.

If you are working on a legacy code base, do yourself a favor and get this book. Put it next to your keyboard, and use it everyday. You won't regret it.

Extending NHibernate’s DriverConnectionProvider

9 commentsWritten on September 18th, 2008 by
Categories: NHibernate

Ahh, i'm finally able to use NHibernate again at work, so expect more NHibernate related posts in the future :)

Today i needed a way to add some functionality when NHibernate opens a database connection, and again when NHibernate closes the connection. When the connection is opened, i need to setup some context on the connection for auditing purposes and it needs to be cleared again when the connection is closed. So i started searching on how to plug this into NHibernate. As usual, this was trivially easy to do.

All you need to do is create a type that implements the IConnectionProvider interface. In my case, i only needed to add a bit of behavior so i could just derive from NHibernate's standard DriverConnectionProvider class and add the stuff i needed at the right time:

    public class AuditingConnectionProvider : NHibernate.Connection.DriverConnectionProvider

    {

        public override IDbConnection GetConnection()

        {

            IDbConnection connection = base.GetConnection();

            SetContextInfo(connection);

            return connection;

        }

 

        public override void CloseConnection(IDbConnection connection)

        {

            ClearContextInfo(connection);

            base.CloseConnection(connection);

        }

 

        private void SetContextInfo(IDbConnection connection)

        {

            // ...

        }

 

        private void ClearContextInfo(IDbConnection connection)

        {

            // ...

        }

    }

Pretty simple huh? All you have to do now is to configure NHibernate to use this new ConnectionProvider in your hibernate.cfg.xml file:

    <property name="connection.provider">My.Assembly.AuditingConnectionProvider, My.Assembly</property>

Was that easy or what? If only all frameworks were extensible in such an easy manner ;)