🎙 Develpreneur Podcast Episode

Audio + transcript

The Swiss Army Knife Anti-Pattern

In this episode, we discuss the Swiss Army Knife anti-pattern in software architecture. We explore how it's the opposite of microservices and how it hides complexity beneath a simple facade. We also discuss how it's hard to maintain and debug, and how to avoid it by asking what if questions.

2022-02-18 •The Swiss Army Knife Anti-Pattern in Software Architecture •Podcast

Summary

In this episode, we discuss the Swiss Army Knife anti-pattern in software architecture. We explore how it's the opposite of microservices and how it hides complexity beneath a simple facade. We also discuss how it's hard to maintain and debug, and how to avoid it by asking what if questions.

Detailed Notes

The Swiss Army Knife anti-pattern in software architecture is a design approach where a single component or solution tries to do everything. This approach is the opposite of microservices, where everything is separate and pluggable. The complexity of a Swiss Army Knife is hidden beneath a simple facade, making it hard to maintain and debug. When a Swiss Army Knife is broken, it's broken, and it's hard to identify the problem. This approach also leads to tightly interwoven functionality, making it hard to change or enhance. To avoid the Swiss Army Knife, one should ask what if questions, such as what if the functionality breaks, what if we need to enhance it, or what if a user doesn't want it. This approach can lead to a ball of duct tape and bailing wire, making it hard to maintain and debug. In summary, the Swiss Army Knife anti-pattern is a design approach that should be avoided, and instead, one should aim for a modular and pluggable architecture.

Highlights

  • The Swiss Army Knife is an anti-pattern where a single component or solution tries to do everything.
  • It's the opposite of microservices, where everything is separate and pluggable.
  • The complexity of a Swiss Army Knife is hidden beneath a simple facade.
  • It's hard to maintain and debug, as you have to sort through a lot of intertwined functionality.
  • Avoiding the Swiss Army Knife is easy, just ask yourself what if questions.

Key Takeaways

  • The Swiss Army Knife anti-pattern is a monolithic solution that tries to do everything.
  • It's the opposite of microservices, where everything is separate and pluggable.
  • The complexity of a Swiss Army Knife is hidden beneath a simple facade.
  • It's hard to maintain and debug, as you have to sort through a lot of intertwined functionality.
  • Avoiding the Swiss Army Knife is easy, just ask yourself what if questions.

Practical Lessons

  • Avoid designing a monolithic solution that tries to do everything.
  • Break down the architecture into smaller, separate components.
  • Ask yourself what if questions to identify potential problems.
  • Modular and pluggable architecture is better than a Swiss Army Knife.

Strong Lines

  • The Swiss Army Knife is an anti-pattern where a single component or solution tries to do everything.
  • It's the opposite of microservices, where everything is separate and pluggable.
  • The complexity of a Swiss Army Knife is hidden beneath a simple facade.

Blog Post Angles

  • The Swiss Army Knife anti-pattern: a threat to software architecture.
  • Avoiding the Swiss Army Knife: a practical guide.
  • The benefits of modular and pluggable architecture.
  • The dangers of monolithic solutions.
  • A case study of a successful modular architecture.

Keywords

  • Swiss Army Knife anti-pattern
  • software architecture
  • modular and pluggable architecture
  • monolithic solution
  • microservices
