6 ms·
When structuring code, elegance and efficiency always take top priority. However, when naming, my philosophy is always clarity over elegance. for example (in
by crimsonalucard 11y ago
When structuring code, elegance and efficiency always take top priority.
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.
- tmikaeld 11y agoI like the logic of this, but it goes against all books that i've read to keep it short. Why do we need to keep it short?
- NhanH 11y agoYou shouldn't try to make it short on purpose because that will obscure the meaning of the variable. But long name by itself could be systematic error in abstraction (BananaSingletonFactoryFactoryCacheFactory comes to mind). At the very least, reading long name will also take a lot more mental power to understand.
- tmikaeld 11y agoOf course, if the meaning makes no sense it shouldn't be long. But if the longer name provide meaning, shouldn't we use it if it's a complex thing and the words bring value?
- squidbidness 11y agoIn this case it's a symptom of poor cohesion and separation of concerns. If you find you're having to give very long names for things, it's worth looking for a way to decompose it into separate things that each do one simple thing. Then more than likely writing the code that composes the separate objects with the right operations will be the perfect substitute for the long name, and it will also be easier to maintain, since you won't have to update both the variable name and the logic that uses it; rewriting the actual expression or logic where it is used will take care of both tasks in one. This is what I usually take from the principle of letting the code itself be your documentation, where reasonable.
- crimsonalucard 11y agoWho says reverseListAndAddOneToEachElement isn't defined via the composition of smaller "separate things that each do one simple thing?" The naming convention still stands as it is not a "symptom of poor cohesion and separation of concerns."
- Confusion 11y agoWe need to expend effort to keep names short, while it is easy to let them become long. 'Keep it short' is shorthand for 'do not forget to expend effort towards keeping names from becoming long'. It's easy to unthinkingly come up with 'company_people'. It takes effort to reduce it to 'employees'. It's actually not just 'short', but 'short and simple'.
- crimsonalucard 11y agoI think it's the other way around. Programmers instinctively want to keep names elegant, similar to how they structure their code. IMO they actually have to kind of step out of their comfort zone if they want to write an ugly (but clear) name.
- walshemj 11y agoEasier to keep short names in programmers memory and less chance of spelling mistakes.
- crimsonalucard 11y agoin my case spelling mistakes are handled by the the editor or IDE.
- walshemj 11y agoAnd how would an ide know that n0cars should be nocars
- crimsonalucard 11y agoAn editor probably not know this but an IDE would. The IDE actually partially understands your code. If your function definition was (in python): 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.
- ajuc 11y agoI am suspicious of names containing "and". 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.
- Kiro 11y ago> but then why even make a function if all it does is calling 2 functions in sequence How else would you execute the functions? What initiates them?
- ajuc 11y agoThe "and you can't name it on higher level of abstraction" part is important.
- jacquesm 11y agoFunction composition is by far the better solution, it is future proof and requires less memorization.
- eru 11y agoIt's syntax is just somewhat ugly in Python. (Compared to, say, Haskell.)
- deleted 11y ago[deleted]
- squidbidness 11y agoHere is where "first write good code" applies, at the design level. This function is begging to be two separate, composable functions that each only do one thing. reverse(addToEach(input_list, 1))
- Kiro 11y agoBut what calls "reverse(addToEach(input_list, 1))" if not another function?
- ajuc 11y agoHopefully a function that can be corectly named.
- Kiro 11y agoWhat do you think is a better name? reverseListAndAddOneToEachElement is describing the function but I agree it feels ugly.
- IanCal 11y agoFor this level of grouping, I'd probably prefer something related to the actual domain. 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.
- deleted 11y ago[deleted]
- Confusion 11y agoWhen a long name only reflects what the code technically does, then I don't think it adds much above just writing (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.
- crimsonalucard 11y agoThat was just an example (I should have picked a better one). Usually, the definition won't be shorter than the name. Either way it takes a second longer to decipher the lisp then it does to read english. When composing many functions of similar complexity, it helps that the reader does not need to examine the definition of every single one. In this case, your given example would be significantly harder to understand.. See below (in haskell): 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.
- gsg 11y agoDoes it mutate the list in place or return a new one?
- crimsonalucard 11y agoIf I felt the the person reading the code needed to know... I'd go ahead and make that name even uglier.
- gsg 11y agoThat doesn't quite fit with "you already know exactly what it does" - you left out a detail. 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.
- crimsonalucard 11y ago> That doesn't quite fit with "you already know exactly what it does" - you left out a detail. 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)
- Grue3 11y agoCamelCase for functions in Python? Why.
- crimsonalucard 11y agowhy not?
- msellout 11y agoConvention. 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.
- yellowapple 11y agoThis is similar to most dynamic/scripting languages of that era, for that matter; both Perl and Ruby (and, IIRC, PHP) have similar conventions. Things got bungled when Java programmers started insisting on camelCased function names even outside of Java.
- fanf2 11y agoThings got bungled when Smalltalk used an old version of ASCII which had a backarrow instead of underscore. Smalltalk used backarrow for assignment and had no way to separate words in identifiers other than CamelCase. Smalltalk programmers kept this convention when they moved to Java, even though the technical limitation was gone and they could have used a more legible style.
- fluffyllemon 11y agoPEP 8: https://www.python.org/dev/peps/pep-0008/#function-names https://www.python.org/dev/peps/pep-0008/#function-names >Function names should be lowercase, with words separated by underscores as necessary to improve readability.
- sbov 11y agoIf you feel the need to write a reverseListAndAddOneToEachElement function for your code base, it is probably because you have lots of instances of it. 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.
- seabee 11y agoIME this also happens not because the function is reused, but because the programmer is trying to create functions at a 'high level of abstraction'. Usually this means one function that has a bunch of descriptively-named function calls chained together to avoid needing more than one control structure, or to hide for loops in other functions.