A few years ago I was fortunate enough to turn a corner in my programming career. The opportunity for solid mentoring presented itself, and I took full advantage of it. Within the space of a few months, my programming skills grew exponentially and over the last couple years, I’ve continued to refine my art. Doubtless I still have much to learn, and five years from now I’ll look back on the code I write today and feel embarrassed. I used to be confident in my programming skill, but only once I accepted that I knew very little, and likely always would, did I start to actually understand.
My Foundations of Programming series is a collection of posts which focus on helping enthusiastic programmers help themselves. Throughout the series we’ll look at a number of topics typically discussed in far too much depth to be of much use to anyone except those who already know about them. I’ve always seen two dominate forces in the .NET world, one heavily driven by Microsoft as a natural progression of VB6 and classic ASP (commonly referred to as The MSDN Way) and the other heavily driven by core object oriented practices and influenced by some of the best Java projects/concepts (known as ALT.NET).
In reality, the two aren’t really comparable. The MSDN Way loosely defines a specific way to build a system down to each individual method call (after all, isn’t the API reference documentation the only reason any of us visit MSDN?) Whereas ALT.NET focuses on more abstract topics while providing specific implementation. As Jeremy Miller puts it: the .Net community has put too much focus on learning API and framework details and not enough emphasis on design and coding fundamentals. For a relevant and concrete example, The MSDN Way heavily favors the use of DataSets and DataTables for all database communication. ALT.NET however, focuses on discussions about persistence design patterns, object-relational impendence mismatch as well as specific implementations such as NHibernate (O/R Mapping), MonoRail (ActiveRecord) as well as DataSets and DataTables. In other words and despite what many people think, ALT.NET isn’t about ALTernatives to The MSDN Way, but rather a belief that developers should know and understand alternative solutions and approaches of which The MSDN Way is part of.
Of course, it’s plain from the above description that going the ALT.NET route requires a far greater commitment as well as a wider base of knowledge. The learning curve is steep and helpful resources are just now starting to emerge (which is the reason I decided to start this series). However, the rewards are worthwhile; for me, my professional success has resulted in greater personal happiness.
Although simplistic, every programming decision I make is largely based on maintainability. Maintainability is the cornerstone of enterprise development. Frequent CodeBetter readers are likely sick of hearing about it, but there’s a good reason we talk about maintainability so often – it’s the key to being a great software developer. I can think of a couple reasons why it’s such an important design factor. First, both studies and first hand experience tell us that systems spend a considerable amount of time (over 50%) in a maintenance state – be it changes, bug fixes or support. Second, the growing adoption of iterative development means that changes and features are continuously made to existing code (and even if you haven’t adopted iterative development such as Agile, your clients are likely still asking you to make all types of changes.) In short, a maintainable solution not only reduces your cost, but also increases the number and quality of features you’ll be able to deliver.
Even if you’re relatively new to programming, there’s a good chance you’ve already started forming opinions about what is and isn’t maintainable from your experience working with others, taking over someone’s application, or even trying to fix something you wrote a couple months ago. One of the most important things you can do is consciously take note when something doesn’t seem quite right and google around for better solutions. For example, those of us who spent years programming in classic-ASP knew that the tight integration between code and HTML wasn’t ideal.
Creating maintainable code isn’t the most trivial thing. As you get started, you’ll need to be extra diligent until things start to become more natural. As you might have suspected, we aren’t the firsts to put some thought into creating maintainable code. To this end, there are some sound ideologies you ought to familiarize yourself with. As we go through them, take time to consider each one in depth, google them for extra background and insight, and, most importantly, try to see how they might apply to a recent project you worked on.
The ultimate tool in making your code maintainable is to keep it as simple as possible. A common belief is that in order to be maintainable, a system needs to be engineered upfront to accommodate any possible change request. I’ve seen systems built on meta-repositories (tables with a Key column and a Value column), or complex XML configurations, that are meant to handle any changes a client might throw at the team. Not only do these systems tend to have serious technical limitation (performance can be orders of magnitude slower), but they almost always fail in what they set out to do (we’ll look at this more when we talk about YAGNI). In my experience, the true path to flexibility is to keep a system as simple as possible, so that you, or another developer, can easily read your code, understand it, and make the necessary change. Why build a configurable rules engine when all you want to do is check that a username is the correct length? In a later part, we’ll see how Test Driven Development can help us achieve a high level of simplicity by making sure we focus on what our client is paying us to do.
You Aren’t Going to Need It is an Extreme Programming belief that you shouldn’t build something now because you think you’re going to need it in the future. Experience tells us that you probably won’t actually need it, or you’ll need something slightly different. You can spend a month building an amazingly flexible system just to have a simple 2 line email from a client make it totally useless. Just the other day I started working on an open-ended reporting engine to learn that I had misunderstood an email and what the client really wanted was a single daily report that ended up taking 15 minutes to build.
Last Responsible Moment
The idea behind Last Responsible Moment is that you defer building something until you absolutely have to. Admittedly, in some cases, the latest responsible moment is very early on in the development phase. This concept is tightly coupled with YAGNI, in that even if you really DO need it, you should still wait to write it until you can’t wait any longer. This gives you, and your client, time to make sure you really DO need it after all, and hopefully reduces the number of changes you’ll have to make while and after development.
Code duplication can cause developers major headaches. They not only make it harder to change code (because you have to find all the places that do the same thing), but also have the potential to introduce serious bugs and make it unnecessarily hard for new developers to jump onboard. By following the Don’t Repeat Yourself (DRY) principal throughout the lifetime of a system (user stories, design, code, unit tests and documentation) you’ll end up with cleaner and more maintainable code. Keep in mind that the concept goes beyond copy-and-paste and aims at eliminating duplicate functionality/behavior in all forms. Object encapsulation and highly cohesive code can help us reduce duplication.
Explicitness and Cohesion
It sounds straightforward, but it’s important to make sure that your code does exactly what it says it’s going to do. This means that functions and variables should be named appropriately and using standardized casing and, when necessary, adequate documentation be provided. A Producer class ought to do exactly what you, other developers in the team and your client think it should. Additionally, your classes and methods should be highly cohesive – that is, they should have a singularity of purpose. If you find yourself writing a Customer class which is starting to manage order data, there’s a good chance you need to create an Order class. Classes responsible for a multitude of distinct components quickly become unmanageable. In the next part, we’ll look at object oriented programming’s capabilities when it comes to creating explicit and cohesive code.
Coupling occurs when two classes depend on each other. When possible, you want to reduce coupling in order to minimize the impact caused by changes, and increase your code’s testability. Reducing or even removing coupling is actually easier than most people think; there are strategies and tools to help you. The trick is to be able to identify undesirable coupling. We’ll cover coupling in detail in a later part.
Unit Tests and Continuous Integration
Unit Testing and Continuous Integration (commonly referred to as CI) are yet another topic we have to defer for a later time. There are two things that are important for you to know beforehand. First, both are paramount in order to achieve our goal of highly maintainable code. Unit tests empower developers with an unbelievable amount of confidence. The amount of refactoring and feature changes you’re able/willing to make when you have safety net of hundreds or thousands of automated tests that validate you haven’t broken anything is unbelievable. Secondly, if you aren’t willing to adopt, or at least try, unit testing, you’re wasting your time reading this. Much of what we’ll cover is squarely aimed at improving the testability of our code.
Although this first part was void of any actual code, we did managed to cover quite a few items. Since I want this to be more hands-on than theoretical, we’ll dive head first into actual code from here on end. Hopefully we’ve already managed to clear up some of the buzz words you’ve been hearing so much about lately. The next couple parts will lay the foundation for the rest of our work by covering OOP and persistence at a high level. Until then, I hope you spend some time researching some of the key words I’ve thrown around. Since your own experience is your best tool, think about your recent and current projects and try to list things that didn’t work out well as well as those that did.