Two Anti-Patterns To Avoid
Published 12/7/2016
In today's episode, we'll be talking about two anti-patterns you should be avoiding in your code.
Today's episode is sponsored by Linode! Head over to Linode.com/developertea or use the code DeveloperTea20 at checkout for a $20 credit towards your cloud hosting account! Thanks again to Linode for your support of Developer Tea.
And lastly...
Please take a moment and subscribe and review the show! Click here to review Developer Tea in iTunes.
Transcript (Generated by OpenAI Whisper)
Hey everyone and welcome to Developer Tea. My name is Jonathan Cutrell. In today's episode we are talking about two anti-patterns that you should be avoiding in your code. We've talked about anti-patterns on the show before, but to refresh your memory, an anti-pattern is a problem that will show up in your code and it's something that has shown up in other people's code before you. In fact, it's so common that they have names, they have common ways of being refactored. These are things that happened to people before you and part of the reason this happens, part of the reason anti-patterns become a thing is because our brains tend to work similarly and we tend to have similar behaviors as other human beings, right? So other developers, they think similarly to you and therefore they will act similarly to you. A little bonus tidbit aside from today's planned episode show notes, bonus tidbit, there are two basic types of anti-patterns, right? There's two basic types. And perhaps more specifically, two types of anti-patterns based on your awareness. There are anti-patterns that you are aware of or that you know you should be doing something intuitively, you know you should be doing something different, right? And there are others that are difficult to determine that they are even occurring. In other words, you don't even know they are happening until they become a problem. Now, this is a really interesting part of learning how to develop software is learning new ways of thinking that are not intuitive, right? The first side of this is that yes, you know, for example, that having good test coverage or having some kind of verification intuitively, you know that that is important. But it may not be intuitive to your brain to think that you should have a bunch of small files rather than one large file. That's not really intuitive. That's not really something that your brain automatically figures out. It's something that you figure out with time and with a lot of other people who are developing software learning what helps them develop software better. So think about anti-patterns on that scale. There are things that you are aware of, these known knowns or even known unknowns. And then there are things that you are not aware of, unknown unknowns and unknown knowns. And we've talked about that concept before. But let's keep that in mind as we talk about these two anti-patterns today. There are two patterns they both have the word dead in them. Perhaps this episode would have been good around Halloween. The first pattern that we're going to talk about today is dead code, dead code. This is also called lava flow code. And dead code is quite simply what it sounds like. It's code that has been left in your application. Now there are many types of dead code. There's dead code that is still actually being run but isn't really having an effect on the system. For example, you may have a column in your database where you are storing some information or perhaps it's working as a caching column but that column is never actually used anywhere in your application. Now, there are some reasons you may want to do this. You want to do a data report later on but a lot of the time we end up leaving things in place as Developer That can be removed altogether. And the reason this is so important, this is where it becomes an anti-pattern. There's not much of a problem when it comes to performance to have a few extra lines of code running. But if you have a lot of code that is either running or is commented out and isn't documented, it's the important part. If there's no way to discern the origin of this code, if there's no way to discern why it is in the system or whether or not I can remove it from the system without breaking things, well, it becomes a problem. It's very difficult especially for new developers coming into the project. And when I say new developers coming into the project, you can think of yourself as a new developer, if you leave the project for a period of time and then you come back to it. A lot of developers have experienced this phenomenon of returning to code that they wrote and wondering who in the world wrote that code. If you exit a project and go and work on a different project, a lot of that working memory is lost and you end up losing some of the intuition for the project. So if you have dead code in your project, it becomes very difficult to discern the origin of that dead code. So in other words, you may end up having three or four or ten different classes or ten different methods or ten different functions that all perform the same basic task. The same basic thing is actually going on in that code, but the problem is it was so difficult to determine which one was correct for the new developer that they just decided to write a new one. And dead code is the result of many different behavioral patterns. One of those behavioral patterns is just throwing some code in to test something out. I'm sure you've said that phrase before. I just want to try something out real quick. And so you try something out and then that code ends up staying in and it makes it into production and then maybe somebody comes along and writes a secondary method. If you have methods, for example, that are numbered, if you have a method that is named the same as a different method, but it has a number at the end of it to signify that it is somehow different from the other one, that may be a signal that you have dead code in your application. Or at the very least, things are very confusing, right? Because a number doesn't tell me much as a new developer about which one of those methods I should be using. Another example of dead code, perhaps a little bit less egregious, a little bit less damaging, but certainly could cause a lot of problems when it comes to performance is dependencies. If you're loading a lot of extra dependencies, for example, if you have a bunch of gems in your gem file, if you're working with Rails, you have a bunch of gems that are never actually being used. You aren't using any of those packages. This happens when you have multiple packages, multiple software packages that do essentially the same things. Maybe you have multiple authentication packages or you have multiple JSON parsing packages, whatever it is that you are depending on in your application. And a lot of the time, what happens is that we will add these dependencies, we'll start using them in our code, then we'll decide that we want to try a different dependency. So we'll add that dependency as well. The problem occurs when you don't remove the previous dependency. So then you have a long list of dependencies and sometimes, hopefully not very often, but sometimes if you have two or three different packages that have similar jobs, they have similar purposes, sometimes those will even have name collisions in your different various namespaces. So especially, for example, if you have a particular brand and they have released multiple versions of, let's say, an SDK, you could possibly have name collisions there as well. So there's a lot of good reasons for cleaning up your dependency management as well. So how can you avoid having a bunch of dead code in your system? Well, we've talked about test-driven development quite a bit on Developer Tea in the past. And despite how you may be doing test-driven development, there are ways that you can use test-driven development to help you remove dead code. Specifically, take a look in whatever language you are using at coverage detection options. For example, for Ruby, there's simple cove. And what that does is it allows you to determine how much of your code base has been covered. Now, what you will find out is that if you start replacing some of that old dead code, or if you stop using some of the old dead code, then you will actually see that that percentage is going to be lower, right? Because a lot of the code that you were using before is not actually even getting hit in your tests. Now, what this can't do is it cannot determine which of your tests is no longer needed. You may have tests and coverage, you may have actual code and coverage in your tests for that code. And it could be old and dead and not actually needed in your application. So that's something that you're going to have to stay on top of yourself. Now, how does that work? Well, a lot of the time what we will end up doing in our coding practice, we will go through and add new things. And instead of removing the old thing, we either comment it out or we just leave it in place, right? And that is the practice that has to stop. A good refactoring process, it includes changing and deleting the old code that you're refactoring. So building an application is almost as much changing existing code as it is adding new code. And hopefully there's quite a bit of deleting code as well. So be vigilant about this. It's very important that you stay on top of deleting old unused code, deleting old unused parts of your databases, deleting dependencies you no longer use and deleting tests that you no longer need. That's the first anti-pattern that I want to talk to you about today. We're going to talk about our sponsor real quick and then we're going to talk about the second anti-pattern. This episode is sponsored by Linode with Linode, you can get an SSD server up and running in just a few minutes. Some of you may not know this. A good portion of what Developer Teadoes actually relies on Linode, a lot of our hosting services actually run through Linode. So it works at scale, but it also works for those of you who are just getting started in development. There's quite a few beginners who listen to the show. And it's never too early to get started with a server. A lot of the skills that you will gain by getting a server up and running, they will stick with you throughout your coding career. It's just a lot of fun to have a server. Honestly, to build something and put it up on the internet or make it accessible in a remote location, it's a ton of fun. On top of that, of course, you get root access to these servers. They're built on Linux. I'm sure you've heard of it. But if you haven't, obviously Linux is running pretty much all of the web. So go and check out Linode. They have incredible plans, incredible pricing. $10 a month is their starting point. And that gets you two gigabytes of RAM on a server. So go and check that out, spec.fm slash Linode. Oh, and by the way, they're giving you $20 of credit if you use the code Developer Tea 20 at checkout. That's $20 of credit. That's basically two months on that entry level plan. To go and check it out, spec.fm slash Linode. Thank you again to Linode for sponsoring today's episode of Developer Tea. The first anti-pattern that we've already talked about is dead code. The second anti-pattern that I want to talk to you about is called dead end, dead end. More specifically, we're talking about the dead end component. And hopefully you've experienced this before. If you have, you will immediately recognize this anti-pattern. It is not necessarily intuitive. We talked about this earlier that some anti-patterns are somewhat intuitive. Having dead code in your application, it kind of feels like you haven't cleaned up your house. It feels a little bit dirty. It feels like you need to straighten things up, clean things up, get some stuff out of the way. So that one's a little bit more intuitive. The dead end component though, that's actually a less intuitive anti-pattern. What a dead end component is, if you have some software that you are depending on, right? So let's say you work with WordPress, and I actually experienced this one recently. You work with WordPress, and you bring in a theme or a plugin from an external developer. Your client asks you to install that theme, but then they want you to bring in a component from a different website. In this particular case, they wanted us to install a theme for their blog and then bring their nav over from their main website. So they have a blog theme, but they want the nav from their other website brought into this theme. Now the interesting thing about software, and depending on other people's software, is that you get a lot of value out of depending on other people. And so software is incredibly valuable. You all know this. Having plugins that you never had to write, all you had to do is click install. That is a lot of value with very little effort. Now, the trade-off is that that software is not always going to be exactly what you need, right? This is a very common problem in business. When you have a non-custom solution, the things that are specific to your problem may or may not be fully addressed. This is the concept of off-the-shelf versus customized software, for example. So that is a problem that you're going to face. Now what happens, the dead-end pattern, what happens, is when you choose to modify those things that you were depending on. So if you added that nav to that theme in the WordPress install, or if you go through and you patch different pieces of code, especially if you modify the actual source rather than laying monkey patching on top, for example. Even that can go wrong, but if you're modifying the source that you're depending on, then you are creating a dead-end. Now what does that mean? Well, most of the time, the software that you depend on will receive updates in the future. Whether that's stability updates, maybe it's compatibility updates, maybe it's safety upgrades, or it could actually be in brand new features. It could be newer, better, faster things that the original developer of that software decided to add to that software. Now the problem is, if you have modified, let's say you're on version 2, if you modified version 2 and they come out with version 2.1, the problem is that whatever their changes are, they could overwrite your changes. In other words, your changes are not necessarily going to be easily merged with the original developer's changes. So in this way, you've created a dead-end because you no longer get to see the benefits of that ongoing development of that software. Now perhaps what's even worse about a dead-end component is that all of the responsibility is now entirely yours. Think about that for a second. If you go through and you modify a plugin or you modify some kind of package that you've brought into your project, if you go through and modify it and you create a dead-end where the original software maintainer no longer can add changes to that. You can no longer bring down their changes and add them to that project. It is now your responsibility to implement those safety upgrades, those security and performance upgrades. Those feature additions. And again, this doesn't necessarily immediately click with our brains. When we see something wrong, we think, oh, we can fix that. We know exactly what's wrong in that piece of code. Again, the problem with this is that once you go in and modify that underlying structure, you've now created your own branch of that software effectively. And if the original developer doesn't have access to that branch, they can no longer continue developing on that piece of software. This is why it's so important to take those changes that you've made, especially if they are, you know, globalized things. For example, if you find a bug in some software that you depend on, then you can take that bug, take the fix that you've applied, and contribute to that project, if it's an open-source project, or send the information to the original developer. This allows you to stay in that future loop. In other words, you aren't creating a dead end when you bring your changes into the open-source sphere. So a quick recap are two anti-patterns for today. Dead code and dead end. Dead code is code that is unused, whether it's commented out, or it is simply just sitting in your code base. It's being run, but it's never actually needed. And end is when you take a component that you are relying on in your application that is built by an external developer, someone else, whether that's open-source or not, and you modify that underlying code. This creates a dead end in your code because you can no longer take new updates to that underlying component and apply them. Thank you so much for listening to today's episode of Developer Tea. I hope you've enjoyed this discussion on anti-patterns. Of course, anti-patterns and design patterns for software is a never-ending discussion, and we will continue talking about this in the future on Developer Tea. If you want a server in the cloud, if you want an SSD server in the cloud with two gigabytes of RAM, and you want 20 bucks for free, go and check out spec.fm slash linode. Remember the code Developer Tea 20 at checkout, and you'll get that $20 with your credit. Thank you again for listening to today's episode, and until next time, enjoy your tea.