How to name things in programming
slideshare.net
slideshare.net
So 'i' is fine for a loop control variable with a scope of five lines but totally inadequate for something expressing a larger and longer lived concept.
Ditto for function names and parameters to functions, if the function and the parameters are named properly understanding the function is trivial.
So if you write a chunk of code that exports one or more functions that is where your effort should go, that's the public interface. The reduced scope of the rest of the code should make any naming issues much more limited.
This is also why it is good to assign one person on a team to defining the interfaces between the code. That way you get consistency in naming which is a great thing to have in a codebase.
Anecdote time:
I once worked for a game programming company. One of the programmers there would name all his functions and variables for fruit and vegetables. It was his way of ensuring job security. Guess who got saddled with untangling the salad when he left the company.
cucumber(cherry, strawberry, orange);
Good luck with that...
i heard a tale of some graph layout code that ended up as part of a Microsoft product - all of the things were named after birds.
sorted(pairs, key=lambda p: p[1])
Though in that case you might prefer using the operator module. sorted(pairs, key=operator.itemgetter(1))
The aspect of Ruby that frustrates me the most is over-use of anonymous blocks when a good name would help me enormously. pairs.sort_by(&:last)
No need for defining a block and naming its parameter either.As the slideshow illustrated, it's all about having good taste as an author. Knowing your audience and all that. In fact, that might have been a good point to add to his slides--that different coding styles are appropriate for different teams and projects.
times_two = -> (x) {x*2} # Proc (lambda)
times_two = Proc.new {|x| x*2} # Proc
[7, 13, 19, 23, 31].map(×_two)
Also, if you want to call a method on the objects, you could do: [7, 13, 19, 23, 31].map(&:to_s)
Which is a bizarre syntax, if you ask me (actually, not really if you know how I works in the background, but it still does look bizarre IHMO).Ruby gives you enough tools to write code clearly with good names if you want to. I think your complaint might be more about the particular style of Ruby a certain programmer wrote than the language itself.
Looks like that guy followed this guide http://mindprod.com/jgloss/unmainnaming.html
If you can't search for single-letter words in your "simple text editor", why are you using that simple text editor to code? In vi, at least, it's trivial: /\<a\>
I think he was contrasting it to an ide that will automatically find out which as "a"s are references to the same. ("Find usages" in most Java ides I think."
Yes, that's what was being said.
But it won't. In vi (and friends), \< is "beginning of word", and \> is "end of word", so \<a\> will not match the a in "absolute" or "tundra" or "fabulous", but will match the a in "(3+a)" and "a=7". Certainly there are text editors that don't let you express this, but they're so broken as to be basically unusable.
An IDE that is able to keep the various references separate is still more powerful, but the difference is tremendously smaller - particularly if you follow the scoping guidance at the root of this comment thread.
Edited to add: Additionally, if your cursor is already on the word in question, that search is one keystroke. * says "search for the word under the cursor" and incorporates the word boundary markers.
That said, this is also where the scope consideration comes into play. If something is used in 100 different lines, 300 lines apart across 3 files, then of course naming it 'a' is crazy. If something is only in scope over 5 or 10 lines, then you simply restrict your search to those lines (either explicitly with marks, line numbers, or pattern bounds; or implicitly by exiting the search when it gets to a region you don't care about - find-and-replace in vim has a "confirm" option).
True, but I have plenty of slides in my presentation without adding more :)
The 'small scope rule' is more of a situation when you can get away with names that are less good, because of the small scope. When I get into discussions about that, everyone agrees with each other, and it distracts from the issue of coming up with good names when the scope isn't tiny.
Also, 'i' for a loop control variable is a trick example: why aren't you using a language that loops over collections without using a loop index?
A few years ago, I programmed in Max/MSP (max4live, technically) for a while and one thing I found super-refreshing is the ease at which you could prototype and experiment your way to a solution just by not having to figure out what something should be called until you were good and ready. Ever since that time, I found that naming things is a big hindrance to evolving code from an experiment to a solution. Names get in the way until you're sure what the code is supposed to do (at which point, the above quote is true and you should be able to give it a descriptive name).
And I guess this is exactly why author wants programmers to learn from the masters of spoken langauges-- ability to use the right word(s) to explain the concept/abstraction/property/behaviour/type.
If one is unsure about how something works, then more often than not one would end up naming the thing wrong. By far and large, the most frustrating thing I've come across during code-reviews is generic names assigned to vars like 'buffer', 'arrays', 'queues' and so on... and SQL table names that have no relevance to the data being stored in them. It is a constant struggle to read and reason with such constructs. So if you know how something works, you are oblidged to name it approp.
Douglas Crockford in his 'JS: The Better Parts' talk at JSConf 2014 spoke about three responsibilities a developer must have:
1. Make life of people using the software better and to not frustrate them, humiliate them, hurt them, confuse them.
2. Make life of people maintaining/developing the software better . To not check-in cruft, bloat, and errors. Write the best code, and to not make anything worse.
3. Make life of people managing the business/development easier.
Here's a link to the talk: https://youtu.be/bo36MrBfTk4?t=3446
Typically when I'm doing something new, it starts as a pretty free-form prototype, which gets progressively refined as I figure out what in the hell I'm actually doing, and start pulling components and subfunctions out of the original spaghetti ball.
"Most of the things programmers say about comments in code are excuses for not writing any comments at all"
This is true. Here is my excuse:
1. Follow all rules for writing good comments 2. Comment is now short, crisp and concise 3. Apply "Extract Function" refactoring, use comment as function name 4. Your comment is a compiled entity now 5. Write testcases for the function that explicitly explain corner cases and weird behavior 5. You have no comments in the code any more
This rule can be applied almost all the time, although it can be quite hard to use when global variables or wide scopes are used (e.g. 1000 line for-loops in C). Comments are either obvious or they're lying. Why would you write something that the compiler will ignore eventually?
Comment-less code is not a virtue. Useful comments that describe the "why" (but not the "what" or "how") of code are a virtue.
Because your real target for your code is not the compiler, it's your co-workers, who will have to go back and read and modify your code. Plus, they may not be able to contact you with questions about your code.
A single well written comment can save your co-workers from having to read a hundred lines of test code (and correspondingly, test code boilerplate). Why not give them that kindness?
> Comments are either obvious or they're lying.
This argument only applies to poor comments, which were not maintained alongside the code. If you just remember that the audience your code was written for is not the compiler, it makes more sense.
Your co-workers and your future self. :)
If a function fits into page, refactoring it into several tiny well named functions will give you an implementation where you can easily see what you are trying to do, but makes it difficult to see what you are actually doing, as you need to jump around between function implementations to read it. With a few good comments you'll get the best of both worlds, and you can now read both your implementation and your intentions with a single continous read.
Your code works just as well if you assigned each function a unique number starting from 'func0' - that's how code obfuscators or minifiers work.
Unless the act of shoving comments into function names makes the compiler type-check them, you are still writing something that the compiler will ignore eventually.
Javadoc and comments are both forms of code documentation. Perhaps we can generalise OP's point to the following:
"Most of the things programmers say about documentation of code are excuses for not writing any documentation at all"
I'm not going to use a library without documentation in favour of one that is documented. Above a certain minimum standard, it doesn't matter how 'clean' the code is if you don't understand why it exists. Cute naming simply doesn't make up for a lack of documentation, and avoiding documentation should be considered a cone of shame, not a badge of honour.
Despite the point-free nature of Forth, there's still the problem of naming functions ("words" in Forth lingo) and global variables. Programming in Forth is an interesting exercise because you quickly see the relationship between how you factor your code and how you name your "words". You discover by yourself many of the rules in the slides. But I find this is really the case when one uses the 64x16 block editor I mentioned. Using standard files and editors removes a lot of the constrains, but they also allow more sloppy coding (which may be a good thing if you have something better to do; e.g. you just need to write a throwaway script to get the job done).
In my experience you can spend a lot of time (re)factoring and (re)naming things. Sometimes it's valuable because e.g. it helps you understanding the problem, and sometimes you are just bikeshedding yourself.
However, when naming, my philosophy is always clarity over elegance.
for example (in python):
def reverseListAndAddOneToEachElement(input_list):
Ugly, but clear. I don't even need to write out the full definition you already know exactly what it does.But if the longer name provide meaning, shouldn't we use it if it's a complex thing and the words bring value?
It's actually not just 'short', but 'short and simple'.
def nocars
but you called the function with: n0cars()
The ide would highlight n0cars because it could not find the definition. The IDE literally destroys the possibility of making trivial mistakes like this in a non-compiled language.Of course this depends on the ide. I use pycharm which not only checks for mistakes like these, but it highlights and automatically formats code to fit within PEP guidelines. The whole IDE actually attempts to fit your programming universe within the app, including debugging, and even connecting to a database.
It does come at a cost, however. Pycharm is heavy app and can be slow at times. It's also a complex tool to learn, but I wouldn't say it's more complex than learning vim or sublime.
Agreed Eclipse is a hog that should be lead to the slaughter. But an acceptable dev machine can be had for $250 at Best Buy.
I agree about clarity over everything else, but then why even make a function if all it does is calling 2 functions in sequence, and you can't name it on higher level of abstraction?
In this case wouldn't
[x+1 for x in input_list.reversed()]
be even clearer?True, functions allow you to change code in one place and affect many places (so they prevent "forgot to update one place" errors), but when function is named from its implementation instead of its purpose - it doesn't make much sense to change implementation anyway. The absolute worst thing is
def reverseListAndAddOneToEachElement(input_list):
#requirements changed
return [x+2 for x in input_list.reversed()]
So either I repeat myself by copy-pasting code, or I repeat myself by saying the same thing in implementation and in the name. It's the hardest problem in naming for me.How else would you execute the functions? What initiates them?
reverse(addToEach(input_list, 1))
def convertDF4ToMX6(data):
# The MX6 format is read as a stack rather
# than a queue, and requires data to be 1
# indexed rather than 0 indexed like DF4
# link_to_MX6 format spec 1.3.2 (v5)
# link_to_DF6 format spec 1.2.0 (v1)
Why are we reversing and adding one? What's the reason we need to do that so much that we're combining those two functions into a single call?This would then mean the calling points might look something like
mx6_data = convertDF4ToMX6(loadDF4(file))
return processMX6(mx6_data)
rather than mx6_data = reverseAndAddOneToEachElement(loadDF4(file))
return processMX6(mx6_data)
Rather contrived, I know. (map inc (reverse input_list))
given that the code is shorter than the name. It would be different if the function would be reusable, but in my experience that is rarely the case with such technical names.There would be added benefit to abstracting it into a separate method when the method name would explain what the code does functionally. Why does it need to be reverse and have one added to each element? Is the input somehow 'wrong' and needs to be corrected? Are we adapting the input list so it can be handled by some reusable code? Is there a previous algorithmic step whose output needs to be slightly tweaked before it can be handled by the next step? In each of these cases, I think there are different names or options better than the technical one.
subdivideListIntoPairsAndReturnListOfPairs .
reverseListAndAddOneToEachElement .
cloneListAndAppendToItself .
multiplyAllElementsByThree $
inputList
As other commenters have mentioned yes, the functions within the composition can be compositions themselves of more general functions, but my reasoning still stands. If you wrote the composition above in lisp primitives, it would be more complex and harder to decipher. Again, even with greater complexity, due to clear (but ugly) naming, the composition above does not require you to read any definitions to know exactly what it does. Your ability to comprehend what I'm doing rises because the above is written in a language most programmers understand better than any other language: English.Also usually the "why" is longer than the "name" so if it really needs a "why", what I tend to do is write a paragraph as a block comment. Much easier to understand a paragraph, then decipher a name. However, this isn't always the case and sometimes a "why" actually delivers more clarity than the technical name. It all depends on a subjective view of what is clear.
pairwise .
reverse . map (+1) .
flatten . replicate 2 .
map (*3) $
input
With all the functions being pretty standard (pairwise is my own name for subdivideListEtc, but it seems like a terse name that still explains what the operation is). Every fragment in this composition is smaller than the names you supplied, and all but one of them are standard Prelude functions that should be considered basic knowledge in Haskell. In addition, since the standard functions have parameters passed as values (rather than being part of the name like multiplyAllElementsByThree), this approach is easier to tinker with if one value was wrong (1 change, rather than 3 (name of function at definition, at use, and value in function definition)).Here's another perspective: My code, despite having several complicated procedures, had naming that was so utterly clear you were able to implement the entire thing based off of the naming alone. I didn't have to explain anything to you, I didn't have to write any comments, yet you understood it within a second after reading it. Could one say the same about your code?
Both of them clearly show what the function is doing in an operational sense, but neither give any high-level indication of what the whole thing is for. They don't say whether this is part of the computation of a hash function, or a format conversion, or what have you -- that takes documentation and proper naming. These just tell you a way of turning one random list into another.
I think your expanded example may be a bit of a special case, because it is at the level where for anything 'larger', technical names would be unwieldy or imprecise, while for anything smaller, abstraction would basically be aliasing. I think most commenters, or I at least, were erring towards the interpreting the original example as one of the first category. The large example shows how it could be appropriate.
But another point is that it is much easier to have a typo that compiles in code than in variable names.
Whether it is reasonable to leave that out or not, the point is that it takes a lot of text to unambiguously cover every possible facet of meaning even for tiny, simple operations.
My mistake. Take it from another perspective. The name is good because it lets you know every single detail about the function except for whether or not it mutates the list.
> Whether it is reasonable to leave that out or not, the point is that it takes a lot of text to unambiguously cover every possible facet of meaning even for tiny, simple operations.
Of course naming is limited, you can't describe an entire program with just names. I'm simply stating a convention: Clarity over elegance. I'd rather make the name as descriptive as possible over as elegant as possible. Perfect clarity and perfect elegance are rarely achievable.
So in short, if I see opportunities to increase clarity, I will do so at the cost of elegance, and I will only increase elegance if there is no sacrifice in clarity.
also:
createReversedListWithOneAddedToEachElementFrom(input_list)FYI for non-Pythonistas: the prevailing convention is lowercase_with_underscores for everything, except CamelCase for class names. Of course, the core types are mostly lowercase. I think it's somewhat like being a famous scientist; you know you're really important if your name is lowercase.
>Function names should be lowercase, with words separated by underscores as necessary to improve readability.
If you have lots of instances of it, its probably because there is a higher level, domain related reason why you're doing it. Your function should be called that, not reverseListAndAddOneToEachElement.
I disagree strongly with one or two of the rules. But an even bigger problem is that some (or even most) of the advice either has little value or doesn't really apply to programming. In english, shorter is better, but I'd much rather a longer class name that I can understand than one that's abbreviated to the point where I am forced to look up what its doing. A good rule of thumb that I try to follow is that for the most part, your code should be self explanatory (comments should cover the rest). We have these rules in programming for how to write variable names, and they're better than the ones in that slide. Another rule, that trumps any other is consistency. If you're working on a project that uses the passive voice (which I think works better for some cases) then use that. The nature of programming is different than natural language writing, and so it makes more sense that these rules that are trying to be transferred over are ill equipped to do so.
I mentioned that some of the things just don't make sense As an example, this was one of the slides, "when writing a novel a writer should create living people; people not characters. A character is a caricature." What does this mean? Its ironic that the slide preaches being short and to the point, and yet is bloated with abstract fluff.
> What's an appointment_list? A calendar
No. Chances are that "appointment" is already a thing in your domain language -- the language you'd use to talk to your customers and stakeholders -- and so appointment_list is a much clearer name than calendar, as long as we make the reasonable assumption that it names a collection of appointments.
When I give this talk, I make this clear. I agree. The point is that there's a lot more good advice from writers over the fine details of prose than there is from coders about fine details of code, such as naming. In the talk, I conclude that the advice from writers is entertaining, but not really relevant, but that it can inspire us to try to come up with our own guidelines for naming.
> We have these rules in programming for how to write variable names
Not enough. Also, they tend to be badly written and lack humour. But please share your favourites.
> when writing a novel a writer should create living people; people not characters. A character is a caricature
This is a digression from coding to functional design, in which 'personas' can be a useful refinement of the concept of an anonymous 'user'.
e.g.
int num = 42;
int acc = 0;
instead of; int n = 42;
int acc = 0;
and it gets worse when things get complicated; vector<int> dist; // stands for distances
vector<int> excs; // stands for excesses
Does anyone else have this problem? int n = 42;
int acc = 0;
FixedEdit: Install http://wbond.net/sublime_packages/alignment and add this key binding `{ "keys": ["ctrl+shift+a"], "command": "alignment" }`.
And yes, I know about git diff -w, but 1. not all tools built around git support it and 2. not everybody uses git.
Tracking bugs through changesets is hard enough, no need to make it harder on purpose.
git diff -wAlso, note that you can do the same in github:
Append ?w=1 to the url for the diff viewer and you'll get the whitespace ignored version.
Whitespace edits are the code equivalence of wikipedia formatting changes to increase the number of articles you've worked on without actually contributing anything.
Also, if you think that is easier to read you are actually setting yourself up by being deceived by formatting because you'll be skipping bits based on assuming you know what they say. Those are hard lessons to learn but the best way to understand a new piece of code that you're reading is not to read it like a book but like a machine, with a pencil and a notepad tracing the values of the variables as you execute the code in your head (or on the paper if it gets complex). You don't need to run the whole program that way, just the sections that you feel are hard to understand.
But ideally this is something that should be decided by each developer's personal editor config, like tab widths for indentation.
It does not logically follow from the code being "cleaner" that it is easier to read. Having to scan across a field of whitespace to get to the number makes it harder to read and easier to make mistakes. Having the indentation of the number be unrelated to the length of the variable name adds another aspect that makes it harder to read and easier to make mistakes.
It's also harder to edit, which makes you do fewer edits that make the code materially better.
parseModifier : String -> Outcome Modifier
parseModifier s = case s of
"shift" -> Ok Shift
"ctrl" -> Ok Ctrl
"alt" -> Ok Alt
"meta" -> Ok Meta
"command" -> Ok Meta
"windows" -> Ok Meta
x -> Err <| "Unknown modifier: " ++ x
I find it easier to read as is rather than if I dropped the alignment: parseModifier : String -> Outcome Modifier
parseModifier s = case s of
"shift" -> Ok Shift
"ctrl" -> Ok Ctrl
"alt" -> Ok Alt
"meta" -> Ok Meta
"command" -> Ok Meta
"windows" -> Ok Meta
x -> Err <| "Unknown modifier: " ++ x
As developers we spend more time reading code than editing it. Optimizing for readability seems like a better goal than optimizing for edit speed. Besides, most editors have functionality to align code. When I am looking over a file, the second example looks like a jumble of words to me, while the aligned version seems easier to parse (ha).To someone who views this as a table, the above is so much more readable that it doesn't even bear thinking about. To someone who reads code the way a computer parses it (as I do), the added space can completely throw them for a loop. What the hell are you doing with n? Oh, if I look far enough, there is an assignment there.
Very likely you will see what I've written and find it incomprehensible because you have never looked at an expression the way I do. What's worse is that there isn't just 2 ways to look at it. Coding style purists usually don't realize that they are simply fooling themselves into thinking that their way of looking at something is optimal for everyone.
As someone else mentioned, the day when we can express how we want our code formatted and our editors will instantly format it that way (for everyone) can't come soon enough. But until then, it would be best to simply realize that there is no "best" way and that you should go with what the majority of the team likes, no matter what you personal preference is.
Madonna, Rain, 3:45
Lady Gaga, Bad Romance, 4:17
U2, In God's Country, 3:57
LCD Soundsystem, I Can Change, 6:31
vs Madonna Rain 3:45
Lady Gaga Bad Romance 4:17
U2 In God's Country 3:57
LCD Soundsystem I Can Change 6:31
I'm not questioning that you find columnized code hard to read I'm just wondering would that apply to all forms of info? Your email list with time, name, subject. Your bank statement with data, biller, amount?If not any idea why tables work for you sometimes and not others?
But most code that has structural isomorphism should be replaced by a loop or a function composition; repeated structural isomorphism is a redundancy that can be eliminated.
Aligning the initialization of a bunch of unrelated variables is a bit of a mixed case. Sequences of initialization are much more common in older languages, like C, that don't permit delaying the declaration. I don't have a strong opinion either way. If the data being initialized is structural, a tabular format should definitely be used, if it isn't fighting the tool (some IDEs etc. autoformat, or lint complains on unnecessary whitespace). If data is not structural and the variables aren't strongly related to one another, I don't see a good argument in favour of alignment, particularly when variable names can have wildly different lengths, e.g.:
source = 10;
timeout = 20;
wait_count = 30;
ch = 0;
accumulator = 40;
access_denied_retry_callback_list = [];
I find this substantially harder to read (see name to value and vice versa) than non-tabulated initialization. source = 10;
timeout = 20;
wait_count = 30;
ch = 0;
accumulator = 40;
access_denied_retry_callback_list = []; source = 10;
timeout = 20;
wait_count = 30;
ch = 0;
accumulator = 40;
access_denied_retry_callback_list = [];
(Still, it's not tabular data, so it has no business being a table.) foo (5, 7);
barbar (j);
do_stuff(6, 1, 7);
or this with flow control statements: if (x == y) {
...
}
for (...) {
...
}
while(...) {
...
}
Things like array initialisers, however, I do align. int n[16] = {
15, 17, 22, 38,203,155, 7, 10,
255, 11, 44, 1, 0, 0, 5,227
};
To someone who reads code the way a computer parses it (as I do), the added space can completely throw them for a loop.Actually, if you were really reading "the way a computer parses it", you'd ignore whitespace completely.
I write a lot of coffeescript ;-)
Joking aside, on my current project we elide the parentheses when making function calls with arguments. So:
myfunc(foo)
myfunc (foo) ->
is an important difference when I'm reading the code. If you write: myfunc (foo) ->
it means the same thing, but it completely throws me for a loop because I have to look ahead too far. So you are right, I don't look at it the way the interpreter does. I'm inferior and can only handle a grammar with a single look ahead ;-)Prose is obviously different, but it's probably worth considering that the only consideration for the length of a paragraph is the rules of paragraph writing, and not at all the physical length of words and sentences.
And then there's refactoring and renaming, and what that does to your artfully placed characters.
Figure out your placement and spacing rules (or better, use a canned set of rules), use them, and think about other things.
The whole point of coding style is that someone else will have to read and maintain your code. If you step away from your code for even a month, it's almost like reading someone else's code when you come back to it. If you're writing code that will never be seen again, and simply has to work once, you don't need any style whatsoever. But that's not very common.
I think the biggest motivator is having to debug/port someone else's code full of magic numbers, short variables, long functions, global variables, and no comments.
Not every shorten the same word the same way, not even yourself next year.
Yes, you have worse problems than ambiguous abbreviations :) That doesn't make the abbreviations okay, though.
My early days of OOP, I started keeping a thesaurus on my bookshelf at work. Probably went overboard on naming for a while, but reigned it in. (Every writer shudders at their first efforts. Hoo boy).
We would also hold short discussions about names for things (I don't see this in the article's list of tools: Involve other people in the names you are choosing. After all, they'll be using the code, too).
I don't quite follow your observation, but if you are suggesting that this function would be better with verbose, Englishy naming, I think you are mistaken. Quite the opposite, the parametrically is better illustrated with hieroglyphs.
Regarding failing "for years as an engineering discipline", are you suggesting that imperative programming was "successful" because of the reliance on using naming to communicate intent in the midst of rampant state mutation and unbridled complexity?
Interestingly, functional programming leads to a different naming custom that this presentation didn't really cover. To write "functionally" you want to have pure single-purpose functions and the name is supposed to describe exactly what the function does. If you can't write a short enough function name then your function is probably too long and should be broken up into functions that can be given concise names.
Another interesting functional programming naming custom is that a function that transforms data (fully FP) should describe the final result rather than the action of changing it. So if you transform a string to json, the function should be simply called `json` rather than `string-to-json` or `json-parser`. This is because when reading the code you can clearly see that the string is now json (it can almost look like a type). Of course, if that function does anything else, then naming it `json` is wrong but the function is also breaking away from being pure and single-purpose.
Eg in the following snippet
map :: (a -> b) -> [a] -> [b]
map f (x:xs) = f x : map f xs
map _ [] = []
there's nothing known about x (apart from that you can apply f to it). So there's no way to give it a more descriptive name. We just don't have more information.Secondly, naming a function "json" requires the user read the code or the comments to figure out what it does, and blocks the user of the name for anything else that returns json. Suppose rather than a string you have a list that you need translated to json... what do you name the function?
There are three levels of documenting code: naming, comments, and the code itself. Function names should be chosen such that other developers can reasonably guess at a glance what the function does, because the two most comon use-cases for names are:
1) reading someone else's code, where digging in to find out what "json" does is orders of magnitude more work than reading "json_from_string"
and
2) figuring out how to do something in a given codebase, where skimming over a list of function names and picking out one or two that look likely for deeper investigation is orders of magnitude faster than reading the docs or the code for every function to find out which obscurely-named function does the job you want.
Longer, more fully descriptive names aid the user in the excecution of these use cases.
This is exactly what functional programming seeks to solve. This should be the same function. Every language that has the power to do FP has the ability to do multi-functions or pattern matching just for this kind of situation.
`json` --polymorphic languages make naming easy!
I miss a few things though.
1. Short functions can use abbrevs; because I can keep track of them.
2. "text_correction_by_editor" might convey a lot more info then "edit"; especially in code where "edit" (and derivative) are heavily overloaded. For instance I can imagine "text_correction_by_user" also exists, or "text_reload_by_editor".
3. Then the Java'isms. E.g. AbstractWhateverSomethingManager. This is more part of the language, paradigm (OO w/ big love for design patterns) and type of money used to pay for development (enterprise money). Its verbose, deterministic and very "correct". Once you are used to the jargon you quickly know what they do, as they explicitly encode one of more patterns in their name.
They are conventions (like Haskell types) but they lack the laws.
In the talk I explain that this is a real example, from software for a publishing company in the Netherlands. The 'editor' is the person who edits the text. The problem was that the subject matter experts used two different Dutch words for two different kinds of text correction, depending on whether the original author or the editor made the correction.
This example is about the tradeoff between making the difference explicit (text_correction_by_author vs text_correction_by_editor), or agreeing on consistent translations for the two Dutch words (e.g. 'edit' and 'revision').
I told him I'm not sure I'd ever fit into the Go community because the Go community seems to like variable names that are extremely short. For example:
func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)
I've even been "gently corrected" in #go-nuts on Freenode when I've shared code and I used "res" instead of "w" and "req" instead of "r" -- they told me my longer variable names wasted space and made it harder to read.Perhaps my brain works different, but I find variable names that are actual words much easier to read.
Because of this, anyone who's been wrangling HandlerFuncs for more than a few days tends to converge on w and r. At this point it's no more a problem than using short variables like d for distance or r for radius in math formulas.
As an aside, I have a file open right now with a struct member called "TentativeSpacesPerIndent int"; I'm not worried — yet — about how ungainly long it is because I'm still trying to figure out what indices I need to keep track of, and the last thing I want to do is confuse myself into using one type of index when I need another, or perhaps I need to track of something else entirely. On the other hand, I have
func NewScanner(bs []byte) Scanner
and all the thought I put into the name of the argument is "if a single byte should be a 'b', what should a slice of bytes be? 'bs'." That seems to be sufficient length for a five-line function.He was told by a doctor to take a pill
active:
The doctor told him to take a pill
What I also say in the talk is that this analogy is a stretch, but at least advice from writers about writing can inspire us to think about how we write code.
Two cases where you might want different factory classes(and hence need a common interface or base) are a factory for 'production' code and a factory that only generates mock objects for unit tests.
Having spent 5 minutes trying to understand what this class might do, I disagree with your claim that the name is clear.
Donald Knuth for one. He published Literate Programming in 1984. http://www-cs-faculty.stanford.edu/~uno/lp.html
If your library exposes 'getCurrentRuntimeContext' which is going to be used in every other line of user's code, name it 'ctx'.
It's ambiguous, but it saves the user 3 seconds per 2 lines of code.
As for the readability, when the reader encounteres 'ctx' for the third time (at line 6 of the source file) they will already know what it is supposed to mean by heart.
With autocompletion in most code editors saving the user typing time is not a valid argument anymore, and I would rather prefer comprehensible if slightly more verbose code than accronyms everywhere.
What is obviously ctx -> getCurrentRuntimeContext for you is completely foreign to the next guy. And sometimes you don't spend a large amount of time in a specific part of a code base, such as when debugging and then figuring out what ctx means is a real PITA.
That would suck in a big way.
You already have '+1' and '-1' so it's not even shorter (and those can't be sneakily inserted into expressions leading to side effects of the expression other than the value computed) and the post and pre-decrement versions of that can lead to very subtle bugs.
Long Names like SomeRealyLongNameFunctionThing and SomeRealySimialrLongFunctionNameThing are both hard to work with and confusing to me.
But not any shorter. "ctx" is just a bad name for a library to expose. Do rename it at those local contexts it'll be on every other line, but do not export it from a global library.