Nice ways of changing external code

All SW-intensive systems have a lot generic functionality[1]i.e. functionality not specific to the product, e.g. network protocols, XML parsing, graphics, and therefore contain a lot of generic components developed by external vendors. Sometimes the requirements force us to modify some of the behavior implemented in those components.

One of proper solutions is implementing the desired behavior via the decorator pattern. This keeps our modification dependent only on the interface of the component and not the implementation. Sometimes, however, the access provided by the interface is not sufficient to provide the desired functionality. For example, if you need to change a driver’s interaction with HW, most likely you won’t find the necessary “hook point” in the driver’s upper interface, since it cleverly hides HW-level specifics from the higher layers. Another by-the-book solution is pushing the change to the mainline, as open source community always recommends with good reason. But let’s focus on the remaining problematic cases.

Doing our change directly in the external component is obviously not nice. Microsoft, for instance, recommends applying the change to a clone of the component instead of the original. This allows separating our own changes from the external changes, which we can handle via 3-way merges. However, this creates some duplicate code in our system, which is on top of the list of Wikipedia’s common code smells.[2]For further discussion, please see Kapser, C.; Godfrey, M.W., ““Cloning Considered Harmful” Considered Harmful,” Reverse Engineering, 2006. WCRE ’06. 13th Working … Continue reading

Linux people take this one step further via patch-files. yocto provides the concept of layers to hold groups of patches per different providers (including us) and per different reasons (HW adaptation, specific requirement etc.). The build system stacks these layers on top of each other to provide the working code. There is physically zero code redundancy in this setting. But, the main concern, the dependency on implementation instead of interface[3]another smell: inappropriate intimacy is still there. Anyone who works with patch-files has experienced that even small changes in the patch destination will cause the patch command to fail. So whenever the external code changes, we have to change our patch as well.

Last but not least, managing the additional complexity resulting from changing external code doesn’t require just solid design work, but also additional testing and documentation. The background (requirements) of the change and the invariants should be documented and automated tests should be implemented, in order to make upgrades easier and ensure that the changed behavior is still there after an upgrade of the external code.[4]Thanks to Holger Strobel for this contribution

To wrap up, while people have devised some nice ways to change external code, it’s still best to avoid them whenever you can.

Happy new year :-)

Footnotes

Footnotes
1 i.e. functionality not specific to the product, e.g. network protocols, XML parsing, graphics
2 For further discussion, please see Kapser, C.; Godfrey, M.W., ““Cloning Considered Harmful” Considered Harmful,” Reverse Engineering, 2006. WCRE ’06. 13th Working Conference on , vol., no., pp.19,28, Oct. 2006
3 another smell: inappropriate intimacy
4 Thanks to Holger Strobel for this contribution

Leave a Reply

Your email address will not be published. Required fields are marked *

 

This site uses Akismet to reduce spam. Learn how your comment data is processed.