14 ms·
Clever vs. Insightful Code
- drewcoo 5y agoWhen I advise people to write simpler code I do mean "not clever." Nor do I mean "insightful." In fact, please make it so obvious that in reading it I don't gain/need/curse/applaud any insights. Make it simple enough that a brand new completely green junior member of the team immediately understands it on first reading. And if you can't make the code completely obvious (e.g. the sorting example), just add a comment. A simple one. None of this is about the creator's cleverness or deep understanding or speed or what tooling can do. It's not about the creator or the machine at all. Simple code is about clarity for all the people who will read and (hopefully not) debug it later.
- valenterry 5y ago> Make it simple enough that a brand new completely green junior member of the team immediately understands it on first reading. That can be a goal, but it's not necessarily the best one. We could of course write code so that it is most easily understood by someone who never programmed before. But that then reduces productivity for everyone with lots of experience and familiarity with that project/style/code. Sometimes you can write code that achieves both goals, but often you cannot and in that case the "simpler" version is not always the best.
- xupybd 5y agoIf we could make our domain specific code understandable to non coders we would have an easier time working with domain experts. That said it's near impossible to do that.
- valenterry 5y agoThe mistake lies in the assumption that technical details are not part of the domain - but they are. Sure, in some languages like C you cannot properly separate irrelevant technical details from the domain specific code. But for the more advanced programming languages that is certainly possible. The problem is just that things like the possibilities of errors, eventual consistency, concurrency and so on are relevant for the business domain as well. You simply cannot abstract over them in general. For domain experts who can actually deal with these issues as well, you can pick a language like Scala or Clojure which excel at creating embedded DSLs and then have the domain exports use them.
- xupybd 5y agoExcellent insight.
- bidirectional 5y agoJane Street does this, traders contribute to code reviews by developers. Though at Jane Street a trader probably has a STEM degree from MIT.
- userbinator 5y agoMake it simple enough that a brand new completely green junior member of the team immediately understands it on first reading. This is why the software industry continues to decline: it's self-inflicted dumbing-down. I really don't understand where this rampant support for antiintellectualism comes from in the software industry, besides managers who want to make employees easily replaceable "cogs in the machine"; and dread what the world would look like if everyone was encouraged to do the same in other (natural) languages.
- jeffreygoesto 5y agoI don't think it is black and white. Disentangling a heavily optimized "clever" codebase took me four weeks once. Refactoring did not only make it more understandable but also faster. Seems like often "clever" is used with those quotes around it and really stand for "(accidentally) complicated". Edit: From the article: 'I’m drawn to this distinction because I feel like our discussions of “clever code” are too constrained.'
- kenver 5y agoThis made me think about how we use the term 'over engineered' in our industry. In most industries it seems to be a good thing (i.e. space shuttle). In our industry it's synonymous with bad, unnecessarily complex code. We seem to have a knack of taking positive attributes such as clever, and flipping them!
- dgb23 5y agoIt’s not exclusively used for clever code. I think a more common case for the term is to describe a program/system that covers way more ground than it needs to in terms of abstraction, tooling, features, scalability and performance. Example: I handed off a website a year ago that didn’t have any sort of remarkable engineering/usage requirements on the backend side. Internal operations of our client however insisted on deploying it on a kube cluster, so we had to accommodate for that. All they actually needed was maybe some caching, if at all. Mild case, but I think of these types of stories when thinking of “over engineering”.
- IncRnd 5y ago> Make it simple enough that a brand new completely green junior member of the team immediately understands it on first reading. This is fine for writing business logic, but this is not good for domains that require insightful code in order to execute within certain time constraints. Some problems require domain knowledge and expertise, which means that you cannot as easily hire and treat programmers as replaceable commodities of junior level people.
- eru 5y agoDo keep in mind that there's a difference between reading and writing code. You might very well need experience and domain-level knowledge to write the code, but often you can still make it readable to beginners. Of course, 'often' doesn't mean always. See eg https://en.wikipedia.org/wiki/Fast_inverse_square_root https://en.wikipedia.org/wiki/Fast_inverse_square_root for an example of code that falls in this gap.
- xupybd 5y agoYes but this can be harder than writing good documentation along side the code. For example I work with software that automates CAD manufacturing. Knowing what side of the part is side A is hard to communicate. But we have drawings that help explain it all. I've yet to find a way to have this embedded into the code. Asci art comments are as good as I've gotten.
- eru 5y agoDonald Knuth thought about this problem before: https://en.wikipedia.org/wiki/Literate_programming https://en.wikipedia.org/wiki/Literate_programming (and https://wiki.c2.com/?LiterateProgramming https://wiki.c2.com/?LiterateProgramming)
- TeMPOraL 5y ago> Asci art comments are as good as I've gotten. This is good, and people should use it more. But, to go further than that, I recommend: - Setting an official, designated place for rich documentation related to code. A wiki, or a folder in a repo, or a separate repo - either works, as long as every developer is made aware the thing exists and is important. - Put references to documentation in that place in your code comments. Having done that, you can now put in your comments things like: // Which side is 'A' and which is 'B' is determined by // Some Method. The code below implements this logic. // The exact explanation (with diagrams) of the method can // be found in docs:/Algorithms/Some Method.docx Of course, that documentation storage place needs to be treated as an extension of the code repository - i.e. devs should have the same access rights (both technical and cultural) to it as they have to the codebase, so they can both peruse the documentation and keep it in sync with the code. -- On the ASCII diagrams, it might be worth checking if your specific case allows richer content to be embedded in code comments directly. For example, in the past, I worked in a Java shop, and realized I can embed images in the comments - the IDE I used would parse data URLs (like: "data:image/png;base64,iVBORw...") in one JavaDoc tag (don't remember which) and render the image in the tooltip! I only ever did embed a cat picture like this, because I soon realized not all Java IDEs will display the images - but if your team standardized on tooling that can handle it, it's an easy way to sneak in proper diagrams. It would be great if IDEs came with PlantUML support in code comments - there's a bunch of diagrams I have now that I'd love to embed in the source code, but can't, because nobody else can make their tool handle them automatically. (In general, it's worth investigating team/tooling-specific options you have for quality-of-life enhancements. For example, even though everyone in my current team uses different tooling for C++, they all use the same debugger - the one in Visual Studio. So I started producing Natvis definitions for some of the complex types we use, as well as error codes from proprietary APIs. While not exactly documentation, they remove some type noise and save you from searching for error codes.)
- anonytrary 5y agoA good junior is an expert at writing clever code. I think this desire is squashed out of people once they realize there are many more stakeholders in the code you write than just you. Being clever is often a waste of everyone's time.
- hyperpallium2 5y agoRead over your code, and wherever you meet with a section which you think is particularly fine, strike it out.
- yesenadam 5y agoThis is a paraphrase of Samuel Johnson's "Read over your compositions and, wherever you meet with a passage which you think is particularly fine, strike it out.” I learnt the truth in this when I spent years writing orchestral music. I think it's very similar to avoiding premature optimization. Each piece would take months, first sketching in the broad features - melody, harmony in a few voices, gradually adding more until I reached what seemed the end, then revising until no improvements came to mind on listening through, and lastly adding the large-scale dynamics, pauses, tempo changes, percussion. I learnt to always write/add just what I heard in my head, to try whatever it occurred to me to try, keep whatever changes sounded better, but never to plan anything. Sometimes, early on, a particularly nice bit would emerge fairly fully formed, of which I was proud, and I'd polish that moment immediately to a near-complete state. But then for months it was fixed, couldn't flex and evolve with the rest of the piece, being already "perfect"—or it was originally, not in its final context—and usually I'd regret it was there, all dead and shiny. They felt like fossilized vanity.
- nsoonhui 5y ago>Make it simple enough that a brand new completely green junior member of the team immediately understands it on first reading. But what if the junior member can't understand OOP, functional programming, has no idea of abstraction and can only produce duplication and duplication of code,should we also try to adjust to that level? I do see the need to keep code simple, but sometimes an additional layer of abstraction and complexity is needed because code maintenance task requires it, junior people most likely can't appreciate it until they are no longer junior.
- panta 5y agoThen probably it’s too junior, and not ready to be a contributor to the project. He should be brought up to speed with the basic technologies and tools used. Project quality should not be sacrificed.
- j_wtf_all_taken 5y ago> But what if the junior member can't understand OOP, functional programming, has no idea of abstraction and can only produce duplication and duplication of code ... then this person obviously did not pay attention in class and should probably not have been hired.
- ClumsyPilot 5y ago"But what if the junior member can't read english and mutiply 5 by 5"
- clusmore 5y ago> Make it simple enough that a brand new completely green junior member of the team immediately understands it on first reading. This is pretty close to Tony Hoare's quote: > There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult. It demands the same skill, devotion, insight, and even inspiration as the discovery of the simple physical laws which underlie the complex phenomena of nature.
- Mikhail_Edoshin 5y agoI'm writing an UTF-8 decoder (just for fun) and there's quite a lot of information to understand even before starting that. And as I started I found that it naturally codes itself into a state machine with 12 byte types, 8 decoding states and 11 moves. If I rewrite my notes to condense them I expect to get maybe 4 screenfuls of comments :) Not complex but not something easily digestible by a completely green junior member perhaps.
- bryanrasmussen 5y ago>In fact, please make it so obvious that in reading it I don't gain/need/curse/applaud any insights. at some point clarity requires succinctness, at some point obviousness becomes stupidity. The above requirement has not actual measurable parts and as such we can never know if we have made things too stupid in our attempt to make our code understandable by all parties. Finally as languages evolve and gain new syntactical structures it means that things come into the language that will not be known by everyone, if you want everything understandable by the least knowledgeable that means that you cannot improve your code base. Your biggest legacy problem becomes the least advanced programmer on your team.
- dqpb 5y agoWeakest Link Oriented Programming
- chii 5y agoinstead of classifying it as 'clever' and 'insight', i would classify it as knowledge in either the problem domain, or the solution stack/tech. Duff's device uses knowledge of the solution tech (C language features). The sorting bucket example uses knowledge of the problem space - that you are sorting birth years of today's population. Some code would have both incorporated - e.g., the fast inverse square root of Quake fame. It requires knowledge of how floating point gets represented, how longs get represented and what happens when you cast between them. It requires knowledge of logarithms and how exponentiation is related to logarithms, and how newton's method, with a good starting guess is quite accurate. As for clever code - the more knowledge (of either kind) you need to know, the "worse" it is for someone to maintain it. As a corollary, if you comment on the code, comment should include both any and all domain knowledge, as well as tech stack knowledge, and reduce the burden on the reader's mind.
- deleted 5y ago[deleted]
- brundolf 5y agoI don't think "good" vs "bad" has anything at all to do with "platform" vs "problem". It's really a question of "essential or extremely useful to the project goals" vs "fun/satisfying for the person being clever". That's the distinction we should focus on.
- sfvisser 5y agoI still stand by this: simplicity is a function on familiarity more than anything else. Twenty lines of procedural go code isn’t simpler than a one-liner of Closure. It might be, to some people.
- mjburgess 5y agoWe can define the number of concepts a program uses, "Program | Concepts", and likewise, TokenSimplicity(Program | LanguageConcepts, ProblemConcepts) As the number of tokens an ideal programmer perfectly knowing LP-Concepts would write to produce Program for an audience also perfectly knowing LP-Concepts, employing no other concepts than those stated. Needless complexity arises as a distance from TokenSimplicity, relative to some choice of concepts. That can arise because the programmer uses concepts outside their audiences competence, or fails to use the minimum number of tokens. NeedlessComplexity = abs(TokenCount(Program) - TokenSimplicity(Program | Concepts, ...)) This article distinguishes (1) using surprising L-Concepts to minimize TokenSimplicity and (2) using surprising P-Concepts. (1) is cleverness; (2) is insightfulness. And "surprising" is all about the audience having an familiarity which differs from the programmer, Suprise(ProgrammerConcepts, AudienceConcepts) = len(Audience - Programmer) So the objective of programming is to `min TokenSimplicity st. min Suprise`. Where concepts are surprising, they can only rarely be used in programming, and hence drive up the number of tokens/lines written. However, where the code is getting excessive, the programmer is encouraged to surprise the audience. The weighting of these objectives is of course team/problem/person specific. Typical webdev/bizapps perhaps extremely weights `min Suprise`, (perhaps routinely at the expense of properly understanding problem concepts). In algorithmic R&D areas (occasionally, eg., data science) we expect the audience to have nearly full relevant ProblemConcepts.
- Cthulhu_ 5y agoIt depends on how much knowledge you need to read each line. The other factor is how much work the code does. When it comes to Clojure or any kind of functional language or construct, those describe the "what"; what is the author trying to do, what should the code do. If you go for imperative code, it quickly becomes more about the "how". Loops are a great example; in functional languages and constructs, you say "filter, then map, then reduce". In an iterative language, you say "Create a variable I, then start a loop, check if it's below length of list, increment, get element I from list X", etc, you get the idea. The functional approach has a definite advantage here because - as long as you understand the language and constructs - it hides the implementation details and the exact approach to execution. A functional approach under water can transparently parallelize the request, even going as far as it becoming a distributed hadoop map/reduce job. Can't do that with a for loop. Anyway, I forgot where I was going with this. The 20 lines can be fine if the one-liner is complicated.
- contrast 5y agoWhile the author is suggesting some good techniques, I suspect that if your code is being criticised for being “clever”, you’re unlikely to improve the situation by arguing that in fact it’s “insightful”. In my view, the most important aspect of what we mean by “clever code” is that the “cleverness” primarily serves to demonstrate how clever the programmer is. In other words, in some sense it obfuscates what the code is actually doing or why certain choices have been made, without delivering sufficient benefit to outweigh the cost to readability and maintainability. To use their bucket sort example, probably you’d want to stick a quick comment in the code that bucket sort has been chosen (and why). That helps with readability. But there’s nothing “clever” about choosing a standard algorithm to solve a problem. Absolutely, making the right choice demonstrates insight - but it also demonstrates genuine cleverness. Really it boils down to how it doesn’t matter whether the code is being called “clever”, “insightful”, or “amazing”. It matters whether a) the tone is dripping with sarcasm, or b) the tone is respectful but the feedback also contains a warning to format and comment for readability.
- mtrycz2 5y agoWe don't write code for computers to run, but for other programmers to read. Best make it so that they understand it. Who "they" is might be dependent on the situation.
- engmgrmgr 5y agoIf you have either high performance real time needs, and it’s impactful to do so, or tight deliverables where performance is some component, the code is often written for a computer over a human. The more specialized or niche certain project areas are, the less likely anyone will ever be reading it directly as a programmer (and those that need to, are often able to disentangle the obscurity). The compromise is a clean interface to otherwise isolated or pure functions. Often times, this is unfortunately poorly executed or inappropriately assumed. Usually the people who should write clever code are the ones who have experience writing clever code, but almost certainly anyone starting to write clever code is writing terrible code. Inexperienced folks often write clever code to solve a business need at that time. They create tremendous tech and culture debt. It’s easy to not understand when you’re an IC or line manager, though, that the business could have been severely affected otherwise. I’ll take millions in tech debt opportunity cost and the future morale hit over a failed startup/vertical any day. Just my 2c in high performance or hardware constrained projects both as an IC, and as various levels of management who’s both inherited mountains of “clever” shit and and built my own directly or indirectly.
- imvetri 5y agoClever code vs Insightful Code. Code is a configuration. Configuration is no code. Clever code vs Insightful code vs No code
- aldanor 5y agoClever comments vs insightful comments... vs useless comments.
- gsliepen 5y agoA great source of both clever and insightful code can be found at https://codegolf.stackexchange.com/ https://codegolf.stackexchange.com/. Code golf is the sport of writing the smallest amount of code that solves a problem. It requires both clever use of syntax to write short code, but also insight in how to reduce the problem to something much simpler than it at first appears. For example, take this problem that checks if the given color name is one of the colors of the rainbow, where the insight is that you can create a perfect hash function to solve it: https://codegolf.stackexchange.com/questions/214678/is-it-a-rainbow-color https://codegolf.stackexchange.com/questions/214678/is-it-a-...
- ano88888 5y agoThe example given about the 120 years old assumption will very likely be broken in the next 10 to 20 years... Perhaps it is better and safer to just stick to simple code.
- bidirectional 5y agoIs it simpler, though? It has fewer assumptions, but writing quicksort from scratch is probably a lot more challenging than putting items into buckets in a single pass.
- 29athrowaway 5y agoIf you change it slightly you can make it more readable: def is_unique(elements): unique_elements = set(elements) has_only_unique_elements = len(unique_elements) == len(elements) return has_only_unique_elements The problem was using identifiers like "l", and trying to make everything a one-liner. Adding a docstring or comment can help too. Is that still "clever code" after these few changes? I would say no.
- aldanor 5y agoAnyone who's written a fair share of Python can immediately see "len(set(l)) == len(l)" as "no duplicate elements", this is such a standard way to check for duplicates in Python that the chances are you've see this expression in this exact form dozens if not hundreds of times already. Agreed with "l" identifier and docstring/comment. You'd probably write it like this if you want it to look nice: from typing import Iterable, Any def is_unique(elements: Iterable[Any]) -> bool: "Returns True if the argument has no duplicate elements." elements = list(elements) return len(elements) == len(set(elements))
- 29athrowaway 5y agoI know Python but my Python is not the most Pythonic. The typing does make it more readable, but the "anyone who's written a fair share of Python can immediately see..." argument doesn't resonate with me. Naming boolean expressions saves time.
- koningrobot 5y agoThey did name the boolean expression; they named it `is_unique`. It's a poor name, but that's a different argument.
- bidirectional 5y agoIt blows my mind that anyone would consider your refactoring more readable. I don't think the example in OP suffers from readability issues at all, nor did the article suggest that. If anything it was just good, simple, 'clever' code.
- theshrike79 5y agoA paraphrased translation from Lieutenant General Aksel Frederik Airo from Finland: You need to go to shit-ton of schools to be able to make simple decisions. Otherwise you'll start to invent all kinds of over-complicated solutions. Everything in war is simple. The guy in the front lines is the one at war. You can't win in a war unless you give simple orders. The people on top need to be able to give commands that are so simple that even the man in the front lines understands. Everything is as simple as possible. To understand that, you need to go study a lot. It's not easy to do things the simple way, being clever is the easy path. Knowing when you need to be clever and when simple is enough is what separates experience from greenhorns.
- TeMPOraL 5y agoIt's a nice sentiment... for running a military. Or managing a company with very high turnover. I don't think it maps well to software development. The soldiers on the front lines spent years being trained to obey orders first, ask questions later. This is necessary because they're risking their lives, and explaining to each and every one of your grunts why it's important they do the thing that's likely to kill them, does not scale. You won't achieve your policy goals if your soldiers each decide the war isn't worth fighting, the orders aren't worth risking lives for. Software developers spend years training (or self-training) to use their brains to solve complex problems, which involves continuous learning, constantly making "tactical" decisions, and quickly gaining understanding of the big picture. It's a shame to first filter people by how good they're at complex technical work, and then make them stop using these skills, for the sake of shortening onboarding time.
- k__ 5y agoThis is so true. We need to stop perpetuating the leadership lie in white collar jobs.
- codingdave 5y agoI think you may be misunderstanding "simple". Simple works great for complex software because simple functions and features are assembled together into the fully complex solution. As a matter of fact, that is what makes a great dev - someone who can envision a complex solution, but then break it down into simple programming tasks.
- pmichaud 5y agoOne practical lesson I’ve learned about how to keep code simple is that possibly the most important factor to simplicity is staying on the same abstraction layer, ie. not accidentally slipping up or down the layers within the same code “stanza.” If I’m trying to read a function that is ostensibly about, say, user auth, but what I’m actually reading is about database error handling and bitwise operations on a user role bitfield, something has gone wrong in terms of simplicity. A dumb example is “How do you drive a car?” The right answer is something like “Gas goes, Brakes slows, Wheel turns.” The wrong answer is something like “Ok well, you see there’s a drivetrain... oh and a spark plug, and then...” In my experience very few code blocks need to be legit complex, eg. the core algorithm of some novel processing you’re doing on the data that came from a paper in the relevant field. Those unusual blocks can be sequestered and documented straightforwardly, with clear variable names and a comprehensive test harness around it.
- j_wtf_all_taken 5y agoWe'll never get those things right at first. That's why - specifically the more complex code you talk about - stuff should be isolated with clearly defined interfaces, known or no side-effects etc. Only then its possible to reorganize and refactor the code when you figure out how it actually should be. For example, the car driving example: what about the drivers license you need? All the traffic regulations you have to follow? Also gotta buy or rent a car to be able to drive one. What do you do if your car breaks down? Maintenance?
- pmichaud 5y agoAll those are great examples of things on different abstraction layers. I agree with you insofar as you can't know what you're building ahead of time so writing software is continuous process of revision, but it's still the case that when I'm writing a particular piece of code I can ask myself what is actually on this layer vs not on this layer, and write my code accordingly.
- redsummer 5y agoOrwell: Good code is like a window pane
- j_wtf_all_taken 5y agoI really hate that saying "its simple until you make it complicated". No! I really like the distinction between "simple" and "easy". Writing a little script that does some job is easy. Then you add lots of extra conditions and edge cases and exceptions because damn, its not as easy as you thought, so the script becomes complicated. After a while you figure out what the problem domain is, think of some smarter rules making the thing complex. Then you dumb down those rules, throw out unnecessary stuff, streamline things, realize that multiple specifically covered edge cases can actually be covered by changing some structure in your code etc - and finally, finally that all makes the thing simple. Simple isn't dumb. Simple is so elegant and smart that it looks dumb.
- kiddico 5y ago> Simple is so elegant and smart that it looks dumb. It should look so dumb that when someone reads it they think "well, yeah, this is obviously how it should be done." Of course, had they not read the finished product it's unlikely that they would have landed on that "obvious" solution on their first try.
- lamontcg 5y agoI think "clever" is being applied at one level here and "insightful" is being applied at another. You can write code at the equivalent of an 8th grade reading level like Hemingway wrote. Each sentence can can be basic using a small vocabulary. Put together the whole novel can have depth and be insightful. Its the difference between Hemingway and an actual random 8th grader.
- GuB-42 5y agoI am the only one to actually like reading clever code? When I see something like Duff's Device, my first reaction is a big WTF, like everyone else, but then, I sit down, try to understand, and when I get it, I am happy because I learned something. In fact, seeing Duff's Device is really what help me understand switch/case in C. And Duff's Device is certainly outdated, but it is by no mean "bad". If you need to unroll a loop by hand, that a good way to do it, it is just that you don't need to unroll loops anymore. So if you write code I have to read later, please don't hold back, use every clever trick you have. A small comment would be appreciated but not necessary. This way, I can read your code and think "I learned something today". Does it slows down comprehension? Of course it does... once. That's the cost of learning, but it is an investment, next time, I'll be faster. I am really talking about the cleverness the article disapproves of. I also value insight, but here, I agree with the article. I know a common saying is "newbies should understand your code at first glance". I only agree when by newbies, it means newbies on the project with regards to domain-specific knowledge. But when it comes to general principles, including knowledge of the programming language, code should be written for the highest level of expertise you can reach (but no further, you have to understand what you a doing!). I mean, if you are not using the full power of your tools, not only you are dragging yourself down, but the newbie you are trying to be kind with will not learn anything new.
- j_wtf_all_taken 5y agoNewbie can also be yourself looking at your own code a year later. You will have forgotten a lot and will have made it harder for yourself to re-understand what you were doing. There's a difference between learning stuff and applying stuff. Its about not making the code more complicated and obscure than necessary. Using generic language constructs like switch/case - sure. I don't think that falls in the category of "clever".
- GuB-42 5y ago> Newbie can also be yourself looking at your own code a year later. You will have forgotten a lot and will have made it harder for yourself to re-understand what you were doing. I hear this argument a lot but maybe that's just me but I don't forget much. I don't have perfect memory, far from it, but remembering my thought process when faced with my old code, even decades old is not really a problem for me, especially if a lot of though was put into it, as it tends to be the case with "clever" code. And it can also an important part of the learning process, reading old code is a good way to take a step back and seeing what really are the good ideas and the ones that are terrible. Also, I don't think there is too much of a difference between learning and applying, especially not in programming. That's one thing I love with this job, there is always more to learn, and while theory is also important, it happens by actually doing things. Boring, repetitive tasks are for the computer, not the developer. And I totally agree that one should not make the code more complicated than necessary, but what it necessary is maybe the hardest skill to master. As for Duff's Device is definitely "clever", few people realize that switch/case in C are that closely related to goto, it is not how they are usually taught and I certainly didn't before seeing Duff's Device. And there are more straightforwards ways of manually unrolling loops that don't have you pause and think.