
How to Write Unmaintainable Code (2017) - migueldemoura
https://github.com/Droogans/unmaintainable-code
======
Yokohiii
I actually like using short variable names. Using "i" as an index variable has
been widely accepted. It saves a lot of typing, the use case is clear and it
is usually tied the a block which is visually identifiable.

I carry over the same principles to functions/methods. Functions are usually
less than a screen which makes it rather easy to pick up the context and
understand the program flow and the use of variables. I use "list" if there is
there is a single list. The context usually defines what is in there. Maybe
the function name, the type declarations or the fact that we are in a part of
code handling lists of customers. How hard is it to guess what
countCustomers(list) or incrementCustomersScore(list, n) is doing? Writing
incrementCustomersScore(goodCustomerList, customerScoreDelta) is just
redundant. Variable names just need to be descriptive enough to define their
role within it's context. If the function is very small, the variable names
can be very short.

Local variables are the smallest named things in our systems, whith a very
small scope, there shouldn't be an excessive naming cult around it. Give
advice how to properly name projects, packages, namespaces and classes and I
start listening. We are really bad at this.

~~~
jdmichal
`i` vs `index` is whatever. `index` is better, but it's not like I'd bash
someone for using `i`.

Using `list` is just bad. Your list (probably) holds a set of things that has
a name. So name your list that. At the very least, name it after the type of
things it's holding. Types are only declared once, but variable names are
forever. Having to constantly look up the type of a variable because the
programmer was too lazy to name the list of things as `things` instead of
`list` is rather inconsiderate.

(Of course, there are times when you would use `list`. For instance, if you're
writing a list sorting function, and you actually have zero context more than
"yep, this thing is a list".)

~~~
seanmcdirmid
Index isn’t going to be consistent when you need a second iterator in a
generic algorithm; people just don’t like the sound of jndex. Use “i” and “j”
and “k”, or “idx” and “jdx” and “kdx” if you must, but please don’t use
“index1” and “index2” and “index3.”

As you say, list might be the best name for a variable if the use context is
generic. The same with iterators and such. But you really have to think ahead
to keep the names consistent, complicated names work against consistency.

~~~
jdmichal
Well, if you combine the two together...

    
    
        List<Foo> foos;
        for (fooIndex = 0; fooIndex < foos.length; ++fooIndex) {
            Foo foo = foos[fooIndex];
            List<Bar> bars = foo.bars;
            for (barIndex = 0; barIndex < bars.length; ++barIndex) {
                Bar bar = bars[barIndex];
            }
        }
    

It would be immediately, visibly obvious if you accidently use `fooIndex` in
the `bars` list. Good luck getting that with `i` and `j`.

That, of course, is assuming you even need the indexes. Otherwise you get
this:

    
    
        foreach (Foo foo in foos) {
            foreach (Bar bar in foo.bars) {
            }
        }

~~~
Jtsummers
You have more context (in that first example) and so the foo and bar indexes
make great sense.

i and j really make more sense (as i and j) when used in their more
mathematical connotation: indexes into a multidimensional array/object.

    
    
      for (i = 0; i < thing.length; i++) {
        for (j = 0; j < thing[i].length; j++) {
          thing[i][j]; // this is very close to the mathematical use of indexes
        }
      }
    

Makes perfect sense because i and j are being used to index into the same
thing.

i and j would be poor fits for your first example because they don't index
into the same thing anymore. You've introduced additional levels of
indirection, to rewrite your first example using i and j (and illustrate why
this is an awkward construct):

    
    
      for (i = 0; i < foos.length; i++) {
        for(j = 0; j < foos[i].bars.length; j++) {
          foos[i].bars[j];
        }
      }
    

It's not _wrong_ , but it is awkward and unclear as the code grows larger it
becomes easier to misuse i, j, and subsequent index variables.

=====

And of course, you're absolutely correct: foreach or equivalent is a better
construct. It states the intent of the code, rather than the how of the code.
This keeps your code closer to the semantics of your problem specification.

~~~
domenukk
however I would skip j as it is too similar to i. Use k instead.

