This post is a review of the book Object-Oriented Software Construction by Bertrand Meyer.
Where to start with this massive tome? Weighing in with other 1200 pages and some pretty deep content, OOSC isn't a quick and easy read. The author bio describes Bertrand Meyer as equally at ease in the software industry and in the world of academic computer science" and his book also straddles the 2 disciplines. There's plenty of interesting material for academics and those interested in the theory, yet the book also contains much practical, useful information which software engineers can use in their day to day work.
Usefully the book uses a new language written by Meyer and others to demonstrate the concepts explained in the book, which makes them much clearer and allows Meyer to show the concepts in their purest form. The book comes with a CD with an environment for using this language (and an electronic version of the book), so you can play around with it to check your understanding of the concepts.
There are some points of controversy in the book regarding which direction is more object-oriented and Meyer acknowledges opposing choices to his and backs up his choices with well though out arguments. By choosing a strict object-oriented viewpoint in the main part of the book, you miss out on details that would be usable in a more common language than the one presented. Mayer addresses this with a section towards the end of the book about object-orientation in different languages, namely Ada, Simula, Smalltalk, C++ and Java as well as extensions for LISP and C. Though as you can see from the list of languages, the books suffers a little here from being originally published in 1994 with the second edition (the version reviewed) published in 2000.
Here are some of the points that I found most interesting or were new to me, there are a lot! (I didn't start taking notes til the 9th [of 36] chapters so there's nothing here from the first 8 chapters):
- You want 3 things from a garbage collector:
- Soundness - Collected objects are unreachable
- Complete - All unreachable objects are collected
- Timeliness - known average and upper bound on time from unreachable to collected
- Inheritance and type parametrisation (genericity) are 2 perpendicular ways to be more generic. Reliability (type safety) and reusability (single language element covering different variants) are conflicting but can be solved by type parametrisation. Static typing gives you errors at compile time as opposed to at run time with dynamic typing and because the earlier an error is detected the cheaper it is to fix, this is an advantage of static typing (though does this rule really apply here?). Because of their unspeficiedness, generic parameters in functions can only be used in assignments, equals and calls to other functions that take generic parameters.
- For a component to be considered reliable, it must perform to it's specification and also handle cleanly, cases outside it's specification.
- There are only 2 legitimate responses to an exception: retrying or reporting a failure to the caller. If failing the catch block or equivalent must first restore the object to a steady state.
- An overlooked aspect of reusability is that a language should allow you to access code written in a different language. OO is more about the modular organisation of a system that the line to line coding.
- From the perspective of types, inheritance is specialisation, from the perspective of a module, inheritance is extension.
- Types can be useful when the code is being read by a human for showing intent (though in languages where you do not declare types, this information could be encoded into the variable name).
- When architecting a system, classes can be broadly classified into 3 types:
- Analysis classes - from the problem/domain space
- Design classes - architectural choice, in solution space
- Implementation classes - low level, in solution space
- Use cases can lead to a sequentially biased analysis and also model existing behaviour rather than coming up with new behaviour. (To counter this Mastering the Requirement Process recommends deciding where the boundaries of the work lie before working out use cases).
- Functions should be split into commands and queries, commands should not return a result and queries should not make change that are visible to clients of the class.
Towards the end of the book in the chapters covering concurrency and databases, the amount of general information starts to tail off as the text becomes quite specific to the solution used in the language that accompanies the book.
Overall, this is a very interesting book for fans of the theoretical side of software engineering. Readers who are solely looking for practical tips to improve their code, will find them but they may lose patience due to the massive amount of other information in the book.