Design Antipatterns
Over the past several months, I’ve gained a ton of software development experience thanks to my co-op as a backend software engineer and some personal projects. Out of all the things I’ve learned, the most impactful insight I’ve gained is something less tangible than knowledge about specific frameworks or applications. Rather, it’s something more meta and overarching.
With my new experiences, I’ve had to write a lot of code from scratch. As I go through this process of planning and writing code more often, I’ve noticed that it takes me way too long to actually get typing on my keyboard. To some, that might sound admirable since I’m probably being very thorough, carefully planning everything out and UML-ing like it’s nobody’s business. But, I can only wish that were the story. (Even if it was, at some point you just have to start coding because things, more often than not, don’t go as planned - you can’t anticipate everything.) In reality, I spend a lot of time chasing design concerns around in my head before I start anything. Here’s a pertinent example:
For one of my web apps, I decided to use Flask for the first time. It was recommended to me by many people for being flexible and lightweight. While these might be desirable traits to an experienced programmer, it was a death sentence to a beginner like me. It seemed like every tutorial and example online had a different way of organizing their apps. I spent countless hours sifting through YouTube and StackOverflow, aggregating the supposedly best design practices. I cannot stress how long this process took, all before I even wrote a line of code. Worse yet, when I finally started coding, I found myself going back to the examples only to find more flaws in my original plans: I wasn’t using an app factory; I didn’t make separate config objects for different environments that pulled from a .env; I didn’t use blueprints. Eventually though, I finally finished my implementation. But to top it all off, after taking a good look at my progress, I realized that I didn’t need ANY of the bells and whistles I implemented. At the end of the day, my Flask app belonged to a tiny personal project–it wasn’t going to be scaled, expanded upon, or worked on by anyone else. Although I learned a lot about Flask, anyone would find a hard time defending my process.
This example was only one of many. It didn’t even cover my obsession with applying design patterns. As you can imagine, this process is extremely unproductive, especially given that it happens all before I start typing anything.
After some introspection, I discovered a common theme among all my experiences building programs: a desire for correctness. I’ve always felt like there has to be a correct way to design and program something; if I don’t do it “the right way,” then the result is unacceptable. But as I’ve come to learn, in practice there’s rarely ever a singular correct (at least as I define it) way to program something. When you code in the real world, there are a plethora of external factors to consider: time deadlines, teammates, and perhaps most importantly, purpose. Prior to this year, I only ever coded in a school setting. In such a setting, the only purpose your code serves is to be graded and scrutinized in the context of your classwork. There’s always going to be a correct answer: Did I apply this week’s concepts? Did I follow the class’s code style? Did I test all my functions? But coding for a company or for a personal project is completely different. Instead I ask myself: Is this just a proof-of-concept to throw together quickly? Is this code ever going to be expanded upon by myself or others? Is this sufficiently maintanable? Based on those answers, my approach to programming should be vastly different. For example, if I need a quick POC, it’s surely quicker to hack something together than to mentally work out viability and design. Unfortunately for me, even though I should be approaching the problem differently, I still find myself thinking about design patterns for code that doesn’t even exist. I’ve fallen into a “design antipattern,” doomed to wasting disproportionate amounts of time to design concerns whenever starting new code.
Before getting into fixes, I want to explore how this behavior came to be. As I alluded to before, school played an important role in this mindset. I’ve trained myself to obsessively seek the right way to do something, which on paper sounds like a good thing. However in real life, the definition of “right” changes based on context, a novel concept to someone who has learned how to “school.” A relevant observation that supports this is how I’ve been taught design patterns. It’s always in the context of a contrived example where its application is obvious and clear cut. Yet, when it comes to real world code, it’s rarely as blatant as the examples they show in class. As a result, I often spend too much time thinking about the suitability of all the design patterns I think could apply for my situation.
But I’d be remiss if I didn’t also attribute some blame on my personality. I’m uncomfortable with uncertainty, which drives me to think ahead about all the possibilities no matter how unnecessary or uneffective it is. I have a flawed belief that this behavior will save me from many facepalms and time-consuming 180s, but these things usually happen anyway.
I know this will be a hard habit to break, but I think it will happen over time regardless of how self-aware I am. See, I have no doubt that experience is the remedy to this antipattern. As I encounter new problems and develop more, I’ll get a better intuition of the “right” thing to do in any scenario. I’ll be more comfortable with the uncertainty that comes with starting a new project or new code. At that point, I won’t feel the need to devote time and brain power to obsessive mental planning. In the meantime, I can actively improve by being mindful of how I’m spending my time when planning new code.
I don’t know how common this problem is, but thinking about my development process has been enlightening and helpful - I encourage you to try it too if you haven’t already!