How to Become a Great Software Developer (Part 2)22nd April 2019
Jon Christensen and Chris Hickman of Kelsus and Rich Staats of Secret Stache conclude their mini-series, “How to become a Great Software Developer.” In the previous episode, they covered the first three of seven principles that differentiate a good from a great software developer: Practice, Persistence, and Place value on understanding above correctness. Now, they reveal the remaining four software developer principles.
Originally published on Mobycast.fm.
Some of the highlights of the show include:
Read and review code written by other people; code bases are easy to access and copy because of open source:
- Is there a consistent coding style?
- How readable is the code?
- How quickly can you understand what the software is doing?
- Are tests and documentation included? Are they manual or automated?
Details matter; coding style should be consistent and intuitive; remove unused software in code base; think like a user and meet their expectations:
- Where I’m going to find things?
- Where’s the configuration going to be?
- Where would I expect the database models to be?
- What about endpoint implementations, routes, and other pieces?
Optimize for clarity; premature optimization is the root of all evil; focus on making code readable and maintainable:
- How dry can you make your code?
- How much can you pack into as few characters as possible?
Testing: Be accountable by validating accuracy of the software code you’ve written:
- What are the inputs to this?
- What are the normal inputs that I’m expecting?
- What are some that I’m not expecting?
Links and Resources
Secret Stache Media
Rich: In Episode 56 of Mobycast, we conclude our mini series on how to become a great software developer. Welcome to Mobycast, a weekly conversation about cloud-native development, AWS, and building distributed systems. Let’s jump right in.
Jon: Welcome, Chris and Rich. It’s another episode of Mobycast.
Chris: Hey guys.
Jon: Good to have you back. Last week, we were talking about seven things to become a great software developer. Of course as always, we like to make these long outlines for ourselves and prepare. It’s very difficult to all of the very important thoughts that we have and keep them to 20 or 30 minutes. We’ve got through three of the seven things last week and this week we will do the other four. We promise we’ll get through all the other four this week.
The first three were practice, practice, practice. Always making sure to write actual code. Persistence, which is not giving up when things get challenging and having the confidence that there is a solution to whatever problem you’re facing. Even if you need to ask for some help to push through those difficult parts and finish things. Finally, number three last week was valuing understanding above correctness. Really it boiled down to making sure that you understand the code that you produce, and when you run into problems, don’t spray and pray, or don’t make random changes to your code, hoping to make the change that makes it work. If you’re doing that, then probably you don’t understand the code that you wrote or the code that should be there. So, taking the extra time to get that right and to understand it, is going to pay off dividends for your future as a developer.
Did you want to add anything to that summary of last week, Chris?
Chris: No. I think that’s a great wrap-up. Though one thing that did […] the lines when we say that again and the whole idea of spray and pray or making random tweaks, hoping something will work. That’s sounds a little crazy, right? Really, software developers do that? The truth of the matter is, it’s actually pretty common, which is scary.
So again, reiterating it’s so important to not have that approach but instead it’s a great opportunity to understand what’s going on, stick with it, have that persistence, strive for the understanding, don’t be pressured into your velocity of getting work items done at the sake of compromising that understanding. Again, it’s just going to pay off so much as you go forward.
Jon: Great. As we said, we have four more to go. What’s the next one? I’m going to not say them all in advance so we can be surprised to see each one comes. What’s the next one, Chris?
Chris: The next one to talk about would be go review, read code. Analyze code, grade code written by other people. This is a great way to learn and improve just by studying the works of experts. This is true for so many industries. Artists do this, musicians do this, architects do this, all sorts of craftsmen have this principle. We as software developers should absolutely do this. Now, with open source, it’s so easy, it’s so accessible to see these code bases, go in, review them, get ideas, learn new techniques, and see what it means to have elegant, concise, great code.
Go pick an open source project that you admire, that’s in your technology stack. Go clone that repo and just start studying it. Look at it and look at it for things like, is there a consistent coding style? How readable is the code? How quickly can you understand what is the software doing? What about documentation or test? Are there test included? Are they manual? Are they automated? These are all things that you can look at, that help define what really great, solid code looks like.
Jon: I think for any mid to senior developers listening, one of the fun things about doing this is that you all go look at some code, open up an open source project that you really admire or use a lot and you’ll be like, “Woah. Not all of this is that great. I can do as well as this.” That’s just a really empowering feeling. That’s cool when that happen.
Chris: Absolutely. It’s a sign that you do have that. You’ve done some of the stuff we’ve already talked about. You’ve done the practice, practice, practice and the persistence. That helps you identify what’s good code and what’s not-so-great code. Maybe you even think like, “Hey, there’s a better way of doing this,” and you end up doing a pull request or something like that. So, absolutely.
Jon: Sorry to put you on the spot but can you think of the last time you looked at an open source project, you looked up the code in detail and you’re like, “This is so good”?
Chris: I have to admit, I’m a pretty tough judge. I’m not easily impressed. This is true, by the way, even with my own code. When I’m writing code, I’m usually thinking like, “Wow, this is the best I’ve ever done,” like, “This is beautiful, this is great code.” And then I’ll come back to it six months or a year later and I’ll be like, “Meh. I’m not sure what I was thinking there,” like, “This could be better.”
I can’t think of any particular open source project recently that I’ve looked at, that I’m really impressed with. Honestly, although I do look at a lot of open source software, it’s really more of a function of the fact that we use Node a lot in our projects, and with Node has a great ecosystem of modules that you can pull and then use and whatnot. So, a lot of the times, just understanding how things work, troubleshooting some stuff, sometimes the best documentation is the code itself. That’s the kind of software I’m looking at. A lot of times I’m less than pleased with the code quality. I’m almost sometimes surprised that, “Wow, I can’t believe this works.”
It goes both ways. You can look at code that’s really good and elegant. You can use it as a way of improving learning. You can also look at code as a way of identifying like, “Oh yeah. This could be done better,” or, “I can identify some of the things that make it maybe not such a great piece of code,” or maybe it’s not maintainable or easy to understand.
Those are valuable lessons that you can learn as well. It just reinforces those topics for you and gives you some of that empathy that you need when you are writing code. So keep that in mind. It cuts both ways.
Jon: I’ll ask myself the same question because I was prepared. The last time I saw code that I was like, “Oh, this is pretty cool,” was a library called PSPDFKit. It is not open source anymore. It was just the case that you could buy a source code license for it. I was working for a client that had purchased that source code license on it. I don’t think you can even buy a source code license anymore. But it’s basically an iOS library for showing PDFs in it. I guess they probably support Android out here, but if you needed to do that sophisticated PDF stuff like drawing on top of a PDF, or having multiple […], or searching through PDFs, or all that cool stuff that you might need to do, it really became a de facto. Dropbox was using it, so many other huge companies were using it, and it was the best library.
I just remember looking at the code and when I finally got my head around it — it was fairly complicated — I was pretty impressed by how far the guy who had developed it, it was really a one-man shop at first. Had pushed iOS, he really just wrung every last bit of everything he could. Everything from performance inside of iOS to memory management to just what possible with the UI, he had just wrung that out of iOS. It was cool to read. There are good examples out there and it’s fun to be impressed by a piece of code, too.
All right, let’s move on to the next one.
Chris: Yeah, moving on. The fifth principle, if you will, is details matter. I’m definitely a big believer in this. Dotting your I’s, crossing your T’s is really important especially when the software you’re building has more of an audience than just yourself, which is almost always the case. The software that you bring should be consistent. All through your code base, you should have the same coding style. I don’t care how many spaces your use, whether it’s 2, 4, 3½. Just make sure every single file has this same number of spaces. Same thing goes with tabs versus spaces.
The way that you comment your code, if you have a common header or something like that in the file, it should be very consistent throughout the code base. It should be organized. I should be able to look at the software the way that it’s structured from a directory standpoint. It should be intuitive, like where I’m going to find stuff? Where’s the config going to be? Where would I expect the database models to be? What about endpoint implementations, routes and whatnot? All that can be really easy for someone to figure out just by an organized directory structure that makes sense.
Also, just don’t have software in your code base that’s not being used. One of my biggest pet peeves is commenting out code. Why do it? This is what we have. We have a version control system. If you want that code back, it’s easy enough to get it. You’re versioning control system help you find that. By commenting the code, when someone’s looking at that, they have to mentally process that and understand like, “Okay, this is not important but it’s still there.”
Jon: You have to answer the question why is this not important, whereas it’s better just not to have that question in the first place.
Chris: Yes. And if you have dead code, unused files, get rid of them. There’s no reason to have it. There’s nothing more satisfying doing a commit when the number of net new lines is negative. Those are some of my happiest commits when I’m going through refactoring and just realize, “Hey, I just don’t need this anymore,” and just yanking it. I would love to have a program that was a single line long. That would be the best program.
Jon: I think beyond those details are also just the details of making sure to think about what users actually do and thinking like the user, thinking about who is using the software, what their expectations are, if those expectations are being met even in corner cases, and then actually trying those corner cases out, not just assuming that they work. I think that’s part of thinking through details.
Another part of thinking through details is if you have a UI and its got words on it, just double-checking that you spelled them right, that things are in the places where they’re supposed to be, and that they’re in the colors that they’re supposed to be. Not doing those things is so expensive. Having somebody else find those mistakes for you, then putting them into a system, then you looking in the system, then take the card and assign it to yourself, fix the two-second bug, then put it all together in a pull request, have somebody else review that code, you just added two or four hours of work, who even knows, a lot of work for different people just because you were too lazy to make sure that you didn’t spell guarantee wrong. Just read it. Proofread your stuff. That is obviously a pet peeve of mine. Obviously.
Chris: Absolutely. These are the things, too. It’s pretty common for people to not do this or to place less emphasis on it but it really is important. At the end of the day, it boils down to just really caring about what you’re doing and treating it as a craft and not just a job or a task. That’s one of the things that differentiates good from great.
Just think about like a piece of furniture or a house. Details matter. The way that you did the joints on a piece of furniture, how much care and craft went into it, and how much attention was paid to the details. That makes the difference between a piece of furniture that’s amazing versus one that going to fall apart in two years.
Jon: Yeah or even if it’s sturdy, when one ends up in a landfill versus one that is handed down from generation to generation for 500 years.
Chris: Absolutely. So, take that same approach with your software.
Jon: Okay. What comes after details matter?
Chris: Moving on, the next principle that really came to mind was optimizing for clarity. This is, again, another one of those things that you seek right off, where there’s the tendency to prematurely optimize something. We’ve all heard of the expression, ‘premature optimization is the root of all evil.’ You should really focus on making sure your code is readable and maintainable, as opposed to being tricky or clever type thing.
You may use other language-specific idiom that allows you to combine the equivalent of four lines of code on a single line of code, and you maybe all proud of yourself and pat yourself all on the back. But now, anyone that looks at it is going to take then 20 minutes to figure out what’s going on, or to go look up at some obscure part of the language reference to understand that. At the end of the day, there’s really no good reason for making people do that. It didn’t make a difference in the execution of the code necessarily.
Jon: But wait, Chris. You have just said that wouldn’t it be awesome if you could write a program in one line of code?
Chris: Absolutely. As long as that one line is simple, concise, readable, and maintainable.
Jon: It sounds like there is just a natural competition among developers to be more badass, that that leaks into language idioms itself, like how dry can you make your code? How much can you pack into as fewer characters as possible? “Look at this. It’s only 13 lines but it does — ”
Chris: Absolutely, it is. This is very much a tendency of developers to do this. That’s why this came top of mind. I would really love to see that not be a case. Instead to have the badassery be in taking pride in that when people see your code, they’re like, “Oh my gosh. This is so easy to understand. I could jump in here and I can start adding code to this with no problem. It’s not going to take me a long time to come to speed on it.”
That should be the metric by which the badassery of your code is judged, not by these unrolling loops for performance reasons or using language-specific idioms or doing some super complicated data structure because it saves you a few CPU cycles. Chances are, you don’t need that and it just, again, makes it so much more complicated. You don’t need to show off that way.
Jon: Yeah and there are some cases where you do need that. I would say if you’re that person that needs that, you know it. You know who you are. You know what you’re doing. Everyone else doesn’t.
Chris: Yes. You’re probably right in the compiler.
Jon: Right. Is there anything else you want to talk about on optimizing for clarity? It’s just one of those things that I agree with so deeply but it’s a simple concept.
Chris: I would say, too. One of the ways you know that your code is very clear is by the fact that you don’t need a lot of comments in it. I would say the more comments you have in your code, that’s a big smell, a code smell that your code is not as understandable as it should be. I think, ideally, you don’t have any comments in your code. The code should be self-documenting. It should be so elegant, well-organized, understandable, and maintainable, that it just documents itself, that it reads almost as prose. That’s the goal. That’s definitely what I’m shooting for.
Chris: I just can’t emphasize that enough. If you can just really shoot for that as your goal as opposed to trying to prove your badassery in idioms or optimizations or whatnot, that’s the wrong direction.
Jon: Cool. Our last and most important item on the list?
Chris: Testing. And really, what this comes down to is accountability. I think definitely in the past, we have organized ourselves as an industry that have separate teams of developers versus testers versus product managers and what not. Now, it’s all become a bit more amorphous and don’t typically have separate test teams.
Jon: Like SecOps?
Chris: Yes. Just throw them all together. It’s very common, though, for developers to think, “It my job to write the code and someone else, whether it be the product manager or customers, something like that, if they find bugs, they’ll tell me and I go and fix them.” Instead, it really should be you take accountability for the correctness of your software first. You can’t call your software done unless it’s fully tested. You should have your own test or integration test, you should understand what’s the code coverage of this, you should be testing for all of the exceptional conditions, what are the unexpected things that can happen. If you’re writing back-end software, you not assuming anything, like for inputs that are coming into the system.
It comes down to about just taking complete accountability for the crapness of your code and having that mindset that when people do find bugs in your code, that’s a bit of a disappointment. It’s something they shouldn’t have found because you should’ve found it yourself.
Jon: That’s a natural human tendency that I think we have to overcome in order to be able to do this well. Recently, I shared with the team an example of this tendency that was on an article. I’ll try to find it and post it on the show notes, from the New York Times. I’m going to give it away, unfortunately, so it’s not going to be as fun for people that click on it.
Basically, it gave you an example. Here’s four numbers and they follow a certain pattern. You can test it as many times as you want and then in the box below, tell us what the rules are. The four number they gave were like one, two, four, eight. Then it was like, “Oh, I get the pattern. It’s obviously squares. Let me test a few squares.” I fully got caught in this. I tested a few squares. “Oh yeah. Totally it’s squares. Got it.” Then I wrote in the box like, “Each number is the square of the one before it,” and then I pressed submit and it was like, “You’re wrong.” The actual rule was that each number was just greater than the number before it. You grew it like 1, 3, 17, 100, and that would have also passed the test.
The point that it was trying to make is that when I ran each test, the answer was like, “Yup, that passed,” and I was like, “Yes, of course, because I’m right.” I never ran a test that was like, “Nope, that doesn’t pass.” I never tested enough the get the no answer. If I were to put in 4, 3, 2, 1, it would have said no, and then I would have be like, “Okay, it doesn’t like that.” I think that’s what software developers do and I think all of us do that. We run our code and we’re a little nervous that it might be broken in some places. We want to make sure that it works, so we go and make sure that it works. “Yup, it works. Good. It works.” But of course, it doesn’t work if you haven’t really found out where it doesn’t work. There must be some place it doesn’t work. I think that it’s literally a human tendency. Everybody has the same tendency. It is absolutely one that you can overcome. So, do it. Overcome it.
Chris: We all have pattern bias and whatnot. I think the good news here is that would be an example of black box testing, where just not doing an exhaustive suite of test versus when you’re writing code, you’re really doing more white box testing. It becomes a lot easy. You can look at like, what are the inputs to this? What are the normal inputs that I’m expecting, and then what are some of the things I’m not expecting? You can actually make it a bit more structured so that even though you do have pattern bias and what not, just by looking at the code and having the advantage of knowing this is just a state machine, you have a function, it’s a set of input, what are the inputs to it, what are the outputs that I’m expecting type thing.
Jon: I think with web apps, when I look at stuff where people tend to not test their own code is, “Let’s see what happens if I log out first, if I’m not in the state I expect to be in,” kind of thing, or, “Let’s see what happens if I go really fast.” Software developers, I’ve noticed when they test they don’t like to go fast because they don’t want to break anything. So, go fast. Try and break things.
Chris: Because your users will. Right?
Jon: Yes, exactly.
Chris: Again, at the end of the day, it boils down to just take accountability for the correctness of your software. Don’t expect someone else to validate and verify that, “Yeah, you’re complete.” Take that responsibility of your own. You’ll be a much better software developer for it.
Jon: Right on. So those are all seven. We did practice, practice, practice, we did persistence, we did value understanding above correctness, we did review great code written by others, we did details matter, we did optimize for clarity, and we did testing. Did I get them all?
Chris: That’s it. That’s all seven.
Jon: All right. Anything else to add, Chris or Rich, before we wrap it up?
Rich: Not for me.
Chris: This is just a collection of seven things that came top of mind of me. It would be interesting to hear what other people think as well. Any feedback or other ideas on what it is that really makes a great software developer, we’d love to hear it.
Jon: Totally agree. Thanks for joining us. We’ll talk to you next week.
Chris: All right. See you guys.
Well dear listener, you made it to the end. We appreciate your time and invite you to continue the conversation with us online. This episode, along with show notes and other valuable resources is available at mobycast.fm/56. If you have any questions or additional insights, we encourage you to leave us a comment there. Thank you and we’ll see you again next week.
How to Become a Great Software Developer (Part 2) was originally published in Hacker Noon on Medium, where people are continuing the conversation by highlighting and responding to this story.