continue / break / next / return vs if-else if
def f(): if condition-1: action-1 return (or continue / break / next in a loop, depending on your language) if condition-2: action-2 return (or continue in a loop) alternative-action
def f(): if condition-1: action-1 elif condition-2: action-2 else alternative-action
The reason is the principle of locality: if the list of conditions / actions is longer than a few dozen lines, you don't know when reading condition-n / action-n what's coming next, because it depends on something being there or not at the end of the ifs sequences.
Functional programming and code extension
I do have a problem with functionnal programming. I will illustrate this with python.
Let's say I have
def buildSomeStructure(): return containerOf(records) myStuff = buildSomeStructure()
Let's say it's a dictionary of something. Now I want to extend it by adding a field to each record. I could do something like
def buildSomeStructure(): return containerOf(records) myStuff = buildSomeStructure() def addThingsToMyStuff(theStructure): for record in theStructure: if some-condition: record.modify() myStuff = buildSomeStructure() addThingsToMyStuff(myStuff)
Or, functionnal style, something like
def buildSomeStructure(): return containerOf(records) myStuff = buildSomeStructure() def addThingsToMyStuff(theStructure): newStructure = rebuildStructure adding modification if necessary return newStructure myStuff = buildSomeStructure() myNewStuff = addThingsToMyStuff(myStuff)
I greatly prefer the former to the latter. Here's why:
- In the non functional style, I will change records in place (possibly even ignoring the container structure), that is the, in the functional I have to rebuild the structure, and to know what is is. Moreover, It's likely it'll take more space, since I'll have two copies in memory (the old one and the new one).
- In the functional programming style, I have to make many things right not to break the code (rebuild of the structure and returning the new structure). In the state (object) style, if I just do nothing I sure as hell won't break anything.
- In the functional programming style, I put something new on the data path (that is modify(build(seed)), modify is called anyway, with x = build(seed), modify(x) I don't change my initial code.
- Of course, functional programming protects you from side effects to some extent.
Variable naming (and not naming)
The problem space
Most likely, the program you're writing doesn't exist in isolation from the universe (in a specification sense, we're not talking about communicating programs here). For example, if you're writing the software for a flying drone, the drone knows about TAS (True AirSpeed), IAS (Indicated AirSpeed), GS (Ground Speed), Vz (vertical speed) or even Vr (Velocity for rotation, that is the speed at which the plane gets airborne). And this is the way your variables should be named, not drone_speed or something like that (is this ground speed ? Airspeed ? Something else ?). The point is not only that any pilot or aerospace engineer, that you'll have to talk to at some point, knows what you're talking about, but so does your fellow developpers, even if they are new to the project.
The problem with this approach is that the developers need some training in the problem space. That is, the programmer either is more a less specialized in the field, or received some initial training when entering the project. This takes time and money, so this is really a cultural issue, because this is not only the developers will, but, for example, if you're the project manager, you will need to reserve some time and money to do it. If it's not in the culture of the company, you may hope to fight and prevail, but the point is that it works essentially because you do it for every developper. And if you've to fight for every one of them, you're toast.
To be continued: example with SIB11, ip_address vs rec[4:8], believing in developer trained in the problem space, it's easier to train a developper in the problem space than a problem space specialist into programming, going from drone to umts because you're a C developper, bridging the gap between the problem specialist and the developper with specification (doesn't work). Counter-example: developping a darknet. The knowledge of the problem space by the programmer is reflected in the naming of variables and functions.
Variable vs the formula used to create it
- If a variable is used only once, think of using the formula instead. If you're starting to use funny names like p1, p2, p3 or x, xx or things like that, not coming from your #problem space, most likely you should consider using the formula instead.
|Don't write||Write instead|
p1 = l p2 = l f(p1, p2)
Sometimes, you want to put the result in a variable because you don't want to compute the function twice. However, come with a meaningful name. Using a name that describes the operation instead of what the result is supposed to be is more or less like putting a comment that says "put 1 in x" after the statement x = 1:
|Don't write||Write instead|
accel_x_time = accel * time
speed = accel * time
If you can't think of a variable name, it might be your ideas in the space problem aren't clear enough. Take a minute or two to think about it.
The solution that doesn't change the interfaces is likely the right one (except if you have to pass something by aliasing).