------
ppeetteerr
Any time I read C/C++ code, I am under the impression it was written to be
illegible.

I realize that with time, functions like `malloc` become second nature, but
why not call it `allocate_memory`? (bash suffers from this too) It's even
worse when reading the source code of old video games due to the abstract
nature of the operations being performed on virtual representations of visual
elements.

The argument of time constraints when authoring doesn't hold much value. Java
is verbose AF but it's also one of the most used languages. Second, most code
is read, not written and should be written to be read by others, not just the
author.

There may be a reason to be terse due to time constraints and lack of
IDEs/autocomplete or memory constraints or w/e, but the need to shorten
variables names and functions today only serves the whims of the author, not
the 10+ future readers. _tinyrant_ :D

~~~
jghn
There _was_ a time where visual and actual compactness was important. So for
instance things like `malloc` date to that era. I'd argue that changing it to
`allocate_memory` now would be even more confusing than leaving it as `malloc`

~~~
ppeetteerr
I fully agree. This reminds me of how some text books will teach people to
write `a = 10` rather than `age = 10` for the sake of brevity. From that
moment on, it becomes a habit to write code in a terse manner. It took me a
few years and some good IDEs to no longer be afraid of names like
`ageOfUser`/`age_of_user`.

~~~
Sohcahtoa82
> `ageOfUser`/`age_of_user`.

I'd be going with `userAge` or `user_age` either way. :-P

~~~
ppeetteerr
We can't be friends :P

------
wolfgang42
_> The design doc should break the algorithm down into a hierarchy of
structured steps, described in a hierarchy of auto-numbered individual
paragraphs in the document._

 _> then... (and this is the kicker) when you write the code, for each of
these paragraphs you write a corresponding global function named:_

 _> Act1_2_4_6_3_13()_

 _> Do not document these functions. After all, that's what the design
document is for!_

Ideally, your company will also have several file shares into which old and
unidentifiable documents are filed, in nested layers of folders named things
like "Old documents", "John's Code", "Please Clean Up", and "Maybe Delete".
However, for maximum effectiveness do not file your design documents here!
Instead, put various old drafts (not identified as such, of course) in a
folder on the server where your code _used_ to run, somewhere like
C:\backups\aurdbcl1\C\Documents and Settings\users\jdoe\Desktop\ (where
aurdbcl1 is the name of the server where your program ran 20 years ago). This
will ensure that they will spend as long of a time as possible hunting for
something that could be useful. If possible, also ensure that there are some
multi-Gigabyte zip files scattered about which have to be unpacked just in
case there's something useful inside.

A related technique for compiled languages is to arrange for various copies of
the source code to be copied into similarly diverse locations. Do not use
version control under any circumstances; if you must, check in at most once a
month with the comment "changed code". This works best for a program which is
maintained very rarely. Anyone attempting to fix it will first have to
identify which copy of the source code is the right one. Make sure you also
have some copies that never made it to production, where you started changing
things and never finished. If possible, the production version should also be
subtly different from _all_ copies of the source code that can be found.

(The above is, unfortunately, from experience. I have many other rants which
similarly belong in this document, particularly around exception handling and
copy-pating, but I feel that this comment is becoming too long already.)

~~~
jackhack
An approach from one of my early employment experiences (1980s):

1\. Write a CAD system. User-facing code in BASIC. Rendering engine written in
assembly.

2\. Run the interpreted BASIC code through an optimizer, which condensed all
variable and function names to be as short as possible (one or two characters)
and moved frequently-used routines to the top of the module before compiling
it all into one executable chunk (no more interpreter). This optimized code is
almost unreadable but executes a lot faster (25%-50%) than the human-readable
interpreted code. Hurray!

3\. Lose the original source code.

