Using pre-made solutions as parts of solving a bigger problem is a common motif on several areas of human knowledge. At first, it makes perfect sense not to waste valuable time making something that was already done. Encompassing this ideal, a lot has been said about doing this with software, what is commonly referred as code reuse.
There are three canonical types of reusing code, as listed by Erich Gamma and Ralph Johnson: software libraries, Design patterns and Frameworks. There are other kinds of code reuse such as software platform (similar to both a framework and collection of libraries ), services or even using a complete application and building on top of it. Each and every one of these types of code reuse differ in its learning curve, in its flexibility (in the sense of how many different new applications, libraries, platforms or frameworks can be built from it) and the rate of functionality/design embedded in it.
But things are not so simple as putting Lego bricks together. Whenever looking for reusable piece of software, how to pick the most suitable one? Even if there is only one piece of one kind, you still have to figure out if it is suitable, or how much work it will be needed to make it suitable (which is the most common case).
This is because the piece can be too complex, not well documented, not fulfill all the desired properties, not be robust enough, without binds to the language/platform you are using, not have a permissive enough license, not be robust enough or make trade-offs that are not really what you would expect (such as choosing CP instead of CA on CAP), not be supported by a big company, and so on. And this gets a lot more troublesome when you have lots of piece of software to choose from. Since evaluating these things take time, a more agile approach is to make the trade-off of how much time to spend evaluating such pieces in order to gain information on them, in order to reduce the risk of making an inappropriate decision (always weighted by how bad can it be to make one, somewhat similar to swot). Even then, on your core domain, reusing big pieces of code is hardly advisable.
However not all software is reusable. At least not easily reusable. The reasons lies on the difficulties of having a reusable design (such as those stated by Uncle Bob Martin in his SOLID series, or by Neil Bartlett on his Component Models Tutorial) and the fact that making it easy for others to use requires a bit more support (such as documentation, tutorials and/or screencasts). Not to mention that most business are not about launching frameworks or application libraries, and therefore, are not interested in this work (which can be good or bad, depending on the cost of making it reusable, and the money made/saved of doing it). Which ensues that a lot of software is not reusable. All of this could suggest that making reusable bits of software requires a Big Design Up Front. However, agile practitioners suggest making code reusable as it is actually needed (a last responsible moment approach). This has actually worked well in practice, as the framework Ruby on Rails was extracted from other projects from 37 Signals, and Apache Hadoop was extracted from another project: Apache Nutch.
Code reuse is not a simple matter, and should not be taken lightly. It involves decisions that can be more relevant from a economical/business perspective than from a purely technical perspective. In the end, the real failure of reuse is the failure to realize this.
One team that applies it consistently can achieve several benefits, such as:
- Reducing the risk of Overengineering: one person is more likely to over engineer solutions when left alone, than when having a partner to keep you grounded on the problem at hand.
- Reducing bugs: a partner reading the code is more likely to catch bugs than a the person coding, who is usually focused on the current line of code, and not on the overall context.
- Improving Quality of Code: refactorings are easier to accomplish safely when one person is not focused on actually performing the refactoring and therefore can focus on ensuring the step is safe and checking for further refactoring opportunities. Also, the methods, modules, class names, functions and variables names are readable by at least two people’s standards.
- Knowledge Sharing: this is one of the biggest benefits of Pair Programming because when developers are pairing, they share several kinds of knowledge:
- Business Knowledge: even if not doing DDD, the developers communicate about the problem on a business level, what concepts are important, the business rules, and so on.
- Technical Knowledge: such as frameworks, object libraries, platforms, ORM frameworks, databases, programming languages and tools that are being used, or could be used, on the project.
- Theory Knowledge: a software project is not just solving business rules. From time to time, more abstract concepts are needed to solve a problem, and developers can teach each other about concepts such as concurrent programming, aspect oriented programming, design patterns, architectural patterns, graph theory, boolean algebra, security and cryptography, regular expressions and formal languages, problem complexity, software design…
- Project Knowledge: how the project works, how it is deployed, how to access the subversion (or any other SCM), how and which methodologies are applied, how bugs are tracked, and so on. It also includes the knowledge of the history of project decisions such as: why was this library used instead of that other one, why this algorithm was selected, why this architecture is being used, which other frameworks were evaluated…
In order to allow the knowledge to be shared among all participants, it is vital that pairs are constantly changed within a team. How often if very dependent on the size of the team, the features being tackled, and the team’s willingness to change it more or less often. All these types of knowledge sharing brings some other nice advantages: it gives the project less risk, as no single part of the code can only be changed by only one person (specially useful when this one person would be vacation, sick in a hospital, or leaves the project). Also, gives more confidence for the team to employ Collective Code Ownership, it allows the team to be more productive over time, as less of the basics is needed to be explained and more pairs can tackle a issue where only a specialist would be able to otherwise, and finally the team as a whole can estimate better the size of features to be implemented (let it be story cards, tasks, or old-fashioned use cases), as everyone is more aware of the code base and the difficulty of problems to be tacked.
Other benefits of pair programming (an in-depth analysis can be found here paper) include: improved morale, fewer interruptions, more team focus and higher productivity. It is also important to note that a team cannot pair program all day, as people usually have other tasks to attend, such as meeting’s, training, reading and responding emails, drink coffee.
This technique can be hard to actually apply, as many developers are not used to pairing, managers are afraid of it costing more (two people working on the same machine can never be more productive) and not everyone work well with such constant peer review and collaboration. Agile Methodologies value individuals and interactions over processes and tools, and this is quite critical when employing Pair Programming, because these difficulties (which may exist in varying degrees) can only be surpassed as long as the team (including managers) is willing to overcome it. Implementing it incrementally (maybe only a few hours a day, and building it up and the team sees the benefits) can ease the resistance, and the team can get experience with it while incrementally discovering impediments of pairing more often. Also, applying Coding Standards first can diminish the occurrences of pairs fighting about minor issues such as whether to use underscore or camel case. Also, if a team struggles in the beginning, mostly managing who codes and who observes, the variant Ping Pong Pair Programming can be easier to begin with. However, it implies Test Driven Development, which can be tricky to begin if the team doesn’t do it already.
Pair programming is a great technique, one that is usually overlooked even by agile teams (as Rachel Davies was able to see on some projects she coached). But with so many potential benefits, it is always worth giving it a shot.
Just the other day I was skimming through a list of topics to post here that I had crafted, and just realized that several of them had a very common, yet simple, motif: improving quality of code. This can sound quite sensible and simple to a lot of people, yet its an idea as powerful as it is controversial. And when I speak of quality of code, it is important to stress that this is the code for humans, as a machine doesn’t really care about it. Setting up this theme, Martin Folwer’s statement feels quite appropriate:
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
-Martin Fowler et al, Refactoring: Improving the Design of Existing Code, 1999
This statement is almost a Quality of Code Manifesto. More precisely, it is about readability, but both concepts are very intertwined. Readability is essential to write code with good internal quality (quality as measured by the programmers). Kent Beck, on Extreme Programming Explained, also mentions how high external quality (quality as measured by the users) can’t be maintained with a low internal quality:
Temporarily sacrificing internal quality to reduce time to market in hopes that external quality won’t suffer too much is a tempting short-term play. And you can often get away with making a mess for a matter of weeks or months. Eventually, though, internal quality problems will catch up with you and make your software prohibitively expensive to maintain, or unable to reach a competitive level of external quality.
Martin Fowler explains these interactions on a article called Technical Debt. Summing it up, code with poor quality is hard to maintain, hard to change, and therefore, costs a lot more in the long run than code with a good internal quality. Not to mention that it lacks transparency, and this can go really bad even outside software programming.
This is such an old issue, that I felt a bit insulted when I read the following (from this post): Java (the programming language) is Turing complete so no new language feature can enable us to solve a problem with Java that would be unsolvable without the language feature.
All of this sounded me absurd, since languages are tools to express code. If being Turing complete was enough, C would be all everybody needed, regardless of being a terrible language to express intention, and therefore, to make readable code. However, the author continues: Therefore any new language feature is at best a convenience to those reading and writing the code. Such features of convenience are not to be lightly dismissed, as they allow developers to increase the signal to noise ratio of our source code.
Therefore, in order to create good code, several practises, tools and concepts were created to helps or warn us: design patterns, DSLs, peer review, object orientation, functional programming, architectural patterns, agile methodologies, refactoring, pair programming, encapsulation, inversion of control, automated tests, code generation, anti-patterns, continuous integration, logic languages, fluent code….
And several of these topics are to encompass this metaphysics.