|
I think that the single responsibility principle (from SOLID) is directly linked to names: if you make sure that your function or class or even variable just fulfills a single purpose, then you should also be able to name it appropriately, using that purpose. Or, the other way round: if you find that parts of a name you're looking at describe different purposes, then there is likely a copnflict with the single responsibility principle!
In other words, clean code leads to good, and reasonably short names.
But let's look at your examples:
doubleCalculateOffsetForWaveFunction(intScaleFactorForWaveFunction,floatWaveFunctionSeedValue)
doubleCalculateOffsetForInverseWaveFunction(intScaleFactorForWaveFunction,floatWaveFunctionSeedValue)
In these names, the type information does absolutely nothing to explain the purpose, so these parts must go. Next, the function names describe what the result is used for (the (inverse) wave function). This info should go into the argument list, not the name. That will also make the calculateOffset functionality easier to refactor: if there's anything you need to fix or change in the offset calculation, having just one function to look at is always preferable to having >1 functions!
As for naming style, I consider '_' separators to be more readable than any other style, but TBH I couldn't care less, so let's stick with what you had. With my comments above, you get just one function instead of two:
calculateOffset(scaleFactor, seedValue, functionType)
Since the function type goes into the argument list anyway, I've dropped it from the argument names. I'd also drop the meaningless suffix 'Value', but it's already a lot more readable. And all that without losing any information!
GOTOs are a bit like wire coat hangers: they tend to breed in the darkness, such that where there once were few, eventually there are many, and the program's architecture collapses beneath them. (Fran Poretto)
|
|
|
|
|
Indeed so!
For the avoidance of doubt, these were not functions created by me! 8)
I have never understood the need, even in interpreted languages like modern BASICs etc, for 'hungarian' notation - if the language isn't type-safe, then no amount of attaching prefixes etc is going to prevent some library assigning a string to the integer variable you just passed it silently and hence subtly altering the results etc.
Possibly useful as a reminder to you as coder, but cannot be relied on by anyone else reading your code, so better to have meaningful variables and proper tests, exception handling etc so that context reveals what should be going on.
I'm working on a very elderly codebase at the moment where some, but not all, tables are named tbl<name>; some, but not all, forms are frm<name>; some, but not all, reports rpt<name> etc etc. The lack of consistency renders all these prefixes completely useless and just makes typing out code tedious and mistake prone...
As for comments? Ah yes, I did find one, once, somewhere in the 100,000 or so lines of code...
|
|
|
|
|
Mike Winiberg wrote: For the avoidance of doubt, these were not functions created by me! 8)
Thought as much, your post made that pretty obvious.
Mike Winiberg wrote: if the language isn't type-safe , then no amount of attaching prefixes etc is going to prevent some library assigning a string to the integer variable you just passed it silently and hence subtly altering the results etc.
I beg to disagree. Prefixes or suffixes can be rather helpful in spotting semantic errors in places where no amount of type safety can prevent them. Consider this example:
class Box {
public:
double height();
} box;
double size = box.height();
This is perfectly fine with regards to the types being used, and there is no apparent reason to use different types. But what if the box is defined in meters, and the size you need expects millimeters? The code above will not so much as hint at a potential problem!
Now look at this code:
class Box {
public:
double height_m();
} box;
double size_mm = box.height_m();
The use of appropriate suffixes makes the error imediately obvious, without the help of comments.
GOTOs are a bit like wire coat hangers: they tend to breed in the darkness, such that where there once were few, eventually there are many, and the program's architecture collapses beneath them. (Fran Poretto)
|
|
|
|
|
I don't disagree with you, or the use of helpful hints like you suggest. But whilst your suggestion (and indeed hungarian notation etc in general) provides useful prompts and hints to the coder it doesn't address type safety and in fact can be counterproductive in non typesafe languages:
I hit this kind of thing a lot in an elderly VBA codebase that I maintain and develop for a client. GUIDs can be represented (validly) as either a string (in 3 different formats FFS!) or as a BYTE array. When reading a GUID from SQL Server into a table and thence into a form and onwards into code you usually get a string, but sometimes (I presume depending on the temperature of Bill Gates' shower at the time the code runs) you get a BYTE ARRAY - all of these can appear in the variable you assign them to if it's a Variant, and you can only find out which one you get by testing the type of the variable after assignment, or when an exception is raised on use! However, if you are attempting to assign the GUID to a string and it arrives as a BYTE array it doesn't cause an exception, instead you silently get a GUID consisting of '??????' 8)
I have spent many many hours tracking down strange bugs caused by this behaviour.
If (as I have discovered in code I inherited) errors have been disabled so that (unless the error is actually fatal) code continues with the statement after the one where an error occurs, you are falling down a rabbit hole with no bottom!
Note that although you may get a BYTE array GUID, this cannot be assigned to a GUID column in a table, so you have to convert it to a suitably formatted string (and the formatting acceptable depends on whether the table is local or on the SQL server).
Working on code like this when it is full of incredibly long-winded, supposedly 'typed' variable and function names is just adding insult to injury! 8)
|
|
|
|
|
I know what you mean. I've seen my share of legacy garbage. And it doesn't stop in front of the big names. I still remember one project where I tried to put a thin layer between our embedded application and embedded Windows (back then still called CE), in an attempt to port it to another embedded OS. I stopped when I realized just how full the Windows APIs were with inconsistencies, including a couple of obvious bugs (well they became obvious when I worked on it - they weren't obvious at all when you looked at the individual parts of the API in isolation )
Everybody makes mistakes, and the older the systems are, the more mistakes you'll find. That's just the way things are, and my own code is no exception.
That doesn't invalidate my statement though: if used in the way I presented above, even if used inconsistently, it will increase the likelyhood of discovering semantic errors.
That said, I wouldn't use hungarian notation for any of the examples you brought up: I agree with you that in those cases it served no meaningful purpose.
I've found the article that was at the back of my mind all the time when posting here: Making Wrong Code Look Wrong – Joel on Software[^] I really like how Joel explains the do's and don'ts of hungarian notation, and how to use it correctly.
GOTOs are a bit like wire coat hangers: they tend to breed in the darkness, such that where there once were few, eventually there are many, and the program's architecture collapses beneath them. (Fran Poretto)
|
|
|
|
|
Thanks for that link - I've read a few of his articles in the past and found them helpful.
So much to read - so little time!
8)
|
|
|
|
|
And having read the paper - I once again agree with what he says!
I was a fervent adopter of C++ in its early days, but as the language developed and got harder and harder both to use effectively and read I gave up using it. (The fiasco of manipulators between versions 1,2 and 3 didn't help either!) (Neither did a commercially produced database library 'accidentally' passing parameters by value and not by reference - as per the documentation - which caused an amazing array of problems until I tracked down just what was going on! 8) )
Joel's example of what appears to be a simple multiplication is one of my pet peeves about C++ and the fact that in a complex class you can end up with what are effectively class globals that can be accidentally hidden by local variables if you are not very careful is another. Once it became harder to use C++ effectively than it was to solve the programming problems I was using it for, I gave up.
As for exceptions, tracing back through 12 layers of exception handling to find out what is causing it is a nightmare - like he says useful for stuff that isn't mission critical, but a bottomless pit in difficult stuff.
|
|
|
|
|
grralph1 wrote: I love and respect Sander. Love you too man #nohomo #bromance 😘
|
|
|
|
|
Haha
"Rock journalism is people who can't write interviewing people who can't talk for people who can't read." Frank Zappa 1980
|
|
|
|
|
I did respond to the previously mentioned post, as one who does use silly names.
Perhaps a new topic, but I also leave silly (funny?) comments in the code for whomever receives the punishment of having to fix modify my code later.
if (...) {
-
-
} else {
}
Nothing succeeds like a budgie without teeth.
|
|
|
|
|
Yes I do remember your bravery and your pride.
I do like the idea of silly or humorous comments.
You only live once.
And it may cheer up someone who is reworking your work.
Weirdly though I hardly ever do it.
(Probably because no one else usually ever sees my source code.)
For the past 10 years I have been commenting for others. Prior to that it was only ever for me.
Thinking about this whole thing I have discovered that I appear to be most creative (not silly) when making up names for functions.
Less so for subs and variables.
However I recently noticed that in some legacy code that I had a public boolean variable called TheWhiteZone. The comment said "The white zone is for loading and unloading only".
This was exactly what the Var was indicating, loaded or not, and it wasn't aloud to park there. No Way.
"Rock journalism is people who can't write interviewing people who can't talk for people who can't read." Frank Zappa 1980
|
|
|
|
|
Indeed. I still remember that, when thinking how to properly initialize a boolean, rather than deciding whether to initialize it with true or false, I literally did initialize it with true||false
But that's decades ago, and I don't recall having done something silly as that ever since.
Although... I once caught a run time error in my code that I was convinced could never happen. Consequently, the error message stated something along the lines of "this should never happen - please contact {my name}". The client I delivered this to did have a laugh, but I was still happy to hear that it was caught in acceptance test and never went out to the real clients...
GOTOs are a bit like wire coat hangers: they tend to breed in the darkness, such that where there once were few, eventually there are many, and the program's architecture collapses beneath them. (Fran Poretto)
|
|
|
|
|
I use "result" or "response" when it is really a throw away variable for debugging purposes. Using "ewww" or "blurpp" is crossing the line. We are working, not joking with friends. Even if it's a personal project, bad habits get carried to other things.
|
|
|
|
|
Agree.
"Rock journalism is people who can't write interviewing people who can't talk for people who can't read." Frank Zappa 1980
|
|
|
|
|
I have used and will continue to use "temp" for a temporary variable that lives for one or two lines of code.
|
|
|
|
|
I always use something meaningful, even if it is a throwaway variable. I work hard to make my code readable and think of whether the name will help or hinder me six months from now. I have worked in way too much legacy code that took forever to figure out and understand maintenance is where the bulk of programming time gets spent. (much to my dismay!)
|
|
|
|
|
I learned from this series of posts to utilize "str" for strings. I never liked using "string" since it conflicts w/ std::string. I always use "using namespace std;"
I favor descriptive names however I would rewrite doubleCalculateOffsetForWaveFunction(intScaleFactorForWaveFunction,floatWaveFunctionSeedValue)
as
Offset_forWaveFunction(scale_factor, seed_value)
I don't believe in Hungarian notation as it is merely another source of error and of course the return value is already documented. "Calculate" is redundant since we know that's what functions do. I find it helpful to distinguish prepositions in the name. "ForWaveFunction" is not needed since the variable is in context. If this method was of a class WaveFunction then all that would be needed would be Offset(scale_factor, seed_value). My local variables are always lower case. Capitals I reserve for global or public objects.
I am fascinated by naming notation conventions. I like the notation to say something about the method and variable e.g. to distinguish public methods from private e.g. camel for public and snake for private though I am conflicted as I like snake as it is easy on the eyes with no capital letters shouting at me though I am currently utilizing all capitals for statics and terminate all lambdas with "_LAMBDA". I am eager to learn of other's techniques and preferences. - Cheerio
modified 23-Apr-21 11:16am.
|
|
|
|
|
Thanks for that it is very interesting.
Quote: doubleCalculateOffsetForWaveFunction(intScaleFactorForWaveFunction,floatWaveFunctionSeedValue)
Gee.
I can read your rewrite easily.
The original is like a the name for a Welsh town and the only person who could read that would be the OriginalGriff.
I have never used ALLCAPS for anything. No reason, just never even thought about it. Therefore no titleCASE case either.
I usually use camelCase now but used to use CamelCase. I sometimes but rarely use snake_case or a cross between it and one of the camel styles just for some emphasis.
For Public variables I always distinguish these with a g prefix. Like gWaveVal. The g indicates Global.
It is fascinating to hear what other peoples preferences are and also the reasons for their preference.
Thx
"Rock journalism is people who can't write interviewing people who can't talk for people who can't read." Frank Zappa 1980
|
|
|
|
|
I once came across a function whose purpose was to send a message to the Sales And Marketing application. The developer had amusingly but appropriately named the function TelegramSAM. Unfortunately, they had then got a little carried away:
The author was listed as M. Bolan
The variables were named "jungle", "faced", "jake", "make", "no" and "mistake".
|
|
|
|
|
This made me laugh.
What a great name for the function.
Almost the perfect name but in retro case.
It may fly completely over the head of younger developers though.
I like the idea of having a theme though.
However easy to get carried away.
"Rock journalism is people who can't write interviewing people who can't talk for people who can't read." Frank Zappa 1980
|
|
|
|
|
Hands down the 3 hardest problems in programming:
-naming stuff
-off-by-1-errors
For throwaways, I usually pick my repertoire of Result (for holding something that'll get returned) and Scrap (generic temporary).
For stuff like responses from dialog boxes, I either take my old-and-tried Scrap, or give it some meaningful name like "SerialNo" when the user is prompted for a serial.
|
|
|
|
|
Never heard of Scrap before so this is a new one for me.
I like naming stuff though and find this the easiest part.
Mind you have regretted some of my names.
"Rock journalism is people who can't write interviewing people who can't talk for people who can't read." Frank Zappa 1980
|
|
|
|
|
Some people have called my code idiosyncratic.
i , j , k for loop indices with scope inside the for loop.
rc for any numerical function return code with a small scope.
val for many kinds of value, as a formal argument name.
that for the argument of a copy constructor.
My input variables tend to have real names.
I mostly store results in variables instead of using the rvalue result because it's typical that I have to test them more than once.
|
|
|
|
|
Short and sweet is OK.
I detest super long naming. I am Lazy.
I will usually use i, j and k for loops but I also use n.
Preference order is i, n, j and then k.
I have no idea of why n became the second choice.
But it sort of just makes sense, as we can use it and it is a number.
"Rock journalism is people who can't write interviewing people who can't talk for people who can't read." Frank Zappa 1980
|
|
|
|
|
For decades I too used i,j,k for loops, but over the last years I increasingly switched to more telling names, so I wouldn't need to constantly check and doublecheck whether or not I'm referencing the right index within a triply nested loop. It's much easier to accidentally use "i" and "j" incorrectly than "row" and "column"!
This change of mind was caused mainly by having to read so many nested loop codes and constantly stumbling over the problem that code containing such nested loops would often do this not just once, but several times, but not always use the same index variables for the same index
GOTOs are a bit like wire coat hangers: they tend to breed in the darkness, such that where there once were few, eventually there are many, and the program's architecture collapses beneath them. (Fran Poretto)
|
|
|
|
|