Build machine's hard drive died. The backups weren't. No version control --
only occasional snapshots. Source code that was on various floppy disks lying
around the office was incomplete and badly outdated (like the "Old
Documents/John's Code example, above).

4\. Team panics and spends a month trying to piece "Humpty Dumpty" (the
software) back together again. No luck.

5\. Spend the next year trying to reconstruct function and variable names from
"AA423()" and "aa_237" to such gems as "customerListIThink",
"doesSomethingToInventory()", "NoIdea()", "BreaksWhenIChangeIt()" while
struggling to add new features at 1/10th the rate before the loss.

6\. Try to rewrite the whole thing in C.

7\. Go out of business.

True story.

------
maerF0x0
Disclaimer: This comment is mostly in jest.

For a second there I thought i was reading about golang[1].

* Single letter var names[2] / [3]

* Underscores [4] / [5]

* extended ascii code [6] / [7]

[1][https://golang.org/doc/effective_go.html](https://golang.org/doc/effective_go.html)

[2] [https://github.com/Droogans/unmaintainable-code#single-
lette...](https://github.com/Droogans/unmaintainable-code#single-letter-
variable-names) [3]
[https://github.com/golang/go/wiki/CodeReviewComments#variabl...](https://github.com/golang/go/wiki/CodeReviewComments#variable-
names)

[4] [https://github.com/Droogans/unmaintainable-
code#underscore-a...](https://github.com/Droogans/unmaintainable-
code#underscore-a-friend-indeed)

[5]
[https://golang.org/doc/effective_go.html#blank](https://golang.org/doc/effective_go.html#blank)

[6] [https://github.com/Droogans/unmaintainable-code#extended-
asc...](https://github.com/Droogans/unmaintainable-code#extended-ascii)

[7]
[https://golang.org/ref/spec#Source_code_representation](https://golang.org/ref/spec#Source_code_representation)

~~~
marcosdumay
> Single letter var names

They are also a Haskellers favorite.

There's a non-sarcastic paper running on the internet named something like
"descriptive variable names considered harmful". Most of the community agrees
with it, including me.

~~~
therealdrag0
Why are they harmful?

------
newsbinator
> Consider this real world example: a_crszkvc30LastNameCol.

> It took a team of maintenance engineers nearly 3 days to figure out that
> this whopper variable name described a const, reference, function argument
> that was holding information from a database column of type Varchar[30]
> named "LastName" which was part of the table's primary key.

~~~
vntok
That's insane, what could those 3 engineers possibly be doing for 3 days?

\- const, reference and function argument should be pretty obvious from the
code context

\- LastNameCol seems like self-describing... of course you would have to know
that you're debugging an application that talks to databases, but eh

~~~
marcinzm
Most likely tracking down what originally populated the variable and how it's
used. I'm assuming the code base was large and spaghetti like.

I'd say it's somewhat akin to proving a negative. Sure you get that it's a
const, reference and function argument which likely refers to the Last Name
Column. However is that all it is? Or is there more meaning in the name?
Meaning that could be crucial to understanding how the application functions?
Does one of the characters mean function reference or does it refer to
something else? Apparently not in this case but how can you know without
investigating?

~~~
wild_preference
Spending time to understand the author’s intent of some code is one of the
hardest parts of reading code.

It’s like when you find a nil-guard in a function. You can’t truly refactor it
until you know whether it was added defensively just-in-case or whether nils
can still exist in the system at the function’s callsite, calling for further
upstream examination.

There’s a certain hell in trying to follow a code base where every function is
infected with ‘if (!arg) return’.

~~~
AgentME
After dealing with code absolutely plagued with that pattern, languages with
non-nullable types are amazing (Flow, Typescript in strict mode, Kotlin, Rust,
...) and I don't think I'm ever going to voluntarily switch away from them
now.

------
sseth
I had a colleague who used to use variable names from his local language in
India (we were working in Europe at the time). So hwndParent would become
hwndBaap. This combines both the hungarian and the local language strategies
for job security.

Fortunately, he stopped programming and became very successful in agriculture.
Good outcome for both fields.

~~~
magicnubs
> Good outcome for both fields.

Well that is what agriculture is all about.

------
nathell
This is much older than 2017; the version at
[http://mindprod.com/jgloss/unmain.html](http://mindprod.com/jgloss/unmain.html)
dates back to 2000.

------
jaclaz
As a side note, the "opening" quote attributed to Napoleon, seemingly isn't:

[https://quoteinvestigator.com/2016/12/30/not-
malice/](https://quoteinvestigator.com/2016/12/30/not-malice/)

I can offer as corollary to the article a couple of unmaintainable simple
batches:

[http://reboot.pro/topic/2986-yacbfc-dec2hexcmd-and-
hex2deccm...](http://reboot.pro/topic/2986-yacbfc-dec2hexcmd-and-
hex2deccmd/?p=204425)

~~~
baud147258
> Quidquid latine dictum sit, altum sonatur. - Whatever is said in Latin
> sounds profound.

This one is good and there's no attribution problem.

------
bausshf
I have an addition to writing unmaintainable code.

Only have one struct with a member of every type. That one struct will be the
type of every variable you have.

If the language you use support implicit operator overload abuse them to make
sure all types can be implicitly converted to each other.

Ex.

struct Variable { byte a; short c; int d; long e;

    
    
        ...

}

This will make it impossible to know what type a variable is until you find
its assignment, which of course isn't on the same line as the declaration and
even better reuse the same variable for multiple values.

~~~
evozer
If you want to be more efficient, you can also use a union for this.

typedef union { int i; float f; double d; long l; char c; void *p; ... } var;

Now you might also get some nice float-interpreted-as-int bugs if you forget
the type!

You can also kind of pretend that you have C#-style type inference:

var x = { .i = 10 }; var y = { .f = 2.0f };

~~~
bausshf
But you don't want to be efficient lmfao

------
joeblau
I had a funny now/frustrating then story where I worked with his guy who named
five variables in a class a, aa, aaa, aaaa, aaaaa. I was trying to refactor
his code and I had no idea what anything did. The company is out of business
now, but it was definitely unmaintainable.

------
alexeiz
Recently I came across some code that checks quite a few boxes in this guide.
Check it out:
[https://github.com/KxSystems/kdb/blob/master/c/c/k.h](https://github.com/KxSystems/kdb/blob/master/c/c/k.h)
[https://github.com/KxSystems/kdb/blob/master/c/c/odbc.c](https://github.com/KxSystems/kdb/blob/master/c/c/odbc.c)

~~~
notamy
It's written like it's APL (I think? iirc k is an APL-style language), so it
actually makes some sense. To the way that the authors actually write code, I
think it's perfectly legible, just not to outsiders.

~~~
alexeiz
Isn't making code ineligible to outsiders an essential requirement for job
security? And how much sense does it make to you? What can you tell about this
code except for "it's written like APL?" Can you tell what it does? How it
does that? What all those one letter functions/macros mean? No, you can't tell
shit.

------
ajss
Along a similar line, I love Stuart Halloway's talk on Narcissistic Design -
[https://www.youtube.com/watch?v=LEZv-
kQUSi4](https://www.youtube.com/watch?v=LEZv-kQUSi4)

Prefer APIs over data.

Start with DSLs.

Always connect (and never enqueue).

Create abstractions for information.

Use static typing across subsystem boundaries.

Put language semantics on the wire.

Write lots of unit tests.

Leverage context.

Update information in place.

------
paulddraper
> a naming convention from the world of C++ is the use of m_ in front of
> members. This is supposed to help you tell them apart from methods, so long
> as you forget that "method" also starts with the letter "m".

C++ has member variables (which this refers to) and member functions.

"Method" is not part of the vernacular.

------
phakding
What incenses me is this recent notion that because programmers fail to change
comment with the code change, they shouldn't even write comments. They should
instead write the self-documenting code.

This doesn't make sense on so many levels. Only a recluse sitting in some
dungeon who never dealt with people can come up with something so inane.

Edit:

I understand that that every developer should aspire to become someone who
writes code that reads like a children's book, and they should. However,
actively discouraging writing comments is so wrong on so many levels.

At the last place I worked, we used to have a small at-home coding test before
interview and none of the young developers who successfully completed the test
did any sort of code documentation or commenting. When I asked why, they would
tell me that their code is self-documenting, which was utter nonsense.

~~~
cessor
I found this technique to work quite well, but this idea does not mean imply
that one should simply "quit writing comments", but rather that comments can
most often be replaced with actual structures that improve the code (e.g.,
extracting long boolean expressions into a function with the same name as the
actual comment), but that also depends on the language and aptitude of the
developer.

Would you really argue in favor of something like this?

``` class Account { ... /// returns the accountId public int d_nr() { ... } }
```

``` class Account { ... /// returns the accountId public int getAccountId () {
... } } ```

The first comment is obsolete when using a proper method name, the second does
that and so the comment is redundant.

May I ask: What did you experience in the wild?

~~~
scarface74
Or even better don’t return an int return an “accountId” type.

~~~
jokerx
Please don't do this!

All you have accomplished really is to move the descriptive name from the
variable's name to the variable's type, and at what cost? You now have to
create a whole new datatype. The programmer must look up that datatype and see
oh, it's just an int. And now you need conversion routines or worse yet
casting to convert that type to a simple int for interop reasons (database,
UI).

Experience has shown that it is very productive to have a _small number of
generally useful datatypes_ which are augmented by custom datatypes.

Creating a new datatype for something as simple as an int or String defeats
that and makes it more cumbersome to work with. (It's especially unwarranted
for a variable that is an immutable variable serving as a simple id.)

~~~
scarface74
You haven’t just moved the descriptive name from the variable name to the
type.

If you are using a strongly typed language, you can just right click on the
accountId type and find everywhere in your codebase where the “accountId” is
being used.

The “accountId” is not “just an int”. An accountId has semantics that would be
different than an int. An accountId is not the same as a “customerId” that may
also be represented as an int. The accountId also has different uses than an
int. You’re not going to take the sum, average, etc of an accountId.

An accountId that happens to have a value of 1 is semantically not equivalent
of a customerId of 1. A method that expects a list of accountIds that are just
ints will just as happily take a list of customerIds.

But a method that takes as a parameter List<AccountId> will cause a compile
time error if you pass in a List<CustomerId>.

Why use a strongly typed language and then ruin one of the benefits of it if
you don’t use domain specific types?

~~~
cessor
I agree with @scarface74 and would go even further in that I would probably
create a custom type for List<AccountId> to convey the purpose of what that
thing is now.

And as for the "type shyness":

> Creating a new datatype for something as simple as an int or String defeats
> that and makes it more cumbersome to work with.

It is never "just an int". Soon you will ask questions about the int, and in a
sufficiently large application you will forget the answers to the quesions
easily, and scatter the same question (i.e., the same boolean logic) all over
the place. Consider an application where you need to filter something by year.
A year, you know? As in 1974, 2018, etc. An int is bad, because an int could
be -5, which does not make sense. Ok, a uint then? Still bad, because then
there is a year 0 and - if your application deals with birthdays of real
people, 1800 would be an invalid birthday. The semantics (or pragmatics,
linguistically speaking) emerge from how you interpret the integer, and this
interpretation can happily live in that one file with that one class that
encapsulates "just" that integer.

The AccountId probably shouldn't be < 0, and a specific type could be the one
place where you make sure that this is always the case.

What if you start with a 32bit integer and suddenly you realize that your
weird Internet-Of-Things-Sensor reading database has grown and the 32bit
integer is getting too small? You could just use 64bits. With "just an int",
you now get to change every single function that expects an int for the
purpose of a SensorReadingId (or an account id or whatever) and change it to
size_t, uint, int64 or whatever. OR, you just tell the object that its
internal representation uses 64bits now, because the AccountId class is the
one single place that deals with account ids. The type provides a consistent
interface that allows you to infer the semantics of its use. An int doesn't do
that.

This idea predates java by some ~20 years [1]. An int is not an account id. An
int is not a year. An email is not a string. The result of working like that
is considered a code smell [2].

Still, coming back to the example I made: It was primarily about commenting. I
was taught to always comment, and StyleCop enforced comments on each and every
field of a class, leading to noisy, superfluous comments.

    
    
        /// Gets or Sets the Name
        string Name { get; set; }
    

does not add anything.

As for returning an AccountID: I'd like to point out that the Account is a
strong and independent object, who can make his own decisions and does not
need to return anything. Returning its id like that is actually breaking
encapsulation. Still if you do it, it probably shouldn't be an integer.

Why are people scared of creating types and objects?

[1]
[https://link.springer.com/chapter/10.1007%2F978-1-4612-6315-...](https://link.springer.com/chapter/10.1007%2F978-1-4612-6315-9_22)

[2] [https://sourcemaking.com/refactoring/smells/primitive-
obsess...](https://sourcemaking.com/refactoring/smells/primitive-obsession)

~~~
jokerx
Your example of needing to define a type because "int" is not good enough is
very C/C++ centric.

Most languages don't have the plethora of integer types that C has. Java, for
example, has just has 2 in general use: int (signed 32 bit) and long (signed
64 bit). (Nobody considers byte a general integer type.)

In C/C++, you have to define so many things about the types you use because so
much is "implementation dependent." So for C/C++, you may be correct. Most
other languages define their types more stringently and include a smaller
number of general purpose types.

~~~
scarface74
C# has nine integral types.

[https://docs.microsoft.com/en-us/dotnet/csharp/language-
refe...](https://docs.microsoft.com/en-us/dotnet/csharp/language-
reference/keywords/integral-types-table)

But even then, a year is an int, but it would have certain semantics you would
want to enforce outside of integers.

------
pure-awesome
> Since global variables are "evil", define a structure to hold all the things
> you'd put in globals. Call it something clever like EverythingYoullEverNeed.
> Make all functions take a pointer to this structure (call it handle to
> confuse things more). This gives the impression that you're not using global
> variables, you're accessing everything through a "handle". Then declare one
> statically so that all the code is using the same copy anyway.

I see this in practice WAY too often... Heck, I've been somewhat guilty of it
myself before.

(Bonus points if it's in a functional language :P )

~~~
kevin_thibedeau
And it's perfectly valid on constrained systems where you don't have or want
to make heavy use of malloc() and don't have namespaces. Provided the structs
stay reasonably focused on one domain.

~~~
pure-awesome
Emphasis on the "reasonably focused on one domain" part - it's when you're
passing through your entire program state in one gigantic state object that
things get messy.

Also, I've been led to believe that design of constrained / embedded systems
follow different rules. Your code can be unreadably complex if you _have_ to
squeeze out that extra performance (however, even then, it should probably be
well-commented or well-documented), and generally (though not alway) such
programs will be smaller and made by smaller teams.

It's when these kind of practices are applied in enterprise software with
large number of programmers, where maintainability is more important than
performance, that this is an issue.

------
zbentley
> In C, functions are supposed to be idempotent, (without side effects).

What is meant by that statement? Is "idempotent" a mistype/mistakenly selected
word? If the author meant "pure" instead, should I file a PR, or consider this
some sort of meta-meta-obfuscation? If the author meant "pure", is that
actually true of C specifically, or just generally good programming advice
(localize side effects to known locations, the fewer the better, don't
sprinkle them all over and document where they occur)?

~~~
badlukk
C functions shouldn't change behavior based on state, they do the same thing
every time. Instead of changing a particular global variable, any variable of
that type should be passed in and changed, then returned. It's good
programming advice for functional languages. In OO it makes sense to make
state changes in object methods, but not _usually_ the best functional
approach.

------
retSava
Well, since the repo more or less took the contents verbatim from the original
author (unless they are the same), and here presents it _more_ clearly than
the original, I'd say the repo owner failed.

At the very least it should be presented in a more unmaintainable way.

Edit, apparently repo owner already checked with author:
[https://github.com/Droogans/unmaintainable-
code/issues/3](https://github.com/Droogans/unmaintainable-code/issues/3) :+1:

~~~
detaro
Interesting, I find the one long document less clear then the original that's
categorized in subpages.

------
coolaliasbro
As a creative process, and in the interest of compassion, I tend to name
everything as humanly readable as possible, and provide voluminous
documentation in production systems. Even quick-and-dirty things tend to get
moved to production if they work, so I increasingly apply the same approach to
them, as the "this will be tossed after x" sentiment has bitten me on the ass
more than once.

~~~
cessor
Could you elaborate what criteria you apply to decide whether something is "as
humanly readable as possible"? I am asking out of genuine interest, I am
researching readability and I am interested in how you make decisions and what
criteria you apply. What means "readable" to you?

------
schindlabua
Ok so sometimes I have no concept of what american and british variants of a
word are because I'm from mainland europe and so I will just use whatever.
Sorry maintainers!

Grey/Gray gets me every time.

~~~
pluto9
> Grey/Gray gets me every time.

GrEy for England, grAy for America.

~~~
schindlabua
Oh! That's a nice way to memorize it, thanks!

------
Sohcahtoa82
I'd add something about breaking common conventions like moving the verb to
the end of the function name. For example, I'd change GetPageFromServer() to
PageFromServerGet()

Also, use synonyms for common function verbs. Like Grab instead of Get.
GrabPageFromServer()

In a code base I dealt with, a developer did exactly those. Most "get"
functions had "get" at the end of the function name. Some functions had it at
the beginning, but replaced with "grab".

Also, he misspelled a class name and just went with it.

------
bausshf
"Hungarian Notation is the tactical nuclear weapon of source code obfuscation
techniques; use it!" \- I'm laughing so hard. This whole article is genius.

~~~
bausshf
Also "Be polite, Never Assert Avoid the assert() mechanism, because it could
turn a three-day debug fest into a ten minute one."

------
rajadigopula
A much novel way - use functional programming and create higher order
functions and purely mathematical combinatoric functions and compose them in a
complex way. A normal day developer must go to college again to even getting
closer to understand it. This way the code is highly functional and there
won't be a compromise in the quality of the output!

~~~
FrozenVoid
Thats what i actually use with C macros, except its intentional and saves lots
of typing: however you must know some macro trickery to understand how it even
works.

------
ape4
I inherited some code with m_ prefixes on parameters to a function. eg
theFunction(int m_param1) That should be a lint error.

------
nerdponx
How is this any "easier to share"?

~~~
davemp
This version is certainly much more readable for me than the older intrusive
ad ridden, click farming version.

------
jjuhl
There are 2 hard problems in computer science: cache invalidation, naming
things, and off-by-1 errors.

------
gerdesj
Don't bother with all that documentation, get straight into the Stackoverflow
example:

[https://github.com/Droogans/unmaintainable-code#a-real-
life-...](https://github.com/Droogans/unmaintainable-code#a-real-life-example)

------
roland35
For embedded C work I do like to mark global variables with a Hungarian g_,
all other prefixes are generally handled pretty well by the IDE's type
hinting. Other than that I agree Hungarian can go!

------
a_imho
Surprisingly light on multithreading and version control best practices.

------
emodendroket
The comment section is particularly trenchant because I recently worked on a
project that had hundreds of instances of the comment "// do this here"

------
S-E-P
My personal trick: Write a basic (not turing complete) brainf __k compiler
into your application and feed your business logic through that.

~~~
bausshf
The brainfk compiler should have reversed symbols. Ex. > will decrement the
pointer, < will increment the pointer, + will subtract, - will add, . will
read, , will read, ] start loop, [ end loop

~~~
S-E-P
you are an absolute madman you know that haha!

~~~
bausshf
I'm awawre of that!

Also I noticed a mistake in my comment.

I wrote ", should read" it should of course have been ", should write"

------
mirekrusin
One of the longest jokes I've seen.

------
tegansnyder
Now whenever someone criticizes my old code I can point them to this and say
it could be worse.

------
jgh
hahah so glad Hungarian notation was included.

------
Mc_Big_G
Just use perl.

~~~
lizmat
Do you have any data to back up that claim? Or are you just propagating
prejudice?

~~~
Mc_Big_G
It was a joke, take it easy. With that said, perl has a multitude of ways to
shoot yourself in the foot and future maintainers in the face. Notably, the
obscure tricks perl allows you to write that are difficult to read in the
future but seem clever when you write them. I've written enough perl to know
they exist but thankfully forgotten all of them so I can't give a good
example. I just remember something about $_ being interesting at times.

~~~
vgy7ujm
Then you don’t know enough about it.. now you are the joke.

------
cessor
Many people are pointing out that short identifier names are ok, and that i is
perfectly fine as an identifier name. It likely is, and I believe the rule to
be true that short identifier names are ok for short scope / context. However,
there are several issues:

i for an index is ok, but this is a red herring: You only ever need an i for
imperative iteration and in a sufficiently high level language you are better
of with selection and projection, (iteration for that matter), where you just
foreach over each element and don't actually need to ask for things by index.
Sure, y'all be hacking C, nothing wrong with that, it depends on what you str
doing, but for comprehension, the mere existence of i is a red flag, because
most of the time you want something to happen to a collection if things and
foreach is perfect for that (or map, fold, filter, pick your poison).

Still, a better example than `i` for short identifier names would be x,y,z, or
r,g,b These are so common and conventional that I would expect them to have
semantics of their own, still they could be chunked to types such as
Coordniate, Location, or Point, or Paint, or Color, respectively. But comming
up for better names than x,y,z is really difficult, will bloat your code and
make it hard to understand what is going on.

I am pointing this all out, because many of you seem to favor such very short
identifier names - and I am with you: sometimes they make sense, see above -
but empirical evidence suggests that very short identifier names, and single-
letter identifier names in particular significantly worsen comprehension of
code. The same is true for abbreviations (depending on how strongly you
abbreviate).

[1]
[https://ieeexplore.ieee.org/document/7884623/](https://ieeexplore.ieee.org/document/7884623/)
(disclosure: author)

[2]
[https://doi.org/10.1007/s11334-007-0031-2](https://doi.org/10.1007/s11334-007-0031-2)

[3]
[http://compscinet.dcs.kcl.ac.uk/JP/jp040302.abs.html](http://compscinet.dcs.kcl.ac.uk/JP/jp040302.abs.html)

[4]
[https://dl.acm.org/citation.cfm?doid=382080.382628](https://dl.acm.org/citation.cfm?doid=382080.382628)

[5]
[https://link.springer.com/article/10.1007%2Fs10664-018-9621-...](https://link.springer.com/article/10.1007%2Fs10664-018-9621-x)

Preprint for [1] here: [https://brains-on-code.github.io/shorter-identifier-
names.pd...](https://brains-on-code.github.io/shorter-identifier-names.pdf)

[5] is the extended Version of [1] including discussion of how attention is
shifted during the experiment. It turns out that, when code uses words as
identifier names people don't need to read the comments as much.

------
tribesman
"Hungarian Notation is the tactical flesh light of source code obfuscation
offering max pleasure; use it!"

------
hashrate
This is suppose to be funny , unfortunately this is the sad reality of what
you'll find in 90% of Enterprise / Startups environment as well as THE
majority of open source repositories of popular open source projects.

I've noticed this especially true for JavaScript and Go.

In JavaScript , because the language is still evolving and there is no real
standard about how to architect code with this language unless you are using a
entire "platform" like Angular / Vue / React witch will highly influence your
coding style.

In Go because Go developers are performances obsessed , coming from C/C++
background and do believe that naming their variable with one letter will save
1GB of memory allocation , 1000 CPU Cycles and make their code "Clear and
Concise"

Ultimately , because there is very little standard in this industry in terms
of code governance and a large percentage of projects are outsourced to other
companies , we end up with what is described in this repository.

~~~
dawkins
In Go single letter variables are used when they are short lived (3 or 4
lines) and in this cases I find it way more readable than long names.

~~~
hhmc
It's also perfectly acceptable (and preferred) if the code maps cleanly onto
some existing mathematical terminology. 'v' is more readable than 'velocity'
in the correct context.

~~~
kstenerud
... until it isn't.

The problem is that you get too close to the code you write, and make
assumptions about its obviousness that simply aren't true. Far better to be
explicit at the cost of a few extra keystrokes.