Transcript Text
Welcome to Building Better Developers, the Developer podcast, where we work on getting better step by step professionally and personally. Let's get started. Well, hello and welcome back. We're continuing our season where we're looking at patterns and anti-patterns for software architecture. We have started out with the positives and looked at the patterns, and now we're diving into anti-patterns. In this episode, we are going to talk about the Swiss Army knife anti-pattern. Now when we get into anti-patterns, we're going to see a theme very similar, or I guess it's more like the opposite of what we saw with patterns. Even in patterns, one of the goals was to take a big problem and break it into smaller, more manageable problems. The anti-patterns will in many cases be the reverse. We will take little problems, roll them all up, and now we're back to a big problem. The Swiss Army knife is one such anti-pattern. And I guess to step back a little bit, what is a Swiss Army knife? Well if you don't know, the Swiss Army knife is those things you'll find, those knives you'll find in stores and such, where it's not just a knife. It's got a knife, it's got scissors, it's got a file, it may have a little saw, a bottle opener, it may have a little magnifying glass, it's all kinds of stuff. There is everything you would possibly want packed into this one knife. So that is possibly useful. There are cases where you say, wow, I want this one thing that I'm going to carry with me and it can do everything. In software, not so much. In particularly solving a problem. It doesn't make as much sense to be everything to everyone essentially within a single component or a single, even sometimes a single solution. This is not quite the same as the design by committee anti-pattern. Because in that case, you have everybody adding something in. It's more like bells and whistles. This is a little bit more intentional, where you take into account a lot of things that might happen or it could be useful to do this and you make sure that you include that. It's not necessarily bells and whistles as much as it is addressing more outliers and maybe making a more, essentially a more general solution as opposed to a specific solution. There are cases where you might want to do this in your architecture, but really not too many. It's really hard to come up with one. If you want to build a product that is everything to everybody, that's one thing. But even then, it's probably going to be a suite of products. If you think of, probably the best known one would be like Microsoft Office. You've got a word processor, you've got a spreadsheet, you've got all that stuff, but it is separate applications. In an architecture, even more so, we want to be able to see what the parts of the architecture are. It should not be some big monolithic black box that you just throw stuff in and something magically occurs and then something gets spit out. Within an architecture, we want to make sure that we, and this actually goes back to object design. If you want to go back to the object oriented patterns and any patterns, we looked at very similar kinds of things there. We don't want to do everything in one location or one component because one, if you change any one piece, that means you affect the whole thing. As opposed to when you break it up, sometimes you can make little changes here and there and it doesn't impact the entire system. It doesn't force you to retest everything. If you've got one monolithic piece, that's what you get stuck with. Maintenance becomes a little harder because you know the component that's broken, but you may not necessarily know where in that component it is. You may have more stuff that you have to sort through to figure out where the bug occurred, where the problem code lies. The Swiss Army knife is that anti-pattern. It's where we try to do everything, put it all into something that on the surface is very simple. It's like, hey, it's one object or hey, it's a very simple, straightforward architecture, but that simplicity is really just a facade that hides underneath a lot of very complex things that are going on. That abstraction may be good for a user or for an end user, but not necessarily for somebody that's trying to implement within that architecture. If you've developed for long, then you've probably run into, particularly if you're doing integrations, you run into the situation where you are frustrated with what you know behind an API wall or some sort of integration wall that's there. They provide you an interface and you don't really know what's going on and you may not have access to data or results or statuses that it would be very helpful to have. For example, bug reports or exceptions. Things that may give you more information about why your code doesn't work. There's the rub and there lies the problem with this sort of approach. With the Swiss Army knife, if it's broken, it's broken. If you think of a Swiss Army knife, yes, because you can sort of use different pieces. If you break the knife blade, then technically I guess you could use the other pieces because it gives you access to those other pieces. But if you need a knife, then that thing becomes useless to you. Yeah, all those other things are great, but that either means you have to go buy another knife and so now you have the Swiss Army knife that doesn't have a knife and a knife or go buy another Swiss Army knife. Now if you are trying to sell products and maybe that works for you is that you force your customers to just go buy a new version. But typically that's not user friendly. They're not going to like that. At some point they're going to say, hey, wait a minute, that's not a good design. I don't want to have to rebuy this whole thing just because of some little problem. And although that's not quite a perfect analogy for software, more so it goes to testing and building. If I have a bug in the system, I don't want to have to go into the whole thing to be able to figure it out. And with really large projects, and you can think about it, if it's a huge project with thousands or tens of thousands of files and objects and things like that, you don't want to have to sort through all of those to figure it out. You want to be able to hopefully get to hundreds or dozens or single files that have what you need. That is the maintenance cost of this approach, of this anti-pattern, is that you don't really probably don't really know where things are broken. So you're having to sort through a lot as opposed to when you break something up into smaller pieces, it's a lot easier to find out which piece is broken and then go address it there. Go fix that, update the piece within your system and you're off and running. Swiss Army Knife is in many ways the complete opposite of a microservices pattern. Instead of having a lot of little things that do all the work, this has one big thing that does the entire work. And so there is no way to plug and play, there's no way to do anything other than interact with this big monolithic thing. And while you may have, you may try to get around this by having a lot of interfaces. So think of a black box that has one or two buttons and then maybe a little output slot. That doesn't provide as much maybe as a black box is covered with buttons and it's got eight different output slots. But think about that box with all those buttons, that's just a pain to deal with. Trying to figure out which button and to make sure you don't hit the wrong button is not only an overly complicated interface, it is also something that becomes a pain to maintain because you have to figure out which button ties to which piece of circuitry or whatever, which button or what interface goes to which piece within that architecture and then where does that lie? And of course, when you're doing an all things for all people or Swiss Army Knife, you end up having a lot of intertwined functionality within that architecture. And then you get into the whole, almost like a stack of dominoes kind of thing where you, you know, the dominoes start falling because you change one, but then that affects something else and then that affects something else. And next thing you know, you're deep into code trying to unravel the spaghetti that is the design, the architecture. And it's not quite, even if it's not spaghetti, even if it's well designed, it's still tightly interwoven. You think if there's, if you have a mess of cables, a bunch of wires and they're all plugged into stuff, but there's no separation of them, then if you're, you know, especially if you're trying to get in from the middle, trying to figure out which, which, you know, cable or which wire is broken, then you have to track it all the way down. It's just, it's a pain. That's the problem. Along with, it goes against one of our key, I guess, best practices as we look at them. When we look at patterns is let's try to take the big things, simplify them, nail that simpler problem and then move forward and then pull it into the overall solution. That allows us something that is much more manageable to build, to test, to verify, to integrate and to put into our system. And so with an architecture, we definitely want that. We want to be able to examine the architecture in components as opposed to just have to look at this one big thing and understand it completely. When we have smaller applications, it may not be a problem. It may or I guess it may not be a problem at all because it could be that your problem is small enough that a single architecture works fine. That you can do one object, it builds it. You've only got a couple of things you're doing, you're off and running. But as things become more complex, this becomes more and more an anti-pattern. And so you'll see this if you want to, if you're wondering, have I built this or am I working in this? One of the ways you're typically going to see it is that you're going to see it as this big box. You're not going to be able to see components or pieces or parts of the architecture. It's basically, think of maybe like the bus or the core that we've talked about with some of the patterns where you have this core and that's it. You put stuff into the core, it does a bunch of magic and it kicks something out. You don't have different ways to get into it and the core does a lot. It's usually going to have a lot of side effects. It's going to have a lot of maybe magic numbers and things that you feel like there's black magic involved in getting anything done. A simpler example of where you would see this would be a relational database where there's a single table, but it's got maybe dozens of columns or maybe hundreds of columns. And the complexity is made worse. And maybe it looks simple because like, hey, there's just a table. It's got a lot of columns, no big deal. But it becomes complex because there's all these things that sometimes are there, sometimes they're not. They may be calculated. They may rely on the values of other fields. There may be a lot of self-referencing things so that you really have to almost unravel or decode the data that's in there. That's not very useful for an architecture, for maintenance, for testing, debugging and enhancing something. It becomes almost like a ball of duct tape and bailing wire and it's just not pretty. So you'll see this often as something that seems simpler at the top. When you look at it, it's like, oh, OK, it's a very simple thing. But when you look at it, you realize there's a lot of stuff it's doing and I don't really see that. I just have to trust that it's doing it. That's when you're running into most likely a Swiss Army knife. Now, avoiding it is sort of easy in a sense, much like we deal with wondering whether or not we want to pull in like a bell or whistle or some feature. So the same thing with the Swiss Army knife. We look at with this architectural decision, what matters? Where does this need to be? You sort of ask a what if. So here's a piece of functionality. What if it breaks? What if we need to enhance it? What if a user doesn't want it? You ask some of these what if questions and it's not so much at this point, it's not so much answering the question as realizing, do we even have a way to deal with that? In testing, it would be what if there's an error that occurs in this functionality? Do we have a way to report the error and also to pretty in a precision way, dig into it and fix the error, determine what actually is broken and what do we need to do so that it is corrected? It really comes down to look at the architecture and think about, do I would I want to have to enhance or change this? Or do I see a lot of research that's going to be needed to get that done? Now we're going to see this other anti-patterns. We will see where our anti-patterns often point us to a solution that maybe is quick and dirty, but in the long run becomes very costly to deal with, whether to enhance it, to maintain it, to debug it. This is one where we're just saying, let's just throw it all in. We're not going to worry about breaking down the architecture. Instead, we're going to just throw it all in there, everything in the kitchen sink and then that's the solution. And it's not really a solution. Thus, it's an anti-pattern. That being said, I think we can wrap this one up. We'll finish our discussion of the Swiss Army knife and we will come back and talk about some more anti-patterns in the episodes ahead. But as always, go out there and have yourself a great day, a great week, and we will talk to you next time. Thank you for listening to Building Better Developers, the Develop-a-Nor podcast. You can subscribe on Apple Podcasts, Stitcher, Amazon, anywhere that you can find podcasts. We are there. And remember, just a little bit of effort every day ends up adding into great momentum and great success. Here we go. Well give it up for Rob, he's my new best friend. I think I love you and we haven't even met so I thought I'd write a little song for you because I think that you're so damn cool. California born, Memphis raised, but Nashville's aware he likes to spend his days. That hockey rink is where he likes to be but he's dying to head to Italy with Tim, Ian, Ben, Beckham, Tom. Where he can stare at the stars all day long. He can eat that pasta till he passes out. Well I love you Rob, I think there ain't a shadow of doubt. Come on, so I said give it up for Rob, he's my new best friend. I think I love you and we haven't even met. I want to say thank you for having me on your show. Cause this friendship of ours is one that can only grow.