Crappy Code
Tue, Feb 19, 2019I’ve been working with a lot of brand new developers at work recently. It’s really fun being able to magically solve problems for them that I remember being frustrated by not so long ago. I’m trying to strike a balance between giving them useful mental models and overloading them with detail. In the end, I’ve leaned most heavily towards encouraging an experimental model.
How does this tie in to crappy code?
Well, frequently you want to write a feature. A lot of that code will be boilerplate. Stuff like creating a database connection, writing stuff to a file, or validating input are all pretty repetitive tasks for most developers. But for most new developers, they’re still learning how to mentally segment all of the different moving parts of a piece of code.
To encourage that separation, I like to encourage “crappy code”. What do I mean? Good code style asks you to have nice, testable, well divided functions. That can be overwhelming when you’re trying to visualize how all sorts of moving parts fit together. Instead, you can write out the results of the moving parts. Most of the time this is hardcoding things that won’t be hardcoded in the final version. Then, when you’ve figured out the process, you can refactor.
For example, let’s say I’m writing a login function. I’ll receive an email & password from the user. I want to check that the password matches the hash that corresponds with the email we have for the user. And then I want to set up a session for the user.
A brand new developer can read that set of requirements and come up with an infinite list of questions. Questions are good! But they do stop you from getting any work done, especially if nobody can answer them immediately.
Let’s say that I have no idea how the function is going to get the parameters it needs. Temporary solution: Hard code them.
How do I connect to the database to get the hash? Who cares. Hard code the hash.
How do we store the session data? Again, not important right now.
So with those questions unanswered, I might write code like this:
import bcrypt
import secrets
def login():
email = "[email protected]"
hash = b"$2b$12$qCsHsvMWciYD2oT/NRGd9eHTZ.ziXlghH/iE0STGTTFy9l/WUhAPy" # bcrypt hash of "fake"
pw = b"fake"
if not bcrypt.checkpw(pw, hash):
raise Exception("You Shall Not Pass")
session_id = secrets.token_urlsafe()
session = {
'user_id': email,
'other_stuff': 'Not important yet'
}
# store session later.
return session_id
So now you’ve written that function. Is it crappy? Yes. You’ve hardcoded the username & password. You’ve hardcoded the session info. You’re actually not storing the session. But, you can run this code pretty easily. And runnable code is great, because if you can run it, you can use a debugger to figure out how stuff works.
From here, you are able to refactor & improve it incrementally. You might create a function that connects to the database & returns information about the user. You might create a function to handle storing the session. You can do anything, because you have runnable code, and that will help you validate everything that much faster.