Reflections on Trade-Offs
2024-12-21
About Trade-Offs
A trade-off is simply the process of deciding what you give up in exchange for what you get.
Trade-Offs in Software Development
(1) Performance vs maintainability
- Applying complex algorithms or optimizations for high performance makes the code harder to read and increases maintenance costs.
- Simple and clear code may sacrifice performance, but it is more stable and scalable in the long run.
(2) Time vs. quality
- If you need to get to market quickly, you should choose rapid development, even if it means incurring technical debt.
- If you prioritize quality, it may delay your release or consume more resources.
(3) Monolithic vs Microservices
- Monoliths are simple and quick to deploy initially, but they are limited in scalability and flexibility.
- Microservices are extremely scalable but have high initial complexity and high management costs.
The Trade-Off of FastAPIs
I've been developing with Flask for a long time, but for this blog project, I decided to skip Django in favor of FastAPI. I chose FastAPI over Django for the following reasons
1. similarity in structure and features with Flask
2. I didn't like Django's strict rules
3. faster initial development speed than Django
As it turns out, all of these reasons were double-edged swords and trade-offs. I was able to implement the MVP without much difficulty thanks to the structure that is more similar to Flask than I thought, but I was faced with the same circular import problem that I experienced in Flask.
What is Circular Import?
- Module A references module B, which in turn references module A.
I'll attach the case I actually encountered
Traceback (most recent call last):
File "/Users/cliche/Desktop/project/backend/app.py", line 4, in <module>.
from utils import main_logger as logger, scheduled, check_data
File "/Users/cliche/Desktop/project/backend/utils.py", line 4, in <module>
from models import AppleMusicChart, YouTubeChart, SpotifyChart, db
File "/Users/cliche/Desktop/project/backend/models.py", line 1, in <module>
from app import db
File "/Users/cliche/Desktop/project/backend/app.py", line 4, in <module>
from utils import main_logger as logger, scheduler, check_data
ImportError: cannot import name 'main_logger' from partially initialized module 'utils' (most likely due to a circular import)
- app.py references utils.py and
- utils.py references models.py
- models.py references app.py
- app.py again references utils.py
As you can see, it's a terrible structure, and it's the result of building a structure for fast development with a shallow understanding of MSA concepts.
Moreover, the project used Flask-SQLAlchemy, not SQLAlchemy, so there were strong coupling issues such as context dependency with Flask, so in the end, I did one major refactoring and switched the framework to FastAPI.
The story is a bit old, but the way I solved it was really dumb, and I solved it by moving the db declaration in #3 back to models.py, not importing the logger in #4 at the beginning of app.py, and using lazy imports where necessary, which is not an inherent workaround, and I don't have a big enough project where the performance overhead is an issue, but I can definitely see that it makes the code dirty.
The similarity between FastAPI and Flask is that they are micro-frameworks rather than full-stack frameworks like Django, which gives you more flexibility and freedom, but to put it another way, while Django has strict rules and organizes the right structure for you, FastAPI requires you to design the structure and take full responsibility for it.
My mentor had a lot to do with me adopting an MSA structure instead of a monolithic one, and I didn't know why at first.
Isn't it just easier to have all the code in one file? Isn't it also work to divide it up? Isn't it annoying?
I think I was more frustrated because at that time, the code was no more than 300-400 lines long with all the features, and every time I split something, I got an error.
But as the project got bigger and bigger, and I started using a lot of different libraries with a lot of different features, the code started to get ridiculously long. In fact, I realized the benefits of MSA the most when I was working on the crawler project in the example above, but as you can see in the code above, the crawl code was divided for each site, and the utilities were kept in separate utilities, and I realized that it was too easy to fix when something broke.
However, I still don't have much understanding of MSA or design patterns, so I suddenly realized that when I was looking for it to study it.
I wonder if the freedom and flexibility of FastAPI would be diluted by introducing design patterns or boilerplates to formalize it and make it different from Django.
I asked several AIs (o1, Claude, Perplexity) this same question.
Almost all of them answered similarly
It's a trade-off that's often discussed among FastAPI developers, and the most important thing is to find a balance.
And the answer that resonated the most with me was Claude's
To me, it's more of a "codification of freedom" than a "loss of freedom".
There is still freedom of choice when applying a design pattern, and there is still flexibility in applying the pattern.
There are still degrees of freedom in structuring the code.
In other words, the adoption of design patterns or boilerplates is more of a "guideline" than a "constraint", similar to how developers follow coding conventions. Having a convention doesn't take away your programming freedom, but rather helps you write more organized and cleaner code.
In the end, it's all about finding a balance, depending on the size of your project and your team.
- Small projects: take full advantage of FastAPI's flexibility, and apply minimal patterns.
Medium: apply patterns selectively and only where needed
- Large projects: apply patterns systematically
It seems like a good idea to be flexible in this way. What do you think?
Maybe this is just AI ranting from a non-practitioner, but it resonated with me the most and made me realize that I've been overthinking things, and that I don't think there will be a place for junior developers in a few more years, if not now.
Comments 1
Login required to write comments
Kakao
Google
Naver