When I was one year into the journey as a full time software developer, I had the idea of making a blog site to keep track of my learnings. In my vision, the blog system should support draft and public stage of posts and has an editor that can support inserting images, text and code. It was such a simple side project yet I deviated too much from the original goal and eventually made a system too complicated to use.
Years later, I found peace in static site generators. I confess I was not impressed with sites built with those tools before partly because I thought if I can build something from scratch, then why not? The simple truth is just because one can does not mean one should. So here I am today reflecting on what went wrong in my first attempt.
An ambitious start
My initial plan was simple, I just need to
- design and code the blog site
- design and code the management panel
- setup frontend hosting
- design and code the backend
- setup backend hosting
- setup database and design database schema
- setup static file storage for images and videos
- setup traffic analytic
- get a domain
Setting up things and wiring them together were not inherently difficult tasks. Had I stick with this plan and use simple solutions I would probably still be happily using my own blog system today. Unfortunately I made too many detours, including but not limited to
- attempted to customize an open source editor and gotten lost in its giant code base
- built my own management panel on top of a UI framework
- attempted to adopt domain driven design and complicated the system
- rolled my own ORM
- diving too deep into technical nitty gritty
I went on to setup a bunch of AWS cloud services, purchased a domain and finally published my app. The whole journey was not smooth and I hit errors in nearly every step. The experience is especially agonizing when I knew my goal was so simple.
After lots of struggle, I finally got the site to work except it has a semi-finished management panel, shaky DDD and ORM implementation. No proper CI/CD pipeline and database backup in place. I felt so exhausted and decided to take a break but then it was a break too long. The blog went unmaintained and unloved. How funny that the focus on technical details was the very thing that killed a blog site meant to talk about them.
Know when to pause and what to prioritize
I think the problem comes down to the prioritization of subtasks. Breaking down a major task to subtasks is just the first step. What is more challenging is to see these subtasks to full completion. To succeed, one should resist the temptation to dive too deep into things other than the original task (or wonderfully termed yak-shaving) and be aware of the often overlooked cost of information foraging.
Subtasks are bite-sized mini projects meant to be built quickly. It is sometimes tempting to work beyond the scope of these subtasks. For example, renaming variables and refactoring any code that caught your attentions while working on a feature. Or get diverted into rolling a bunch of utilities (poorly tested) instead of using well known tested solutions. Before you know it, the subtask becomes a complex project of its own. If there is truly any potential in these subtasks, you should simply take note of them and move on before delving too deep to unwind. You can come back later to revisit and evaluate objectively the costs and benefits of realizing those potentials. If sometimes a missing piece is so fundamental that you can’t just move on. Before jumping to roll your own solution, you should search at your best effort for already matured solutions or best practices. If you found nothing satisfactory after exhausting all options, then congratulation to you because you might have just found an uncharted problem domain. Whether or not you should pursuit it is another topic for discussion.
A research showed that 50% of time in a day of a developer was spent on foraging information from various sources. (In my own experience, digesting and reformulating these information to produce step-by-step solutions take another big portion of time.) Only a lesser amount of time is spent on the implementation. Based on the rough estimation about my own development work, I spent 50% of time on information collection, 30% of time on digestion and 20% of time actually writing the code. These activities can happen in any order, very much like our ancestors foraging, eating and growing muscle all at any time. But this foraging process can be dangerous sometimes because we could lead ourselves into the rabbit holes, one problem after another as if the next link will have the answer. While we are furiously searching for solutions, our mind go full problem attacking mode like a warrior so determined to fight to death except for the wrong battle. Our attention gets narrowed down to the specific setup of our problem and we ignore the context of the solutions by others, grabbing every solution thrown our ways without examining them carefully. Eventually we got frustrated if none of the answers work. I believe at this point one should immediately close all tabs, take a deep breath and revisit the problem before the project is full of blindly copy-pasted codes. Then we should ask ourselves what are the missing knowledge here? Have I read the documentation? Am I really using the correct API? What are the assumptions I made about other people’s working solutions? Unfortunately when our mind is caught in stubborn momentum while searching for answers, it took lots of mental efforts to break away from this vicious cycle.
Knowing the problem is the first step to overcome
Frankly I’ve learnt a lot from my first blog system. If I had to do it again, I probably would have the same urge to diverge at various stages of development but this time I will be very aware of when to pause and what to prioritize.