Getting really good at asking questions is also a great hack for looking like a better developer (it’ll also help you actually become better, but in the short term it’s a good hack). When you ask a bad question, like “My code isn’t working, can you help me?” people have to wonder what you’ve tried already or if you tried at all before giving up and asking someone else. If you ask the exact same question with more detail, especially about what you tried already, like “I’m trying to send an email but I’m getting an error message I don’t understand. I tried googling it but I got a bunch of different answers and I don’t know which one applies to my problem. Can you help me sort through them?” then it’s obvious that not only did you not immediately give up, but you also respect your answerer’s time enough to make it as easy as possible for them to help you. Telling them what you’ve tried already means they can skip suggesting things you already did, and asking a specific question means they don’t have to do the work of figuring out what the question actually is before they can even start thinking about how to answer it.
People love it when you make things easier for them, and when you show them you’ve put some effort into doing so, they’ll think you’re a better programmer than the person who makes getting the real question out of them like pulling teeth even if both of you are around the same skill level. That’s the hack part :) The becoming a better programmer part is that stating a question really clearly (yay rubber ducks!) and listing everything you’ve tried already may trigger that flash of insight about what you haven’t tried but should or what assumption you made that could be wrong. If you get into the habit of reflecting on what you’re doing, you’ll learn a lot faster than someome who sits around and waits for help.
Willpower is a big deal when you’re doing an inherently difficult and frustrating task like programming. It’s also something we tend to assume we either have or we don’t, but there are actually a lot of things we can do to improve our chances of making it through a willpower challenge whether that’s making yourself write boring documentation or resisting the urge to screw around on reddit all afternoon instead of doing your work.
Kelly McGonigal gave a talk called The Willpower Instinct (not so coincidentally also the title of one of her books) about that exact subject at Google. It’s a really interesting talk and I recommend watching it, but it’s also an hour long so I’m going to list the takeaways here. Full disclosure, some of these things will take up a little bit of time outside of work, but they will definitely not eat your life and will be useful for way more than just being a better programmer.
1 Sleep! Just getting enough sleep makes it much easier to make decisions that support your long term goals/resist choices that sabotage your long term goals. Meditation helps too, that was the tool used to improve sleep in the study Kelly McGonical referenced. That study was done on people in rehab for drug addictions, and even with an urge that strong to use drugs, simple sleep and meditation made the partipants much more resistant to relapse than the control group. Something really cool about that study was that the participants got those fantastic benefits from meditating for only 10-15 minutes a day.
There’s a lot of really interesting stuff in the talk about how different parts of your brain actually work together (or don’t) when you need to use your willpower to delay gratification or work toward a distant future goal, but I’m not out to transcribe the whole talk here, you’ll have to watch it for all the details :)
2 Stop beating yourself up when you make a mistake. Beating yourself up doesn’t actually improve your willpower at all. It turns out that the harder you are on yourself when you have a willpower failure, the sooner you fail again and the worse it will be next time. The worse you make yourself feel, the more you want comfort, and the more you want comfort, the more likely you are to turn to the exact thing you’re trying to stay away from, whether that’s chocolate, alcohol, cigarettes, or excessive youtubing. It actually works much better to have compassion for yourself and just try to do better next time.
3 Learn to identify with your future self. Most of us feel like our future self is a stranger, and the more you feel like that, the less likely you are to do things to protect that stranger’s health and happiness (like exercising or saving for retirement). Who here has cursed their past self for not commenting their code? We all know that we should, but we hardly ever do it. I think a big part of that is that we somehow don’t believe the frustration our future selves will feel when they have to work on another piece of badly commented code is as bad as the frustration our present selves feel.
One way you can get to know your future self is by writing a letter from them to your present self. This can either be a general letter about who future self is and what they’re up to, or a more specific letter thanking your present self for doing the work of exercising more, quitting smoking, or actually commenting that code even though it seems perfectly clear right now.
4 Imagine yourself failing. It’s totally counter intuitive, I know! The idea is to think about how things could go wrong for you so you can come up with workarounds. Say you want to exercise more, if you know that you’re likely to put things off until it’s too late at night to go for a run, you could leave yourself notes or set reminders to make sure you actually go for that run. If you keep track of what goes wrong for you and basically become a detective of your own failure, pretty soon you’ll have a comprehensive set of workarounds / ways to avoid the things that trip you up.
It’s also really helpful if failure doesn’t come as a shock to you – it’s easier to shrug it off and try again if you’re a little bit pessimistic and go “okay, I know I’m going to fail at this a few times, what am I going to do when that happens?” Sure, it seems obvious that the answer is “get back to the thing I was doing to reach my goal” but if failure is a surprise then it’s really easy to decide, “welp, I missed two workouts this week, I’m fundamentally a failure, no point in trying again so I might as well sit on the couch all weekend watching tv” even though two workouts are just not a big deal in the grand scheme of things and you could easily get back on the wagon by working out on the weekend.
5 Learn to tolerate discomfort. In her talk Kelly McGonical mentioned that the ability to hold your breath for 15 seconds is actually a very strong predictor of how well you will do in willpower challenges. There’s a technique called “surf the urge” that relies on that idea. When you “surf the urge” you give your full attention to your craving and trust that if you just sit with it for a while, it will pass. Immediately trying to repress the urge, whether it’s to have a chocolate bar or to screw around on reddit for three hours, just teaches you that the discomfort you’re trying to avoid is intolerable and you Absolutely Must Do Something About It Right Now. That’s just not true, you’re a grownup, you can ride it out. What you do by surfing the urge is break the link between feeling stress and opening that tab, which makes it much much easier not to give in.
And finally, here are some much less evidence-backed tips from me:
A Outsource your willpower if you can – browser extensions like stayfocusd (I haven’t found a really good mobile app yet, recommendations welcome!) that just don’t allow you to spend all afternoon screwing around on Facebook mean you can take all the energy you would have spent resisting the urge to open that tab and spend it on something else.
B Build habits. Once something is a good solid habit it takes way less willpower to keep doing it. Flossing, for example, is boring and a hassle but once it’s a habit it feels way more weird not to do it than to just get it over with. I recommend BJ Fogg’s Tiny Habits course if you want to make more things a habit so you can stop thinking about them.
Today’s tip for becoming a better programmer while still having a life isn’t just good for you, it’s good for your whole team. That tip is documentation.
I know, nobody actually likes doing documentation. Fortunately, I’m not talking about dry design docs or endless specifications, I’m talking about a simple wiki (or whatever works for you), written by you and your team for you and your team. It doesn’t have to be polished, it doesn’t have to be formal, it doesn’t even have to be spelled perfectly. All it needs to be is correct and understandable. The idea is to explain things just like you would to another dev on your team, not to waste hours proofreading.
Great, but what should you document? In short, anything you’re going to want to know later. Especially useful things to write down are why architectural decisions were made, how parts of the system work at a high level, guides to testing certain features (great for complicated payment provider integrations, not that I’ve been fighting with those), and especially guides to setting up your development environment, whatever that thing is that you forget every time and have to look up again or ask someone about.
Just saving yourself time relearning parts of your codebase will help you get things done faster, which is basically being a better programmer, but explaining things (even if you’re writing to yourself) helps you understand them better. Explaining something forces you to think about every little detail, and putting something in your own words helps it stick in your brain – it’s the same principle that helps you remember things better when you take notes on them, whether or not you ever look at those notes. The better you understand your codebase, the better decisions you can make about how to add new features or fix bugs.
As a bonus, reflecting on why you made certain decisions and being able to go back later and see if the reason you did things the way you did holds up over time also makes you a better developer. You don’t even need to make a special effort to do this, if code gets used it gets changed. All you need to do is wait, eventually you will have to revisit the code you documented and by the time you do that, you will probably have forgotten the details and will need to go look it up in that handy wiki you created :)
Writing things down also helps you get that answer again without interrupting anyone, and the less you can interrupt teammates the better considering how expensive interruptions are for programmers. I couldn’t find a hard number, but I feel comfortable saying that it takes at least ten minutes to get back into a complex task like programming once you’ve been interrupted. It can be even worse if you get interrupted at just the wrong time. I have a terrible time getting into a task when I know I’ll have to stop soon for a meeting or appointment or whatever, which means an unfortunately timed interruption can kill a solid half hour of productivity even if it only took a couple of minutes to deal with the interruption itself.
All the benefits you get from making knowledge about your code available and searchable also apply to your teammates. If you just document how to set up your development environment, that can save hours every time someone has to set up their environment whether it’s a new employee starting or a long time employee getting a shiny new computer to replace an old one. It’s even better for everyone around you if the whole writing things down idea catches on – then they also get the benefits of explaining things and documenting the particular things they forget and need to look up as well.
And best of all, this is another work thing you can do at work that has no effect on your personal time.
As much as we would all like to believe that programming is about logic, not feelings, being able to deal with your emotions is incredibly important if you want to be a better programmer. For example, one of the best things you can possibly do for you career is to learn to take criticism. Logically everyone should be thrilled to get feedback on their work but you know what gets in the way? Yep, it’s emotions.
It can suck to hear all about what’s wrong with your code, especially if you worked really hard on it and thought that this time you finally got it right. Hearing about what you need to improve is incredibly helpful (who has time to make every possible mistake on their own? that would take forever!), but that doesn’t mean it never hurts your feelings. And when people’s feelings are hurt, it’s really hard for them to listen. Sometimes emotions get in the way of your improvement as a developer.
So how do you learn to take feedback even when it hurts?
First of all, you’ve got to accept that it’s normal to have feelings about being told that your code isn’t good enough. There’s no fixing a problem that you can’t admit is happening, after all. That absolutely does not mean you should be ashamed of having feelings – not only is it just plain wrong to shame anyone, including yourself, for being human, but it’s a huge waste of time. All it means is that if your feelings are keeping you from being able to take feedback, you’ve got to get a handle on them. You would debug a program that couldn’t handle certain inputs, right? Sometimes your mind needs debugging too.
One way to do that is to remind yourself that feelings aren’t facts. Just because you feel attacked or like everything you do is stupid and terrible and you’re never going to be any good at this and should just crawl into a hole doesn’t make it true. That’s just your brain freaking out, if you give it a minute it will calm down. Yes, it sucks in the moment to hear that your code needs work, but you’re going to feel fine tomorrow. With practice, you’ll get used to hearing what you can improve and start skipping the boring angsting step to go directly to fixing things.
A common thing programmers do that makes that way harder is to get really really really attached to their code. You should absolutely care about whether you’re doing a good job but you’ve got to remember that your code is not you. The quality of your code has nothing to do with your worth as a human being and any one piece of code doesn’t even mean much of anything about your skills as a programmer. Everyone has off days, making a mistake does not mean you’re a bad programmer, will always be a bad programmer and should just go find a hole to crawl into. Everybody makes mistakes, you’re not that special ;)
Quick side note: code reviews are never supposed to be mean. Aside from being a tremendous dick move and thoroughly unprofessional, it’s a waste of time to be a jerk when you’re giving feedback. If people hate doing code reviews they will find ways to not do them and the quality of code on your project will suffer. If you can’t be nice because it’s right, be nice because it’s effective. And if your team lead/senior dev/whoever does your reviews can’t at least be civil, find a new job. Life is too short to put up with dicks.
Something else you can remind yourself about when you’re having feelings about a code review is that nobody gives advice to people they don’t believe can do better. If you believe someone can’t learn you don’t bother giving them a code review, you quietly fix what you can while they’re not looking and hope they eventually get fired. Bothering to give someone feedback is a statement that they’re worth the effort.
The most important piece of advice I can give you, though, is that you need to be able to take a step back both from your feelings. Meditation is great for this, by the way. I’m going to steal Headspace’straffic metaphor here because it’s really good: training your mind isn’t about forcibly clearing it, it’s about learning to watch your thoughts and feelings go by like cars on the road and not needing to run out into the street and direct traffic. Having a feeling doesn’t mean you have to do something about it right then, you can wait a bit and see if it’s still important.
That stepping back thing is useful for more than just code reviews, too. Professional software development can be really frustrating for reasons that have nothing to do with writing code. Features get changed or cut, projects get dropped, companies change direction, sometimes things never make it into production no matter how much you believe in them or how hard you try. If you can’t step back from your attachment to a project and accept that things don’t always go the way you wish they would or even the way they logically ought to, you’re going to have a bad time in this field (or any other for that matter).
While you’re at it, literally step away from the computer now and then and do something else. Not only can you become a better programmer and still have a life, but having a life will make you a better programmer. Nerds tend to hyperfocus, which is great when you have a concrete task to get done but not quite as great when you lose all sense of perspective because you do nothing but code all day. Having other things you’re good at and other things to look forward to really helps put that one bad code review into perspective.
More stuff you can do to be a better programmer while still having a life!
The core of programming is really problem solving, but we’re kind of expected to pick it up as we go while we’re learning specific skills like programming in java. I have a strong suspicion that’s why so many new developers feel totally lost when they try to build something on their own: we’ve collectively done a bad job of teaching them how to break down problems and solve them.
Problem solving is a gigantic topic so I’m not pretending this blog post is going to be comprehensive, I’m just aiming to share a few tips to get you started.
First of all, don’t just start coding. It really helps to have some sort of plan for what you’re going to do. If you dive in and just start coding without any sort of plan you’ll often end up lost in the weeds because figuring out how to solve a problem and how to code that solution at the same time is so much harder than doing those things one at a time.
Ironically, it’s also hard not to do those things at the same time. It’s really common to feel like you’re wasting time planning and making lists when you should be writing code, or that planning is boring and no plan is ever perfect so why bother? It’s also not at all unusual for programmers to start coding without a plan because they’re worried about whether they can solve the problem, so they just start writing code and hope the complete solution will come to them.
Having a plan actually speeds things up because it cuts down on the feeling your way around in the dark that you end up doing when you don’t know where you’re going or how to get there. If you really can’t stand the planning part, programming may just not be for you – solving problems is the real job, code is just the tool we use to solve them. Making a plan may force you to admit that you just don’t know how to solve a certain problem which sucks, I’m not going to lie, but isn’t it better to figure that out right away instead of potentially spending days or weeks coding only to find out that your partial solution is never going to work? Trust me, that sucks way more.
So that’s all great, but how exactly do you break down a problem and make a plan to solve it?
One example is laid out in 5 Steps to Solving Programming Problems by Adrian Prieto. The step I want to concentrate on is “2. Solve the problem manually.” Seriously, write it down exactly the way you would do it if you had to do it manually. If part of the problem involves looking things up in the database, just pretend you have a gigantic binder or that you can call another department for the data you need. The imaginary manual procedure might sound really awful and tedious but that’s fine, computers are great at boring and tedious.
Example time! A common programming challenge question is to write a palindrome checker – you give it a string, it tells you whether or not it’s the same backwards and forwards. It’s really easy to look at a short palindrome like racecar and see that it’s obviously the same backwards and forwards, so let’s imagine we have a much longer string. Now how do we tell whether or not it’s a palindrome? One way is to look at the first character and see if it’s the same as the last character, then the second character and the second last one, and keep doing that until we get to the middle of the string (let’s assume for now that we don’t have to worry about spaces or punctuation). If we make it to the middle of the string it must be a palindrome, so we can return true. If any of the pairs of characters don’t match then it’s definitely not a palindrome, so we can stop checking right there and return false.
Now that we have a manual process, we can start adapting it for a computer to run. The thing you have to remember is that computers are really dumb. If you tell a person “stop when you get to the middle of the string” they’ll know what you mean and what to do if the string has an odd number of characters so there’s only one in the middle. Computers, on the other hand, don’t know what a “middle” is unless you tell them and don’t know what to do with a string with an odd number of characters either. For that matter, they don’t know how to tell they’ve gotten to the middle of the string.
In the interests of not making this post 5000 words long I’ll skip the specifics of telling a computer how to find the middle of a string, the important thing to know is that once you have an overall process you can dive into subproblems like “how can the computer tell when it has checked enough characters?” without losing sight of why that problem even matters and how it fits into the rest of your solution.
It really doesn’t matter how bad your first try at a process is. Writing down how you would do it manually is always good enough for a first try, and once you have a basic process you can start improving it or even trying totally different algorithms. The great thing about a simple set of point form instructions or even pseudocode is that it’s much quicker and easier to change than actual code, so you can mess with it to your heart’s content.
That works great for straightforward problems, but what do you do with an overwhelmingly large problem where it’s not obvious where to start? Let’s say you want to build a todo list app. Should you start by designing the UI? Or by figuring out what your data model should look like? How do you decide which features your app should have?
The question about what features you should have is one of the simpler ones: build the tiniest thing that could possibly work. You can always add more features later. In the case of a todo list app, I would start with being able to add new todos and being able to cross off existing ones. Don’t worry about subtasks, don’t worry about due dates or recurring tasks or anything else, just start with the simplest thing that could possibly be considered a todo list.
As for where to start, if I knew the right way to approach every problem I’d be a millionaire :) I personally like to start with the UI so that once I get down to the data model I already have a list of all the visible information that I definitely need to store. On the other hand, if you’re especially comfortable with data modelling it can be easier to start there. That can also save you from building a database that’s perfect for one screen and kind of terrible for everything else. It really doesn’t matter where you start as long as you remember to look at your overall design from different angles and see if it still makes sense.
At the “boxes and lines” diagram stage just like the point form description of a manual process stage you lose hardly any time at all if you sketch out a solution, figure out it doesn’t handle something well, then throw it out and start over. The important thing is to learn more about the problem, not to come up with a perfect design on the first try.
Like communication, practising problem solving doesn’t have to take up a single hour of your time outside of work. You can get all the practice you need on work problems while you’re at work and still have a life outside of work :)
In my last post about becoming a better programmer while still having a life, I talked about communication. Specifically, making sure you understand why you’re doing a task and what the eventual user of that feature wants to accomplish. That’s far from the only thing communication is good for, though. It’s not just about clarifying tasks, it’s also important to communicate status. Strictly speaking, this may not make you a better programmer in terms of getting things done. It does, however, make you easier to work with and that’s a big part of being a professional. And in the interests of full disclosure, I’m not always great at this, especially when I’m busy, but I try.
If you use slack, a good solution for my team and maybe yours is to post little updates about what you’re working on and how it’s going in your dev channel. When you share what you’re working on, people will have something useful to tell you surprisingly often. I’ve had coworkers tell me about existing code I hadn’t seen before that applies to my problem, ways they had already tried to do something and failed (super helpful because it narrows down what I have to try), or bring up potential issues I hadn’t thought of.
Team leads also really seem to like having a running list of what you’ve been doing and if you’ve hit any snags lately. In my office it’s common for people to work from home, which means my team lead can’t always rely on chatting with people in the lunchroom or on the way to get coffee to figure out whether our tasks are going well or not. My last set of updates were a series of complaints about how badly I was getting along with play 2.5’s requirejs plugin, don’t feel like you have to have positive or even particularly well thought out updates.
Nobody particularly likes to post a bunch of updates about how badly things are going, but that’s actually really useful for your team lead and the rest of your team to know. They can’t make plans about next week if they have no idea how much stuff is going to get done this week. Your team lead doesn’t just know what you’re doing or if you need help, you’ve got to tell them directly. If your updates are always about how badly things are going that’s a useful sign that something is wrong. It could be that you and/or your team lead need to find another solution because the current one isn’t working, it could be that your assignment isn’t at the right level for you and you need some help, it could just be that it’s an especially hard task and you’re not going to be available to do anything else for a while.
If something is going poorly, it’s always better to talk about that sooner rather than later. Seriously, waiting too long to raise the alarm kills projects. Now, it is true that in dysfunctional workplaces you may be blamed or punished for bringing up perfectly reasonable concerns. I’m not going to pretend that every boss you’ll ever have will be the perfect manager, but if you bring up a concern and get ignored or punished for “being negative” I want to reassure you that you are not the problem and didn’t do anything wrong.
If things are going well, you should talk about that too. Just like your team lead needs to know if they can’t give you another task, they need to know if they do need to get another feature specced out and ready for you to work on next.
Whether or not you ever show anyone else your list of things you got done (and it’s not a bad idea to have that handy for when annual review time comes around), just looking back at your list can help motivate you. When I feel like I haven’t been accomplishing anything, it can be really helpful to scroll back through the updates I’ve given and remember that while I maybe didn’t end up with a lot to show for my fight with requirejs, I did learn a lot about play 2.5 plugins and build processes and that will definitely be useful later.
If ongoing updates throughout the day are too much information you can do daily or weekly updates, the only essential part is giving updates on a regular basis. Definitely don’t feel like you need to write a novel for every update, status updates are meant to let people know what you’re up to, not to eat up time you could be using for your actual work.
Giving status updates regularly probably sounds like a really small thing, but it’s been incredibly useful for me.
In my last post I said that being a better programmer wasn’t worth sacrificing your entire life outside of work, but that doesn’t mean being a better programmer isn’t worth some work. Also, sacrificing all of your free time is simply not necessary. There are lots of things you can do to be better that don’t involve never seeing your friends again and/or being a bad partner. Lots of them!
Here’s tip #1 for being a better dev without killing yourself over it:
Specifically, when you get a task, ask some questions to make sure you understand it. Some of the most important questions are the ones you’re scared to ask because you don’t want to look stupid. Like “What is feature x for?” Just because the JIRA ticket says to build an x doesn’t mean the business really needs an x. They might actually need outcome y and think that building an x is the way to get it.
Once you understand why the business needs an x you might be able to suggest a simpler solution – sometimes you don’t need a week of dev time, sometimes all you need is a cron job. Sometimes there’s a library that can do what you need quickly and easily. Sometimes there’s a product or service that does what you need for less than the cost of the dev time, plus if it breaks you may be able to make it their customer support’s problem instead of yours :)
Even if you don’t have a better solution, it’s really helpful to understand why you’re doing something and what you’re really supposed to accomplish. No spec is ever perfect, you’re practically always going to have to make some decisions on your own – knowing the reason behind what you’re doing lets you make way better decisions than if you’re just trying to guess what might make sense. That’s how things nobody wants get built (well, one of many ways they get built, let’s not pretend there’s only one cause) – somebody gets a vague spec, takes their best guess, maybe runs into some problems and has to cut part of it, maybe some of the parts that get cut are actually really important but the dev didn’t know that and now we’ve got a feature nobody wants.
Another good reason to ask questions is to clarify the spec. If you run into anything that needs more details or contradicts some other part of the spec, it’s better to know that before you start building. Nobody likes having to go to their boss after days of development and tell them that they just realised that to build the feature properly they need to build z too and that means they have to throw out the code they already wrote that only supports x and y. Nobody likes hearing that either, so think of the time you spend asking questions as an investment in not disappointing your boss/missing your deadline later.
You might find a whole extra set of problems that need to be figured out before you can build the thing you were originally supposed to. On a large project at work I found out partway through that I hadn’t put nearly enough thought into how new settings for an extension of an existing feature were going to work with the original settings. I could have saved myself a lot of time building and rebuilding handling for that if I had asked more questions in the beginning (and done a better job of planning everything out before I started building it, but that’s a separate blog post).
Not only are complications like that really useful to know about for the sake of building something only once, but the feature might get scoped down or cut entirely if it’s too much of a hassle to do it properly. That might sound disappointing but how much more would it suck to waste days or weeks of time on something that’s never going to work correctly?
And the bet part? Asking questions about work while you’re at work doesn’t touch your free time at all!