Seems to be an obvious question, but I haven't seen one authoritative answer to this. People can have opinions about code quality for sure, or people can use phrases like "Bad code is bad code, whether it compiles or not." (from this article).
But can we define what is bad code? Can we all agree on that one definition?
I guess this definition will change over time. Shall we make a committee which will publish a new definition every year?
What I'm trying to say is that this is not a trivial problem to decide if this code is bad or is good, the same way as it is hard to say if this is the best chess move or not (I can give you an answer, but how you gonna know it is true, it is hard to test).
It is possible to identify some parameters of code, like LoC, coverage by tests.
Other parameters are harder, for example, readability. Readability depends on the reader.
We - developers like to throw around those terms like 10x programmer, bad code, etc. But in practice those terms like mythical creatures. Everybody has different ideas, sometimes definition is "I know it when I see it".
How we suppose to have constructive discussion throwing those ambiguous terms around.
Photo by Maria Teneva on Unsplash
Top comments (48)
Like most things in life, I'd say the real answer is purely relative.
I believe the most important thing to know isn't if it's bad or good, its can it be made better?
The reason why there is no set rule for "perfect code", or "bad code" is its all relative. There are some red flags, and code smells, but I'm sure there are cases where these rules are to be broken. 😉
I believe all code could be improved. To believe all code is bad is a way you can go about improving yourself and code, rather than considering things black and white.
👍
But this means that you can't just throw around this phrase without specifying what exactly you want to say. There is no single definition of bad code everybody agrees on...
The best code is no code.
I agree that it's mostly relative and purpose-determined, though everyone develops some personal aesthetic sense over time.
Gerald Weinberg writes in his timeless piece
The Psychology of Computer Programming
that an objective question to ask is if the code lives up to the requirements.About your last link, this issue made me lmfao: github.com/kelseyhightower/nocode/.... Plenty more like this one in the issues!
Any definition that a lot of developers can all agree with is going to be pretty general. I'd define bad code in light of what ideal good code is.
Readability is a tricky one, because it depends so much on the context and the reader. A novice will have a hard time following very dense code written to solve a difficult problem, but that doesn't automatically mean it's bad code.
Maybe this question of definitions is missing a piece. The more complete question might ask "bad code for what?" Without context or a stated purpose, it's not fair to judge code in a vacuum.
There's a lot of code written for code golf. It's largely impenetrable and undocumented and probably doesn't even solve a real problem! Does that mean it's bad? Because I think it's beautiful and clever and perfectly suited to the situation.
And any written definition for judging good code from bad is going to be either so general or so contentious as to be useless without taking context into account.
So, my definition of bad code? It depends.
I like your response. I will question parts of it to make it even better
But how to know what it suppose to do? We can write specification, but typical software specifications are partials, they are not formal specifications. Not a lot of people write models and check it with TLA+, right?
It can be quite expensive to write the specification. And this is hard to write full specification if you don't know full requirements, if your business needs to response to market changes.
The second part it is quite hard to verify that software is working according to the specification, we can prove that some portion of software confirms to some portion of spec, but to prove it confirms 100% we need to use formal verification, which is hard and expensive.
Readability. I agree. But this means we need to give definition for readability to accomplish definition of good/bad code.
💯this what frustrates me when people use this phrase in the context "bad code is bad". Bad for what? Maybe there were reasons for it?
Bad code can be replaced. If it can't be replaced, problem not in the code, but in communication - nobody took time to write down all requirements in any other form rather than code, and nobody can reverse engineer this code. This is not a bad code problem, this is organisational problem.
Oh man the point you made about good code being so elegant you learn from it. I started a new job as a software developer. The database was down for a week so I spent a week reading line by line the code. There are two parts to the code.
The refactored code was so easy to read and understand. I was able to learn from it.
Example using wrappers in Python to deserialize JSON files instead of manually decoding
I recently started debugging part of the models that haven't been refactored and it's so bad I don't think even the guy who wrote it knows what it is doing.
But the question is your problem in the bad code itself or the fact that there is no other documentation of requirements rather than code itself? (Otherwise you can throw it away and rewrite from the scratch).
Do you know in which conditions this code was written?
The first person who programmed it has a PhD in statistics and has little to no background in programming. The "documentation" I have to compare it against is an Excel sheet with complex formulas. The logic in the Excel is completely different from the logic in the Python he wrote.
Irrelevant P.S. I'm a so-so chess player myself, but I would think a chess grand master with a grasp of the underlying concepts of the game could quantifiably (rather than subjectively) define and explain whether "that chess move" is at least a candidate for best.
In any case, he could still whip my tail.
P.P.S. Apparently a single board position in chess is NOT NP-complete. (See also). Therefore, a "best move" is provable, at least in some cases.
NP complete problem is hard to solve but when you got the answer it is very easy to check. For example, factorisation of numbers, if I will give you number which is product of two very big prime numbers it will be hard for you to find which numbers are those, but if I will tell you at least one you will be able to check it immediately. So yes chess is not NP complete. (Link to the video I provided in the article says the same
¯\_(ツ)_/¯
)The link you provided mentions PSPACE. Here is comparison of NP-complete vs PSPACE-complete.
This quote says basically the same. For NP-complete problem it is easy to confirm the correctness of answer for PSPACE-complete it is hard to "convince" the correctness of given answer.
Thanks for your response. Good insight.
Based on my link and your comment, I'm still not certain that all that applies to a single board position, which has a very limited number, even a countable number, of possible moves. So, whether a move is the "best" is going to depend on your definition of "best" (there's that same pernicious relativity we keep hitting in regards to "bad code".)
If we're talking about "the move that is going to create the least immediate disadvantage" (minimizing the value of the pieces at risk of immediate loss), that's definitely P.
If we're talking about "in the context of the whole game", it would depend on the number of moves out from the end of the game, because (off the top of my head), the number of possibilities to be analyzed for, say, three moves from checkmate would be the possible moves for this turn times the possible moves for next turn, so on and so forth. (Not strictly calcuable, mind you, since the number of possible moves changes depending on the previous term. NP again.)
In other words, a chessmaster could easily explain whether a move is "best" in the context of endgame. That's not even remotely NP. I think that's precisely why there are entire books of endgames to study.
But the entire game of chess from the start is NP-hard (although not NP-complete, as I cited.)
Or to put that another way...
(In spooky voice) It depeeeeeeeeeeeeeends.
For anybody who reads this conversation and not sure what is NP-hard vs NP-complete:
It makes a lot of sense from chess player point of view to study endgames and openings, but this logic doesn't apply to study of complexity. Talking about endgames is like comparing sort algorithms for almost sorted arrays. Nobody interested in that.
People are talking about big O notation (sometimes about big Theta). Right?
"It depends" applies to common knowledge, like subject of this article (what is bad code), but I don't think it applies to scientific or mathematical discussion. (Unless we are talking about philosophical interpretation, but we are not in that situation anyway).
To be fair I already lost the thread of conversation...
Well, I don't want to lose context. I was referring to what you said in the article.
There are some values of "best move" which can be quantifiably stated and proven. In the same way, there are some values of "good code" and "bad code" which can be quantifiably stated and proven. Just because the sum total is NP-hard or NP-complete doesn't mean that all parts therein are also NP.
In any case, thoroughly interesting conversation! Thanks.
P.S. "Almost sorted" actually does make for some interesting sorting algorithmic efficiency discussions. There are forms of "almost sorted" that actually bring out inefficiencies in certain sorting algorithms.
Yes, I know that this thread is addressed to my reference to chess. But what you try to say to me? This is how I see it:
¯\_(ツ)_/¯
Where this going?
The overarching point is, you said "you can't prove that X chess move is best." And I just proved that, actually, yes, you can in some cases.
I mean obviously in some case it is provable, like one move before checkmate. But I talked about general case, the same way as you talk about worst case in big O notation...
Yes, and if we go alllllllllllll the way back to the original topic of the article, some "bad code" situations are provable. It is not entirely subjective.
And the chess analogy mirrors that.
Which is my point.
True like this one
A second pass on this. THIS is bad code because it is ambiguous to the reader.
8 / 2(2 + 2)
There's a big internet argument as to whether it's 1 or 16, and it is bad code because there are multiple justifiable results from it, and the next person to come on the code may have a different interpretation.
but to me this seems like outlier, rather than typical example
I provided you an entire list of quantifiably "bad code" principles in my other comment. None of them are outliers, IME; I've yet to find a single contradiction to any of them in any discussion about coding practice. :)
All good code is alike; bad code is bad in its own way. -- Leo Tolstoy
The code I'm working with is bad in that I'm having to dig though hundreds of global of questionable necessity, and functions like
modify_all_variables()
that's ALL side-effects, so that it's hard to know what the behavior actually is, much less modify or replace it.But there are many other ways to have bad code.
The quote 😂
A lot off side effects in one function, means that it is hard to "load" the code in the head, right?
. source
The lack of modularity and proper abstractions makes it hard to modify. Is it bad "editability" (inventing the word in the same vein as "readability")?
I always ❤ MonkeyUser.
I think there's more to it than that. For example I try to keep subroutines to where I can see everything they do in one screen, and while that used to be 24 rows by 80 columns (standard VT100 terminal size, back in the day), for VSCode on a HD monitor, I'm running 55x90 or so. Even fairly straightforward code can be hard to track if it's into the KLOCs without structure.
In my case, with
modify_all_variables()
, I don't know what's in it, I have once found where it is (I don't believe it's in the program at hand) and I would have been much happier to seevar new_vals = modify_all_vars(old_vals)
, as this cuts the scope to what's being modified tonew_vals
andold_vals
, giving me much less to fit into my head.So, yes, I guess, although that "lost" feeling comes more when I'm very full-stack, leaping a lot from CSS to HTML to JS to backend code (in my case, Perl) to SQL to Bash and back and forth a lot. I swear, there have been days when I could not pull together a complete sentence after that bulldada, but this is less bad code than all eggs in my basket.
("Editability" has past usage at least as far as 2009, and while it may not be in Webster's, anyone who understands read -> readable -> readability should be able to get editability, so we should start lobbying the OED.)
A second pass on this. THIS is bad code because it is ambiguous to the reader.
8 / 2(2 + 2)
There's a big internet argument as to whether it's 1 or 16, and it is bad code because there are multiple justifiable results from it, and the next person to come on the code may have a different interpretation.
Bad code is code that costs more than it needs to.
Some of the ways that code costs us is when:
It's too slow/uses too many resources, it does the wrong thing, it's too hard to understand, it's too hard to change, or it's too hard to delete.
Code is bad code (and not merely solving a complex problem) when there is a way to (re)write it that would be faster, does the right thing, is easier to understand, is easier to change, and is easier to delete.
Who cares if it still produce more money than it spends? (There are people which will ask this question)
Assuming we know what the right thing is. I mean we can know some portion of requirements. The question is: which portion is it 20%, 50%, 80% (based on Pareto principle)? To makes sure software is doing 100% correct thing we need formal specification and verification, which is hard.
I call this "bad readability" (I count how much people mention this in comments)
sounds reasonable
There's a lot of great answers in the comments already, but for what it's worth, here's what I've observed:
I agree there's a lot of relativity to it. What is "good code" or "bad code" depends on your language, your paradigm(s) (object-oriented, procedural, functional, etc.), your project, your standards, and so on and so forth.
However, I think there are some common traits of bad code, including...
Lack of clarity. If someone who has a reasonable grasp on the language cannot discern what it does, there's a problem.
Lack of readability. Different languages are capable of different levels of readability (e.g. in general, COBOL source is not going to be as readable as Python, for example), so we have to compare apples to apples, but when style convention and consistent formatting are ignored, the code is going to be an eyesore.
Poor naming.
x
,foo
, andxztoab
tell us nothing about what the variable or function does. Use self-commenting code principles.Lack of appropriate intent commenting. Without going into the entire debate about commenting, many programmers agree that if the programmer's intent for a block of code is unclear from the code itself, that's what a comment is for. (Comment WHY, never WHAT.)
Lack of proper structure. Regardless of what paradigm(s) you follow, there are structures that the code should be organized into. When this organization is lacking or misapplied, we get spaghetti code. (Also, see below.)
Lack of clear responsibility. I think the single-responsibility principle can be applied to most structures, regardless of paradigm. A function for writing to a file shouldn't also be the home of the network-checking code. An object for storing high scores shouldn't also contain sound volume settings.
Magic numbers. What is that
976
doing in the super important math calculation? We have no idea! Important (and otherwise seemingly arbitrary) numbers should generally be named, usually by assignment to a variable or constant.Long story short: code should be well-structured and well-formatted (as appropriate to the language/paradigm), (therefore) readable, (therefore) maintainable.
We could, of course, go pretty deep into the principles of clean coding, DRY, SOLID, and the like, but the exact rules will depend on your language and paradigm. (And even then, they're not a magic bullet.)
Ironically, I think most programmers can agree on what very bad code is. We mainly start having difficulty agreeing when it comes to what good code is, and that (again) depends largely on the nature of your language and paradigm.
I'd be surprised if you could get folks to agree on what bad code is, but there are Bob Martin's "code smells" that seem like a helpful start....
I would question opinions of this author after his latest comments
What has Bob Martin said that's been controversial?
Yeah I would like to know also
Oh Uncle Bob? I'd totally forgotten he'd caused some controversy.....
Yes Uncle Bob. I didn't mean you, sorry for confusion.
Haha - yeah - for just a second there you made me sweat 😅 wondering what my recent comments had been!! :-)
I guess yes, it really depends. I remember this time I was working on my project and my lead dev said that this:
was not good code, and this:
was better.
So first, I should say in my defense I come from another programming language than Python so this was not very intuitive for me (now I got used to it even if this is still weirdo).
So I guess everything is relative since we do not share the same standards, backgrounds, intentions, and objectives.
answer proposition
Only if we should give an absolute definition, I would say that a bad code is a code that does not cover the use cases. If we need an algorithm to do X,Y,Z in a context C, and it only does X,Y, or it does X,Y,Z in a context D, so it is a bad code for me.
Then, we could say what is a code that does X,Y,Z in a context C,D? Is this bad code because it does too much? I would have said no some months ago, but now that I have some issues with some codes that tried to anticipate too much but in a bad way, I would say yes.
It would be nice if we can specify what exactly code suppose to do, but we can do this only to some extent. To fully specify code we need to use some kind of formal specification and verify it with TLA+ or similar to make sure specification itself doesn't contradict. In practice only a small amount of code (very important code) goes through this process, the rest get only partial specification. The biggest question is how much is specified? Is it 30%, 50%, 80%? How we gonna know it without actually writing the whole specification and measure percentage?