There are lots of rules, guidelines and frameworks out there designed to make software easier to build and upgrade. Concepts like SOLID look at how to write object oriented code in such a way as to allow pieces to be easily pulled apart and reused. Design patterns a geared toward solving common problems in tried and true ways. These ideas are great and all developers should not only understand them, but strive to fully utilize them. However, these principles are centered around a Utopian vision of software development. They assume that building the features the first time is the hard part. In reality, that isn’t so. The difficulty and frustration often associated with developing software comes from the maintenance phase, the long running part of the software development lifecycle in which bugs are identified and fixed.
Building software with a clear set of use cases and requirements is a relatively straight forward process. Various design patterns exist to help you solve problems which others have come across already. You can use principles like SOLID to help separate your classes and simplify your code. With modern RAD frameworks like Ruby on Rails or CakePHP, you can have something up and running in less than a day. But, as most software engineers know, that is just the start. Next comes the long process of maintenance and bug fixing. What makes this part of the software lifecycle so difficult is the inherent unpredictability of users. Software behaves predictably. If, under a certain set of conditions, you give it A, you will get B every time. Unfortunately, conditions change constantly and users often give C when you expect them to give you A. Expecting to have all of the use cases well defined at any point is unreasonable. Predictable software is used in unpredictable ways. That is a simple fact.
Any reasonably complex system will have a mind boggling set of conditions and permutations which make it impossible to fully predict all of the paths through the code. The best you can do is expect failure and try to capture enough information to be able to account for the situation next time. Using a set of guidelines like SOLID may make it easier to swap out a broken class for a new class, but they don’t really help you identify the problem or fix any data corruption which may have occurred. Knowing you have a problem and being able to isolate and fix the problem is just as important, if not more so, than being able to rely on consistent interfaces from your factory method. That is why I am proposing an additional set of software development guidelines called “LUCID code.” LUCID code is that which Logs information, uses Unit tests to predict behavior, is Configurable, Isolates features and is fully Documented.
LUCID code is code which understands that bugs are unavoidable; it expects to be updated somewhere down the road. Code which can “speak” to developers through logs, unit tests and documentation is not an artifact of the software development lifecycle, but a part of the team. It provides feedback which enables the human team members to more easily identify and change the unpredicted behaviors. It also allows the team to understand and correct corrupted data, an often overlooked part of the bug fixing process. Code which is isolated from other code and allows itself to be controlled through configurations, is code that can be made to behave in more predictable ways. If the team can throttle throughput, change flows, or increase logging levels without having to redeploy, then they are more likely to be able to keep misbehaving code in check while they work on a fix. In a production environment, code which is based on LUCID principles is less disruptive and easier to control than code which is not.
The principles of LUCID coding do not aim to resolve all issues in the early phases of the software development lifecycle; they simply make it easier to work with code in the real world. As predictable as your software may be, users will always find a way to do something unexpected. The real world is an unpredictable place for code. Having the code you write support you in your efforts may not allow you to predict all of the ways in which your systems will be abused, but it makes your hindsight much more clear.
I’ll follow up this blog post with a series of posts each one focusing on a different aspect of LUCID development. The elements seem simple on the surface, but doing it right takes skill and discipline.