Verdict: A demanding, thought-provoking read.
This is a huge work by John Lakos, spanning three whole volumes: Process and Architecture (this one), to be followed by Design and Implementation, and, finally, Verification and Testing, covering his ‘Large Scale C++’ work at Bear Sterns and Bloomberg. Covering four chapters, 988 pages, hundreds of figures, this book requires a significant investment in time. It is heavily cross-referenced, within itself and with the other two volumes in this set. Unfortunately the index is not so good – having access to the PDF helps mitigate that. He does provide his own notation for class diagrams – however, that notation is not described in the book’s ‘Quick Reference’ appendix, which is a bit of an oversight (as is the lack of a glossary). In fact, describing this notation in the inside front and back covers would have been even more convenient. Due to the heavy cross-referencing, I had to have three post-it note bookmarks constantly active – the Contents, the Quick-Reference, and the Index. Sparing use of a highlighter pen proved useful. Although I have read this book from cover to cover, I had to re-read some parts of it to digest the material. Every chapter has a concluding summary, as do some of the larger sections within the book. The physical version of this book is a paperback and I was concerned that it would not stand up to sustained heavy use; but it stayed intact during this review and seems robust enough.
The first chapter, ‘Motivation’, lists the circumstances handled by this book. It distinguishes between highly changeable application software and more stable library software – typically produced by different types of software developers. This process, instead of creating technical debt, invests in Software Capital, with the aim of software that is delivered quickly, provides better functionality /quality and is cheaper to produce, maintain, and deploy. All very laudable but there are trade-offs to be made in order to achieve this and they are covered.
Lakos’s approach is to design software not only taking logical design (classes, etc) into account but also that of physical design (object files, shared libraries, static libraries, filenames used), resulting in a software component that is easy to locate within an organisation and, to a degree, can be used a bit like a software brick. As such, these components have four essential properties that must be adhered to. In particular he emphasises that avoiding cyclic dependencies is critical, with nine standard levelisation techniques being documented in depth. Interestingly (or comprehensively?) this chapter explains the C++ build process, library archives, declarations, definitions and linkage. He introduces bindage, the four properties of components and his own notation for depicting software logical designs (with code examples) and In-Structure relationships. The source code is welcome but additional – presumably in-house – tools are mentioned, along with their configuration files. Some coverage of that would have been welcome, too.
Lakos realises that not all the source code used in an enterprise will adhere to the four rules of component design and that organising software at the component level is insufficient – more is required: the Package, the Package Group, and the Unit Of Release (UOR) “which represents a physically (and usually also logically) cohesive collection of software (source code) that is designed to be deployed and consumed in an all-or-nothing fashion”. Frustratingly, there are some sections where things are detailed to the extreme, and in others there are sections which are a bit vague.
The remaining two volumes of this work – Design and Implementation and Verification and Testing – have yet to be released. If they are anything like this book, they will demand a significant investment in time but will show insights into the author’s work and the methodology he created from that work.