On today’s show we have the honor of welcoming Jacob O’Donnell as our special guest. Jacob is a consultant at Stride and we are very happy to have such a good friend and experienced programmer join the show this time around. Jacob will be talking with us about the dangers of ifs! Now we all know how it goes with ifs and how out of hand things can get over time, but on the other hand how do you avoid ifs in the projects you’re working on? Especially if you are not the only one in control. We get down to these important questions with Jacob and try to figure out when are ifs appropriate, when should the alarm be rung and how to go about fixing an over abundance of ifs, because let’s face it, death by a thousand ifs is not a nice way to go! The team pitch in with their personal experiences and opinions on the matter and their are some tactics and tricks in here that you will not want to miss. So tune in and get the low down!
Key Points From This Episode:
- Jacob’s background and programming and how long he has been on the job.
- Joining a project and being blindsided by all the ifs involved.
- When are if statements not bad? And why this question is a bit tricky.
- Programming without ifs and ways this might be possible.
- Using attributes to talk and describe in an object oriented way.
- Remedies or preventative measures for a death by a thousand ifs!
- When to start addressing the problem of ifs before it gets out of hand.
- How to approach an insurmountable number of ifs and when to leave them be.
- Utilizing no object patterns and libraries as a handy workaround.
- Balancing time saving, pleasing a client and clean code.
- Enforcing a limit with static code tools as another remedy.
- Some teach and learns from the team!
- And much more!
Transcript for Episode 58. Death By a Thousand IFs with Jacob O'Donnell
[0:00:01.9] MN: Hello and welcome to The Rabbit Hole, the definitive developer’s podcast in fantabulous Chelsey Manhattan. I’m your host, Michael Nunez. Our co-host today.
[0:00:09.8] DA: Dave Anderson.
[0:00:10.8] MN: Our producer.
[0:00:12.0] WJ: William Jeffries.
[0:00:13.7] MN: Today, we’ll be talking about death by a thousand ifs.
[0:00:16.8] DA: Ouch. Yeah, sounds pretty painful as it is which is a bad way to go.
[0:00:21.2] MN: Yes, definitely. Either that or window. One or the other.
[0:00:25.4] DA: I’ll take the ifs I guess, maybe, I don’t know.
[0:00:28.2] MN: Yeah, thousand ifs are pretty bad to see in a code base and today we’ll be talking about what to do when you actually see them, what are some of the problems of that and maybe some solutions on how to remedy that. Before I continue, we have a special guest, the one, the only, Jacob O’Donnell.
Jacob, how’s it going?
[0:00:46.6] JO: It’s going pretty good.
[0:00:47.5] MN: Awesome. Jacob, could you tell us a little bit about yourself to our listeners?
[0:00:51.7] JO: Sure. Well, my name is Jacob, I’m going to reiterate that and I have been programming since I was a baby. When I was a baby I started programming and I’ve been pretty much doing interpreted languages, sometimes I do static, sometimes people say, “Why don’t you do type scripts?” and I’m like, “All right.”
You know, other than that, yeah I’m a consultant at Stride and yeah, that’s me.
[0:01:15.3] MN: Yeah, well I imagine since you were a baby, you’ve seen a lot of if statements.
[0:01:19.3] JO: Boy, back then, people loved ifs when I was a baby. You know, that’s the first thing I learned as a baby.
[0:01:26.5] DA: Your first word?
[0:01:27.3] JO: If.
[0:01:31.3] MN: Tell us a little bit about that, you go into a code base as a contractor, as a consultant, as a developer, we’re starting a new job and you just – you’re blindsided by the amount of ifs, tell us how does that play out in your mind?
[0:01:45.2] JO: Yeah, typically what I see is like I’ll open – someone will be giving me a sort of a tour of the code base and they often sort of hit this far. Okay, this is one our main files and they opened it up and right away you see just like tons of ifs and conditional logic and wrap that in some more control statements and you know, right away, it’s a little bit like you know, you can tell, it’s like the sign, it’s the first sign of a troubled codebase.
[0:02:12.0] WJ: They always want to explain it like, okay, well the reason why we did this, I mean, it was like – I mean, they know.
[0:02:18.9] MN: Yes.
[0:02:19.3] DA: There’s history.
[0:02:20.8] MN: You’re right, there is always an explanation, they go into it, they feel a little guilty opening the file, they sort of haw and paw a bit but.
[0:02:28.8] DA: There’s the prime directive, you know? They did the best they could at the time with the tools they had in all that good fun stuff.
[0:02:36.8] WJ: Every insane line of code is a perfectly sane response to an insane situation.
[0:02:40.8] DA: Love it.
[0:02:44.0] MN: Yes, but the code, it still has a thousand ifs at the end of the day.
[0:02:47.5] JO: Still has a thousand. It’s a hard hole to get out of because when you go in there, I mean, it’s just so incomprehensible like often, the conditionals have like six and’s or or’s to them. To deconstruct like figure out what any part does, takes so long like it just takes forever and even then you’re kind of unsure and maybe you sprinkle some console logs or whatever your print state of choice is.
You start to be like, “Okay, I think during my execution right now, this is where I need to be and this is good enough.” But it’s still always like, get in there and you go, “No, we’re in trouble.”
[0:03:25.7] DA: When you see some of that also, can be tempting if you have some business you need to do, you have some critical feature, you need to get out there. The pattern’s already there. There’s a thousand ifs and I mean, you’re already going to die from a thousand so a thousand and one is not a big deal.
[0:03:43.0] WJ: Who’s going to notice?
[0:03:45.2] MN: Yeah, that’s the thing I wanted to talk about because you know, people don’t often just start writing if statements all over the place. I imagine like it’s slowly gets added on and on and, “So we just add one more if, it will be fast,” we could make this feature original, boom, there goes the fifth one. 10, 20, thousands.
[0:04:06.5] WJ: It’s the broken window effect.
[0:04:08.7] MN: Pretty much, it’s just like, there’s one broken but just add another one. Break more windows.
[0:04:13.8] DA: Because sometimes, those developers will be recognized as like being the rock stars, they’re the 10X developers who are getting things done so quickly, someone ask them to do something and just out the door, amazing. But you know, they’ve also 10x the number of complicated logic points and other craziness.
[0:04:35.2] WJ: Cyclomatic complexity.
[0:04:37.7] JO: I’ve also seen, I feel like in codebases where I’ve seen that, there tends to not be a lot of discipline about abstracting sort of concepts out. You’ll see the same if In tons of different files, like the same sort of almost a hack. Like rather than abstracting this concept to “Okay, you know, this client has permission,” they’ll go to every single sort of like point where that might need to happen and say, “Unless it’s this client -“
[0:05:05.9] DA: Yeah, that’s true. I guess to build on the point that you were saying before cyclomatic complexity, in case people aren’t familiar with that, that’s like a numerical measure of how many possible branches you can go down with your thousand ifs.
If you have a thousand ifs, it’s at least a thousand but if you have those thousand and or ors on top of that then it’s going to be exploding on top of that even more. Like one per and or or? Is that cyclomatic works?
[0:05:37.0] WJ: Wouldn’t you go up like exponentially? Because like, if you have one if statement there, two code paths, what if there are two if statements and it could be true or true false or false, false, or false true.
[0:05:51.2] DA: That’s true, I was thinking of that of the else ifs, if it’s just the regular if, then.
[0:05:56.4] WJ: Yeah.
[0:05:57.2] DA: Buckle up. Are all if statements bad?
[0:06:03.5] JO: That’s an interesting question, I mean, definitely not but it’s actually hard to put your finger on when it becomes bad. I was actually trying to think about this, what makes an if, good or bad and I really struggle actually.
One of the few things I could come up with is like, you really want to kind of take like that, whatever that Boolean logic is and name it, the reader doesn’t need to sort of reconstruct what does this mean when I’ve ended these three or four variables. But beyond that, like the simple fact like let’s not have too many. I had a hard time thinking like what makes a good if?
[0:06:43.7] WJ: I think there’s a Sandi Metz talk where she explains how she actually came from Small Talk where there are no ifs and she found that actually, by coding without ifs at all, even in languages that have that language feature, the code gets to be clearer, I don’t know that I could actually program with no ifs.
[0:07:06.4] JO: Interesting exercise, I actually just watched that talk, it was her Rails Conf. 2015 I think. Yeah, it’s a crazy thing to think about to program without ifs and I think you just need to really up your object orient game which that’s a separate topic. I feel like objects are in decline but save that for another day.
[0:07:25.7] WJ: Yeah, it seems like there are a lot of different classes of problem where ifs tend to be used or be used like you know, I mean, we talked about some but there’s also the no problem where there are no – throughout your code base and you always have to check, there’s type checking, that’s another one that’s pretty closely related.
[0:07:47.5] DA: These instance.
[0:07:49.0] WJ: Yeah, with the permissions when what you got too already, are there any others?
[0:07:52.5] JO: I mean, it’s really easy to code business logic in an if, if I’m a business then I’m making decisions and my decisions are important and you know, that’s how I get that really complicated, nasty thing like, “If the price is over $20 but less than $30 then I’m going to apply this baseline rate. Otherwise, it’s going to be this thing. It’s like, wow. You really need to have deep understanding in order to parse that code.
[0:08:19.2] WJ: Especially if they’re giving in to you like a control flow like here is the flow chart, here is the diagram that shows what you do in different scenarios and if yes, or if no appear throughout.
[0:08:31.4] JO: Right, we speak with if. If is like an English word, people don’t speak with object oriented methods, they don’t say, you know, like, I don’t even – can’t think of something on top of my head but it’s very natural to describe that. When someone just sort of says, “Okay, if it does this, else it does this,” and then it’s very easy to translate that directly into code.
[0:08:52.9] WJ: Actually, I think that maybe one way that you could talk about this in an object oriented way is by describing attributes of an object. I’m thinking in my head of a stool which has three legs and a chair which has four legs. You could use Boolean logic and say, “If chair, then four, if stool, then three.” Or you could use duct tape and you can have a chair that responds to a legs count method and the stool that responds to a legs account method. You could say, “Chairs have three legs, stools have four legs,” and you avoided your if.
[0:09:31.0] JO: I think when you’re dying for an object that is when you start seeing that same logic spread across the code base but not necessarily for number of legs but other attributes of chairs and stools. If you have somewhere else in the code base like, what’s another property of seats? Comfort level, if you say, if stool comfort level is seven and if chair comfort level is 20, because it’s a real comfortable thing.
That’s really crying out for an object, you can refactor that and have two messages and you’ve now got this place for information to collect about sitting objects.
[0:10:09.9] WJ: It seems like we’re trying to transition into solutions here. What are some remedies or you know - What is the medicine that will save your life from the death by a thousand ifs?
[0:10:22.0] MN: Don’t be the person to add the thousand and one if. Really try and stop yourself from just one more, it wouldn’t hurt a bit. Be the change that you want to see in the code base and make the change. Don’t like, you know, I think Jacob mentioned earlier, having – rather than having this really long and’s or or’s, checking for whether it’s true or false to actually have a constant that describes what you’re getting so that the developer after you doesn’t have to spend time reading and trying to understand this Boolean thing. Try to avoid being a thousand and one.
[0:11:01.8] DA: That’s always like kind of hard because the classic naming problem and if you give it a bad name then that may be worse than no name at all sometimes. If it’s just like, my condition won and my condition too, you know, future generations may questions your wisdom.
[0:11:20.9] JO: A bad name is usually better than a complicated if statement, would be my argument. I mean, maybe not my condition one but usually if you just try a little bit, you can beat out the, just like, or or and and whatever variables you already had ready.
[0:11:39.0] DA: Yeah, that’s true, I was trying pretty hard to be.
[0:11:43.2] MN: If you do see a bad variable name and you somehow figured out a more clearer name and make that change too. So that the next person can then iterate on the variable name and everyone gets to understand at the end of the day.
[0:11:57.4] JO: One thing I wonder though is when you say, don’t add that 1001th if. Like that, I feel like that’s actually pretty tricky because, then, what are you talking about, how do you solve that? We should talk about that but I think more importantly, don’t add that 10th if. The moment your spider sense starts tingling and you’re like, “This is starting to be bad.”
That’s when you need to address it and that’s when, you know, before it becomes a pattern. But what should you do when it’s 1,001? You can’t really stop what you're doing for two weeks and refactor a giant thing.
[0:12:37.0] MN: I wouldn’t say like refractor the whole thing because then that would take two weeks to do but you know, try to chip down the mountain of ifs down and maybe have it into like, if it’s nested way too deep then maybe you can take a piece of the nested if and make that into a function and slowly bubble up the nested if as – so that it doesn’t become nested anymore
[0:12:59.3] WJ: Yeah, I think that the method of abstraction, yeah I think that method abstraction is a powerful tool for combating methods that have become infected with a proliferous of ifs.
[0:13:11.0] DA: Yeah finding a seam and then maybe breaking it into three different parts so then you have three methods with 300 ifs which maybe start with 333 and then you decide which one that has 33 or 34.
[0:13:24.6] JO: Yeah, I’ve had Michael Feathers reference there. I mean that is actually important if you are dealing with the situation, what’s the name of the book? Dealing with Legacy Code or something like it’s an excellent book of how to come out of that.
[0:13:36.9] DA: Yeah, I think we have talked about this in the podcast too about tech debt, we have a great episode on that and we are talking about prioritizing when you should even attack this thing because maybe this piece of the codebase never changes and it works and you have things that you have to do. So maybe you shouldn’t go down that path if you have some other thing that you need to work on but if there is return and there is complexity because there’s a thousand ifs then that is a good time to jump in there and start refactoring.
[0:14:06.4] JO: Yeah, the boy scout rule. Just make it a little bit better than when you left it.
[0:14:09.9] MN: There you go.
[0:14:10.6] WJ: Yeah I think also hashes are off to a good pattern like there are times when what you really need is a data object, you need another type of data object in order to encapsulate what’s going on because it is not really a logic problem. It’s not different behavior needs to happen in different scenarios. It’s that the same behavior needs to happen with different data.
[0:14:34.0] DA: Yeah, in Python you don’t even get a case statement. They just don’t want it. You just get a hash and you have to stuff your logic in there through callbacks.
[0:14:44.0] WJ: No object pattern, also handy.
[0:14:46.9] JO: Great for getting rid of ifs which I’ve actually, you know I think it is a great idea but I’m not sure I have ever seen it in the wild.
[0:14:54.7] DA: Can you talk a little bit more about that?
[0:14:56.1] WJ: Yes, the idea is that if you have a dog class and the dog class can speak and it says, “Woof,” but sometimes you want in your application for that not to be dog. Rather than having places where in your code where you check and see if the dog is there and if it’s no or undefined or in nil, then you return an empty string. You can create a second class called the no dog or the no-dog, however you want to name it in order to make it clear.
And then you give that method – you give that object a speak method and it says, “Empty string,” and so then instead of returning an undefined when you can’t find the dog, you return a no dog.
[0:15:42.9] MN: Oh interesting, so you avoid the idea of checking what it is by just asking to woof in this example and the class itself would then either return the sound or an empty string because it is not a dog.
[0:15:59.9] WJ: Yeah the idea is that your methods should always be called, like if you call speak if you are planning on calling speak then you call speak. Don’t check in to make sure that there is a dog that you can call speak on. Just call it and make sure that there’s always something that responds to speak.
[0:16:18.3] DA: Right adhering to that same contract where it is a string and it’s not returning, not or no.
[0:16:24.9] WJ: Yeah, exactly.
[0:16:26.1] JO: Right, so you can clean your client code up and you never have to be checking for random things because all of that is abstracted into your no object.
[0:16:33.4] MN: That’s cool. I mean that is a really interesting pattern and I have to say, I don’t think I have seen that in the wild either but it seems like a really good pattern to follow that I should start using if the event I need to start chopping down some ifs.
[0:16:47.1] JO: I’ve actually used it before and people didn’t like it. They were unfamiliar with it. They said, “I don’t quite get that. Why are you doing that? Why don’t you check for if-no?” So I mean, sometimes you can get that, sometimes with some objector to techniques like that, if you are not used to them it can be jarring.
[0:17:05.0] WJ: One solution to that that I found is using a library that makes it really easy. And then when people are like, “What is this? I don’t understand this pattern,” then they can go and look at the library. See that it is coming from a library and then go look at the docs and then the docs explain the pattern for you and you don’t have to justify it yourself. People also feel like – well if there is a library for it then it must be a good idea. It’s not really a good way to think about it but in this instance, this is helpful.
[0:17:31.4] DA: And sometimes you are going to left out things. So what should you do if the product or the business is coming to you with this really complicated feature and you know it is going to add more ifs to your codebase, what is a good strategy for that?
[0:17:47.4] JO: Yeah, I mean I have come across that a bunch of times where I start to look at the code and I would look into requirements and I am like, “This is going to be problematic with the current way we have things laid out. I am going to really change like I’ll weigh a bunch of things kind of work. Yet if I did this other way that I believe still fulfills like the heart of the requirement then it is going to be smooth sailing and we won’t have to do a whole lot.”
And so I think you always – when you see opportunities like that, it’s always worth pushing a little bit like you want your product owner to like you and you want to be a good person that people get along with so you don’t get much done.
[0:18:29.0] DA: That a rule, yeah.
[0:18:30.4] JO: Yeah but if you go up and you say, “Listen I think if we just do it this way, it’s going to reduce the amount of time I have to spend that is going to make the code better,” and see what they say and often, I’ve worked with a lot of product owners who are very amenable to making small changes for time savings and they go, “Oh if the code is better I guess that is good.”
[0:18:47.2] DA: Yeah, that is totally true and also like I mean they may not – sometimes they know exactly what they want but sometimes they have an idea of what they want and this is just one idea and then there is other ideas that can surface when you have that conversation. I think that we are just happy with this different thing that is pretty much the same. That’s definitely kind of a trap of like some we’re doing developers where you get the requirement and the requirement is law. And you cannot have the conversation and even find another opportunity for improvement. It’s just like, “Okay, well I am just going to struggle with this and you know add my one word statement over here.
[0:19:26.8] JO: I imagine Turbo Tax’s code base is to have 1000 if, right? That is kind of – you know they need that.
[0:19:34.8] MN: Yeah, if whatever you are married or if you are single then that is like, “Oh how many children do you have?” And if it’s more than one, do that kind of thing yeah.
[0:19:44.0] WJ: I would love to see Turbo Tax’s code base. So I think there is another remedy that I think can be helpful and that is static code analysis tools. Like Code Climate will do this. There are other tools out there that will do this where it will check the psycho medic complexity or the ABC score or other scores that will tell you in a numeric way exactly how many code pass there are and you can use that to enforce a limit.
[0:20:13.4] DA: Oh yeah especially when you get that grave in Code Climate and it’s like, “Oh see this? It’s not me but the system tells us that your code is an F,” it’s not me.
[0:20:25.1] WJ: This objective of math says your code sucks.
[0:20:28.4] MN: Data.
[0:20:29.4] DA: Yeah it sucks by ten.
[0:20:32.7] JO: Yeah, do we get a commission for that? I like that. I mean Code Climate is like -
[0:20:36.6] WJ: Code Climate should make me a commission. It’s hoping a lot.
[0:20:40.7] DA: Yeah, it is pretty nice but there are ways to measure it without code climate. It is just like a very easy way to get involved in that because I think underneath that, they are using a lot of open source tools that you can access but it’s just shiny.
[0:20:55.5] JO: I do think that those tools are sort of brilliant like spud-like lintors are very easy when we are – when you are doing code reviews or whatever. You no longer have to argue about whether there should be spaces there. The machine tells you and you can’t argue with the machine. You can bring it up to the team and be like, “I don’t know about this rule,” but for the most part people are just like, “I’ll just do what the machine tells me.”
[0:21:16.0] MN: I saved it. It formats. It’s happy, I’m happy and I think a lot of the times, I think going back to what you guys have mentioned like co-climate can definitely test the complexity and the amount of nested ifs you have and stuff like that and be able to catch it so that everyone is aware of that and then try to stop you from adding the 11th if. Not the thousand but even 11th as Jacob has mentioned before. When your spidey senses starts tingling you –
[0:21:41.0] WJ: Even a second.
[0:21:42.0] MN: Yeah, even the second, if you are nesting way too hard don’t nest at all. We get it, sometimes it’s very, very stressful for you to get this feature out. Just try not to do it. You don’t want to be the cause of a person’s death by a thousand ifs. Just don’t do it.
[0:21:59.3] DA: Jacob’s life is precious.
[0:22:00.7] MN: Yes.
[0:22:01.8] JO: I’m at 999 right now so one more if and I’m gone.
[0:22:06.3] DA: It is like the blinking heart.
[0:22:06.3] MN: So do we have any teach and learns today? We want to discuss?
[0:22:14.8] DA: Yeah, I’ve been learning a bit more about API patch nation particularly with GraphQL but the concepts associated with paginating is pretty broadly applicable. So GraphQL doesn’t really have a native pagination method built into it. It’s a “choose your own adventure”, you can do whatever you want with it. So the classic pagination technique like doing offset and limit that applies. So you can totally do that if you want to but there’s a really popular framework called Relay.
So with Relay, they give you an API like an interface that you have to implement where you can accept a cursor which is something that you are getting everything after or before and you’ll tell it a number of things that you want. So either it’s the first number of things or the first 100 things or the last 100 things that is before that thing. So either first and after or last and before and that’s how you page left or right.
[0:23:19.6] MN: Oh interesting, so it’s the number that you currently want and then anything before or after it based on the number that you want to provide it.
[0:23:27.7] DA: Yeah, exactly.
[0:23:28.9] JO: So is the cursor like a bookmark in this sense like this is where I’m at?
[0:23:33.2] DA: So advantage of that approach is that if you have a data set that is changing very quickly, you won’t have the case where when I go to the next page, I will see the same page again. If I am paging by a 100 and a 100 items were added to the beginning then than can be a really jarring user experience like you might just want to go to the next page from there.
[0:23:51.7] MN: Awesome.
[0:23:52.3] WJ: Have you ever been to a pagion?
[0:23:54.1] DA: No, what’s this?
[0:23:55.4] WJ: In the “pagion nation”.
[0:23:58.3] JO: Ah this guy. This guy.
[0:24:02.8] DA: You know I was worried about a thousand ifs but why don’t you just murder me.
[0:24:08.6] WJ: It’s very orderly though. It’s just that when I found it very opsetting.
[0:24:13.1] MN: Oh god, keep going. Oh gosh.
[0:24:18.9] WJ: All right it gets around.
[0:24:20.7] MN: Awesome. Jacob, thank you so much for coming on down. Great to have you here, how can people contact you?
[0:24:28.4] JO: People can say hi to me on the street if they see me, I am very recognizable. Other than that, you can email me, if you want to just send me an emails and we will just be pen pal emails. My email is email@example.com or you can go to my GitHub, J O’Donnell.
[0:24:52.5] MN: There you go.
[0:24:53.4] DA: I’m going to start all of your repos.
[0:24:55.1] MN: Awesome.
[0:24:55.7] JO: I’ve got a million useless repos.
[0:24:58.4] MN: Don’t worry, that all get starts tonight. Don’t worry about it. Awesome, let’s keep the conversation going on Twitter. Follow us now @radiofreerabbit. If you like what you hear, give us a five-star review, it helps developers just like you find their way into The Rabbit Hole and never miss an episode. Subscribe now, however you like to listen to your favorite podcast.
On behalf of our producer extraordinaire, William Jeffries and my amazing co-host, Dave Anderson and me, your host, Michael Nunez, thanks for listening to The Rabbit Hole.
Links and Resources:
Working Effectively with Legacy Code
Our seasoned cross-functional agilists work with you to develop technology, ship product and deliver value. We leverage our diverse expertise across industries and throughout the organizational growth cycle to your benefit. We bring best practices, emergent practices and creative solutions to your problems.