Posts

Showing posts from November, 2023

Simplicity and maintainability

We generally consider simple, efficient, and maintainable to be related: that something improved in one of the three ways will likely benefit in others. However, there's an ambiguity in "simple", related to one in "maintainable". Consider the following case: You have a delimited set of instances of some human-readable structure. For this to be a useful example, the number of cases should be somewhere between five and maybe a hundred, and it should be open - that is, there should be a probability that more instances will be added as time goes on. An example might be specifications of message structures in an ASCII format for an evolving protocol. These structures also aren't simple discrete units. They come in pairs or even triplets, with there being a base type and one or more derived types. The derivation is fairly simple for a human to do and could be put into a set of rules for an algorithm. You need all of these cases to be defined for a program to r...

Removing consecutive if tests

Consider a set of exclusive tests followed by actions. That is: if (test1()) doSomething(); else if (test2()) doSomethingElse(); else if (test3()) ... If you get the data for the conditions and the actions into a single convenient parameter, if necessary by creating an arbitrary struct, then we have: Param foo(...); if (test1(foo)) doSomething(foo); else if (test2(foo)) doSomethingElse(foo); else if (test3(foo)) ... This is exactly equivalent, logically, to the sequence in using func_pair= std:pair<std::function<bool(const foo& )>, std::function<void(foo&)>>; std::vector<func_pair> vec; auto iter = std::ranges::find_if(vec, [&foo](func_pair inVal) -> bool { return inVal.first(foo); }); if (iter != vec.end()) iter->second(foo); if the vector has been populated with the appropriate tests. (This is not exactly the Command pattern, which is more a generalization of the switch statement. I introduced this a few posts ago, in ...

Emergent Design

Before talking about emergent design, I always feel that I should suggest going and looking at Jim Coplien's discussions of the problems with "agile" design. The problem is, Coplien's right. So-called emergent design - that is, design generated by an atomic, bottom-up approach in incremental steps - will work only if someone is (or a few people in very tight communication are) working in conformity to an implicit but detailed and coherent overall plan, in which case it's not really emergent at all. Continuous refactoring can preserve and even improve an underlying good design, but it's a very long way to get from a heap of well-executed details to anything like an optimal system architecture. The other problem is, we don't really have a choice. The alternative is detailed top-down design - that is, waterfall - but that requires a requirements stage which is detailed, thorough, and subtle, and no organization I've been in in the past decade and a half w...