diff --git a/blogs+posts/software-engineering/README.md b/blogs+posts/software-engineering/README.md index 3d3dad9..8bab58e 100644 --- a/blogs+posts/software-engineering/README.md +++ b/blogs+posts/software-engineering/README.md @@ -7,14 +7,22 @@ Here are posts and articles covering more general software engineering topics. ## Management & Leadership * [Repetition, Repetition, Repetition](./repetition) - Lessons from Sports Management that cross over to software engineering. + * [I think you'll find it's more complicated than that](./more-complicated) - Knowledge Transfer opportunities in Agile ceremonies. + * [Becoming a Coach](./coaching) - Considerations on becoming a volunteer Sports Coach. + * [Think on Paper](./think-on-paper) - Clarifying your thought process and helping your decision making. -## API Design +## Design + +* [Be considerate in your API design, but not overly so](./api-design) - An example of when being overly helpful can be to the detriment of your API design. + +* [Antipattern - STL Inheritance](./antipattern-stl-inheritance/) - An explanation as to why you probably don't want to inherit from that STL container + +* [Template Extension in C++](./template-extension/) - A note on how templates are extended in the STL to 'borrow' behaviour compared to how OO inheritance achieves it. -* [Be considerate, but not overly so](./api-design) - An example of when being overly helpful can be to the detriment of your design. ## Performance Engineering @@ -23,7 +31,9 @@ Here are posts and articles covering more general software engineering topics. ## Designing the 'espresso' Library * [Design Considerations & Influences](./espresso/design-considerations) - Thoughts and influences on the design of the espresso library. + * [Object Creation Patterns](./espresso/object-construction) - Discussion on constructors and factory classes, as applied to the espresso library. + * [Utilizing Manager Objects](./espresso/manager-objects) - Discussion on the advantages of deploying a manager object and the separation of function. ## Developing C++ with Visual Studio diff --git a/blogs+posts/software-engineering/antipattern-stl-inheritance/README.md b/blogs+posts/software-engineering/antipattern-stl-inheritance/README.md new file mode 100644 index 0000000..b0bdc42 --- /dev/null +++ b/blogs+posts/software-engineering/antipattern-stl-inheritance/README.md @@ -0,0 +1,76 @@ +[home/](../../../)[blogs+posts/](../../)[software-engineering/](../)[antipattern-stl-inheritance](./) + + +# Design Antipattern - STL Inheritance + + + + +_Photo Credit: [wikimedia](https://upload.wikimedia.org/wikipedia/commons/1/18/ISO_C%2B%2B_Logo.svg)_ + +### Never, Ever Inherit from an STL Container + +That is unless you're following the style and convention of the STL library to create a template class to represent a modified form of container. Otherwise, you're most probably applying an antipattern to your design and you'll likely end up with unexpected behaviour, resulting in memory leaks. + +Why? + +Well, because it's wrong on both of two very important points: 1) **Design** and 2) **Implementation**. + +#### Design + +If you find yourself tempted to inherit from an STL container because your class represents a list or some other grouping, then you might be violating the design difference between 'is a' and 'has a'. Just because the class you're building represents a collection of things doesn't mean it 'is a' collection of things. It more likely means that it 'has a' collection of things. _(See Item 32 and Item 38 in Effective C++ Third Edition by Scott Meyers)_ + +For example, if you consider your class as representing a list of things, then you likely needs to contain a `vector` things rather than inheriting from it. + +The following code represents a 'is a' design. +````C++ +class Foo : public vector +{ + // asking for trouble + . + . + . +}; +```` + +Whereas the following represents a 'has a' design. +````C++ +class Foo +{ +private: + // 'has a' + vector myListofThings; + + . + . + . +}; +```` + + +#### Implementation + +The STL was not designed to be extended through normal OO class inheritance. Apart from the fact that the STL represents _template classes_ rather than actual concrete classes, the most important factor is that the STL was designed with performance in mind from the outset and intentionally excluded _virtual functions_ in its implementation. That includes _virtual destructors_, which means that if you inherit from a container, you're not going to achieve the correct order of object destruction you might be depending on to release heap memory and other resources, resulting in memory leaks and dangling resources. + + +#### Summary +One of the worst examples of a memory leak I ever had to deal with in my career was because of this _antipattern_. I was given the task of converting a batch system into a real-time service and once the system was developed, a catastrophic memory leak in the underlying libraries became apparent. It'd never been noticed in the batch system because those libraries were exercised only once before the process terminated whereas now, they were embedded in an online, always-on service, which meant they'd be exercised over-and-over without the process terminating (and memory being released). + +Actually, getting to that point took effort in itself because the server crashed immediately upon innovation, which meant the issue couldn't be debugged in a debugger. It took some ol' fashioned crash analysis by-hand to determine the cause of the crash might actually be a lack of available memory. And, in turn, that that had been caused by earlier leaks. Further still, it wasn't just a handful of leaks but rather a collection of thousands of minor leaks that collectively added up to a massive leak (relative to the typical machine specs of the time). + + +Unfortunately, the _antipattern_ had been applied liberally, which meant there were several classes affected and in turn, associated references (e.g. _iterators_, etc.) were rampant throughout the codebase. That meant that, having diagnosed the problem, the majority of the work had only began because so much of the codebase was affected. + +In order to cope with the extent of the disruption and minimize impact, I modelled constructs like `iterator` and `const_iterator` as well as methods like `begin()` and `end()` within the classes themselves. So began iteration after iteration of breaking the class inheritance in order to have the compiler let me know of all the broken references. After several weeks of this painstaking work, I eventually managed to get the issue under control and the server could actually function. + +The point is that all of this rework could have been avoided had the original author simply known that the STL containers aren't designed to be extended through inheritance. + + +*** +_Donnacha Forde_ + +_[linkedIn.com/in/donnachaforde](https://www.linkedin.com/in/donnachaforde)_ + + + + diff --git a/blogs+posts/software-engineering/template-extension/README.md b/blogs+posts/software-engineering/template-extension/README.md new file mode 100644 index 0000000..6674be1 --- /dev/null +++ b/blogs+posts/software-engineering/template-extension/README.md @@ -0,0 +1,67 @@ +[home/](../../../)[blogs+posts/](../../)[software-engineering/](../)[template-extension](./) + + + +## A Note on Template Extension + +In C++, _class_ and _template class_ are different things, which show up in the way that each are used to model the problem domain. I like to use language like _"you inherit from a class"_ but _"you extend a template"_. Sure, both are physically extending the thing but the effect is that you expand the function of a class whereas you restrict the function of a template (at least in the STL). + +In typical OO design, you start with an _interface_ and perhaps an _abstract class_ so that you may generalize and rely on polymorphism. For example, if I were modelling shapes, I might have something like the following: + +````C++ +interface IShape +{ + void draw(); + void print(); +}; + +interface ICircle : public IShape +{ + double getRadius(); +}; + + +class Circle : public ICircle +{ + ... +}; + +```` + +In broad terms, you extend the functionality of the parent. You typically extend the interface by adding to it, thus introducing new behaviour. + +However, the design of the STL could almost be described as the inverse of this. The topmost templates contain the fullest functionality and the 'inherited' templates effectively restrict functionality. Technically, inheritance isn't actually used but rather 'implemented in terms of' (often modelled in C++ as _private inheritance_). + +A good example of this is the implementation of the `queue<>` template, which is implemented in terms of a `deque<>` - i.e. a 'double-ended queue'. This makes sense in so much as a `queue<>` is a restricted form of a `deque<>`. Whereas it's possible to traverse a `deque<>` in either direction, a `queue<>` can only be traversed in one direction, hence it's a 'queue'. + +Here's the STL code declaring `queue<>`: + +````C++ +template > +class queue +{ + . + . + . + +protected: + _Container c{}; +}; +```` +Note the second template argument, which defaults to `deque`, is used to declare the only member variable in `class Queue` and is what's used to provide the implementation of `queue`. **The queue is implemented in terms of deque.** + + + +If you set out to model this sort of construct in a Object-Oriented class library (which was popular in the '90s with libraries like RougeWave), you'd probably design it along the lines of first defining `class queue` containing elements with a single pointer to the next element and then extend it through inheritance to define `class deque` with an additional pointer to the previous element. But, in generic or template design, you invert that approach and define `template class deque` first and then define `template class queue` as a restricted form of `deque`. + +This illustrates an important way Object-oriented design differs from 'Generic' design. Remember, C++ can support multiple languages and paradigms and that what we have today in C++ development is arguably a _hotpotch_ of technology and paradigms with a mix of OO and Generics. + + +*** +_Donnacha Forde_ + +_[linkedIn.com/in/donnachaforde](https://www.linkedin.com/in/donnachaforde)_ + + + +