DEV Community

Cover image for What is bad code?
stereobooster
stereobooster

Posted on • Edited on

What is bad code?

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

Latest comments (48)

 
stereobooster profile image
stereobooster

I'm afraid you lost me there

Collapse
 
stereobooster profile image
stereobooster

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?

Collapse
 
sanidz profile image
sanidz

By definition if it smells too bad than it is bad code... but not all smely code is bad.

Bad code is good implementation of antipattern/s.

Collapse
 
stereobooster profile image
stereobooster

I'm afraid I'm not following you

Collapse
 
sanidz profile image
sanidz

Sorry I just tried to oversimplify..
Code smell is term used to describe some possible problem in code regarding bad code, something "fishy" so to say, it can be serious or not, however it just feels wrong and its subjective.(naming, readability, complexity...see link below)
Little code smell can be tolerated and is sometimes justified, thats why bad code is code with too much smell.

One of the main reason for getting code smells from the bad code in the first place is lack of bussiness understanding + lack of technical knowledge.
Main reason for not fixing it is lack of confidence and fear to modify and refactor bad code.
List of code smells is long and depends from language and usually can be detected by static code analysis tools.

About antipatterns
Smelly code at the begining is allways acting alone, but when evolved will become serious bad code and will get its ultimate monster form as multiple antipatterns. So any "good implementation of antipattern" (is oxymoron), will be badcode as well.

Good code = badcode without smell

I find this classification really good
sourcemaking.com/refactoring/smells

At the end we are subjective and generalise, thats why we just say its bad code... :)

Collapse
 
kbariotis profile image
Kostas Bariotis

By the way, related to this, here's a recent article from Martin Fowler:

"Is High Quality Software Worth the Cost?" martinfowler.com/articles/is-quali...

Collapse
 
kbariotis profile image
Kostas Bariotis

Short answer: i2.wp.com/commadot.com/wp-content/...

First of all, I don't think that having bad code is a bad thing. It's called technical debt and is totally acceptable. Bad code can become good code and vice versa.

As for the definition of bad code, at the end of the day, a piece of software tries to solve a problem. As long as that problem is being solved, we are talking about good code. When it fails to solve this problem or possible new problems that will arrive as time passes, then we start talking about bad code and the question becomes: What level of bad is this code at?

Then there is only one parameter to consider. How easy it is to extend/maintain/change it. That of course, is a whole chapter by it-self:

  • is it really reflective of the actual real-world problem that it tries to solve?
  • are there good tests that you can rely on?
  • is it readable in a way that you can understand what you need to do?
  • is there documentation that you can refer to when something doesn't really make sense?

What do you think?

Collapse
 
stereobooster profile image
stereobooster

First of all, I don't think that having bad code is a bad thing. It's called technical debt and is totally acceptable. Bad code can become good code and vice versa.

👍

As for the definition of bad code, at the end of the day, a piece of software tries to solve a problem. As long as that problem is being solved, we are talking about good code.

I'm not sure if everybody would agree to call it good code, but I feel wrong calling it bad. I feel that this dichotomy of good/bad is wrong by itself. Good/bad is broad category, with ambiguous definition. For example, it is fair to say this code is hard to read or this code hard to modify or this code is undocumented etc. but if it works and helps people I wouldn't call it bad...

Collapse
 
codemouse92 profile image
Jason C. McDonald • Edited

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.

Collapse
 
stereobooster profile image
stereobooster • Edited

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.

However, if that's not the lens you're looking through, then (based on the suspicion that NP ≠ PSPACE) there's a difference between NP-completeness and PSPACE-completeness. If a problem is NP-complete, then even if you can't solve the problem efficiently, you can still check "yes" answers efficiently. On the other hand, if NP ≠ PSPACE and you have an instance of a PSPACE-complete problem you're convinced has a "yes" answer, there might not be any efficient way to convince someone else of this.

-- What is practical difference between NP and 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.

Collapse
 
codemouse92 profile image
Jason C. McDonald • Edited

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.

Thread Thread
 
stereobooster profile image
stereobooster

For anybody who reads this conversation and not sure what is NP-hard vs NP-complete:

This means that NP-hard problems might be in NP, or in a much higher complexity class, or they might not even be decidable problems. That's why people often say something like "NP-hard means at least as hard as NP" when trying to explain this stuff informally.

The halting problem is a good example of an NP-hard problem that's clearly not in NP

-- Trying to understand P vs NP vs NP Complete vs NP Hard

Thread Thread
 
stereobooster profile image
stereobooster • Edited

In other words, a chessmaster could easily explain whether a move is "best" in the context of endgame.

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...

Thread Thread
 
codemouse92 profile image
Jason C. McDonald • Edited

Well, I don't want to lose context. I was referring to what you said in the article.

...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).

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.

Thread Thread
 
stereobooster profile image
stereobooster • Edited

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:

  • Me: Post a link to the video which says that chess is outside of NP-complete field
  • You: Apparently chess is not NP-complete. Here is a link.
  • Me: Yes. Chess is not NP-complete, because... Your link mentions PSPACE-complete, the difference between PSPACE and NP is...
  • You: ...But this all depends, because for endgames situation is different...
  • Me: Yes, but we are talking about classes of complexity so we should compare worst cases ¯\_(ツ)_/¯

Where this going?

Thread Thread
 
codemouse92 profile image
Jason C. McDonald

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.

Thread Thread
 
stereobooster profile image
stereobooster

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...

Thread Thread
 
codemouse92 profile image
Jason C. McDonald • Edited

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.

Thread Thread
 
stereobooster profile image
stereobooster • Edited

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
Thread Thread
 
codemouse92 profile image
Jason C. McDonald • Edited

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. :)

Collapse
 
jacoby profile image
Dave Jacoby

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.

Collapse
 
codemouse92 profile image
Jason C. McDonald • Edited

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, and xztoab 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.

Collapse
 
anwar_nairi profile image
Anwar • Edited

I guess yes, it really depends. I remember this time I was working on my project and my lead dev said that this:

if type(users) is list:
  for user in users:
    ...

was not good code, and this:

if users:
  for user in users:
    ...

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.

Collapse
 
clavinjune profile image
Clavin June • Edited

it has countless wtfs per minute on code review

Collapse
 
stereobooster profile image
stereobooster

Vote for readability (lack of it to be precise), right?