Code style

This is an idea I noticed in a response at a tweet from @garybernhardt.

Indenting with tabs, spaces, two or four spaces, where do you place the opening/closing braces, how do you break long lines, whether you place spaces or not around operators, and in which contexts, how many white lines you place between class declarations, all of those things, should be irrelevant. All of those are just visual aids, which:

  • Should not show up in your diffs, when you are reviewing a pull request from somebody.
  • They should be ignored by your version control system; any commit that merely changes whitespace/formatting is a non-change, since nothing changes functionally.
  • You should be able to tell your IDE how you want to look at the code, what code style you want to use. Yet that should not provoke/show up as a change (a commit) in your VCS.

Files

Your IDE should take care of creating/naming files. It should also take care of where to put the things you create as a programmer: globals, functions, classes, modules, etc.

Ideally, your only responsibility should be telling your IDE what's your module structure. It should deal with the rest.

Also, your VCS should stop caring about files. We don't need to know that 'a file was renamed', we also don't need to know that 'a function was moved from this file to that file', if it didn't change.

But, 'a function was moved from this module to this other module' is something I do care about. As I also care about 'all the changes made to this single function'. Perhaps the VCS should version not files, but a standarised, machine friendly, machine-diffable version of the code we write. The IDE, or your VCS should know how to generate those for you, automatically. Possibly the IDE would be a better fit, and the VCS should just be considered a dumb storage, versioning a standarized representation of the code generated by the IDE.

Code analysis

Before, and mostly because of this article from Joel Spolsky, and my own experience as a reviewer, I tried to avoid exceptions, and preferred error codes, because error codes:

  • Are visible to the reader.
  • Their handling (or lack of thereof) is visible to the reader.

Because of that, you don't have to zip around your whole codebase when reading some piece of code in order to check whether a method throws an exception or not, and the opposite situation, to check all of the places where an exception is handled, and figure out which one of those is the one calling the function you are reading right now.

Writing exception-based code does give you clean code, with centralized/localized handling of errors (when used properly). You basically end up with the code that handles the happy path, in a single place, and code for handling the possible errors, somewhere else, wherever the exceptions that might be raised are handled. But, that code is awfully hard to read with our current tools, because all of that error handling is littered over so many different files/places in your project, many times even with no obvious connection of how to get it, because many "final" exception handlers (like, for example, DRF's custom exception handlers) are defined dynamically, just by putting a class name in a string in a settings file somewhere... you will not find them by just following the call chain, when reading the code.

But, that is a limitation from our current development tools, nothing more. All in all, I think exception-based code is better than error-status-based code, fundamentally because a dead program is better than a limping program, and exceptions guarantee you that if you did not handle them, your program crashes, (and you get to see the stacktrace of when it crashed) instead of carrying on with God-knows-what you get after something fails and somebody didn't handle that error code properly.

As for reading exception-based code, I wish I was able to ask to my IDE to:

  • Show me what non-runtime exceptions a given function raises, which is of course the aggregate of whatever exceptions it, or its callees, raise. (This is one of the things that I think Java got right, the compiler tells you that, and the language has the concept of runtime errors and business-logic-related exceptions, ...)
  • Show me the call tree of a given function: who calls it, who calls its caller(s), and so on and so forth until hitting either main or whatever is the boundary for the framework I'm using: e.g., a Rails controller, a Django view, etc.
  • Show me all of the places where a given exception (or its ancestors) is handled. And show that somehow in the call tree.

Also related, and occasionally useful, is being able to see the (for lack of a better name) reverse call tree of a function: which functions it calls, which functions those functions call, and so on and so forth. Of course skipping (optionally) the core language/framework stuff.

When analyzing a function, it would also be nice to be able to ask the IDE to show you the dependencies of a variable: where has it been changed in the current function so far (something function-aware, not just a find-in-file), and which other variables/expressions are used to calculate this variable.

Testing

Somewhat related to the code analysis section; I should be able to modify something in the codebase, and have my IDE to run only the affected tests, and no others. The IDE should figure out where what I modified is tested, maybe from coverage information from previous test runs/static analysis/whatever.