Alberto Gutierrez has posted an article where he list his ten most important principles that should be followed to ensure the success of a software project. Many of them are really good practices that would help most developers in the long run—after all, the only easy thing about software development is screwing it up.
I feel I need to add to several of the observations on his list, both more in more abstract and more specific terms.
Code quality is measured using many metrics—for instance, simplicity, readability, robustness and testability are often cited as the fundamental ones. But one of the things that is often neglected is insulation from infrastructure, which is the effective uncoupling of code from external libraries, frameworks, and services; it is from this that other properties, like testability, derive in large part.
Island and bridges
No code entity is an island. While the relationships between internal functions and classes are the centre of the software’s architecture, their connections with external entities are an more important aspect in a program’s design. Libraries and frameworks should be leveraged to avoid reinventing the wheel, but without establishing a strong dependency towards a particular component.
For instance, the customization of libraries by subclassing is often criticized for the inherent coupling it introduces. It may be the case that the domain classes outlast many of the libraries they employ , so you do not want to become overly dependent on such external help. Old libraries are dropped for new ones relatively often, but the core of an application changes very slowly.
In fact, many PHP frameworks (such as Doctrine or Zend Framework) are starting to introduce more flexibility in their 2.x versions—for instance by not forcing the Active Record pattern anymore.
What’s in a name?
Another property of code that is often overlooked is the quality of the names employed in a code base. Classes, methods, functions, parameters and packages should all be part of a meaningful and consistent naming process that keeps the door open to a cohesive refactoring process.
Naming things is considered one of the two hardest things in computer science (the other being cache invalidation, in case you’re wondering), but just because it’s hard doesn’t mean that it has to be done inconsiderately.
Good naming results in an Ubiquitous Language, a shared vocabulary between customers and programmers that promotes coherent modelling: the best way to take care of the customer is to start speaking his language instead of expecting them to learn the technical jargon we are accustomed to. Communication and feedback from the actual customer is one of the pillars of Agile methodologies.
The role of automation
Finally, a more abstract note sparked by Alberto’s talk of continuous integration and testing procedures, which are two implementations of automation in the context of software development.
Automation is a far-reaching concept that goes well beyond building and testing and can be exploited for different processes. For example, importing new version of libraries, or deploying a new release of the software requires going through long lists of mechanical tasks. Automation prevents human errors from injecting failure in these processes that require special handling.
It also saves time, thus leaving you able to cook on real code instead of doing the dishes.