Stir: The Story of How I Built An Open-Source Java Framework

Stir: The Story of How I Built An Open-Source Java Framework

The story and lessons I've learned from building an open-source Java framework and how you can build your own passion project!


10 min read

Hey guys! Over the last couple of months, I've worked hard to release my first open-source Java framework. The framework, Stir, is a passion project I created as a complete server-side rendering solution you would use in a backend web application. In this blog post, I'll go over the challenges I've had in building it and the lessons I've learned in the design, technical, and philosophical aspects of things that you could use to bring about your own passion project!

Inspiration and Context

Oh boy! While writing out this blog post, I expected this section on the inspiration and context of Stir to be fairly short. I thought I would just give a fairly brief explanation of what brought me to work on this project and how you could draw inspiration for projects in a similar way. As it turns out, this ended up being a long but interesting story/rant on the exact details of how this idea came to be. Trust me though, you're in for a ride with this one and there are some interesting lessons here you could use (although I suppose adding in this extra paragraph as a disclaimer doesn't really help).

The inspiration I had for Stir came about through a perfect storm of circumstances and is yet very replicable in your journey. It was a really busy semester that term and so I didn't have much time to pursue my passion for building side projects or just coding creatively. Sure, as a computer science major, I did do a good amount of coding and there were some interesting assignments here and there, but it felt more like a necessity than the pursuit of a passion or a fun hobby. I guess to that extent it was like something was missing in my life at the time that I didn't necessarily pick up on. Sure, I was doing well, fairly happy, and pursuing other goals where I could but because of the workload I had it was like I wasn't able to use my fullest potential and fully be myself. Then comes along an assignment in my databases course where we got to develop a web application to interact with the database. At this point, I couldn't hold in my excitement to potentially build something nice and reminiscent of the types of large web projects I would enjoy building. We were deciding what tech stack to use here and were deciding between something in Java or PHP. At this point, I believe I was leaning more toward PHP because I felt that the way things are done in Spring with Hibernate (a Java ORM framework) and Spring Data JPA, would abstract too much of the SQL code we would use and defeat the purpose of the assignment in some aspects. However, I eventually found a way to instead use raw JDBC with Spring Framework which opened up the possibility of using my beloved backend framework for this project. I got extremely interested in taking this approach and started furiously coding a proof of concept during a lecture (which I probably should have listened to but oh well) and got something working. From there, I knew we just had to try to build the project this way and my team members agreed.

For the next week or so I started working hard on this assignment through my interest in learning new things here. As I start building off of my proof of concept, suddenly something insane and possibly masochistic comes to mind. What if ... I were to make my own mini version of Hibernate to both abstract my SQL commands into Java methods and take data from a database and convert it to simple classes. The idea blew my mind because I always found it almost magical how tools like Spring and Hibernate abstract complex logic into simple classes using annotations and the Java reflection API. If I could learn to do this myself imagine the type of possibilities it would open for me. Maybe I could build something pretty cool like my own backend framework. The thought of this deeply consumed me and I went into a full frenzy mode, coding hard for this project for long hours each day, learning more about reflection and annotation processing, and falling a bit behind on other schoolwork than I would have liked. Despite this, and the newfound stress from the deadlines and studying I would need to catch up with (which by the way, ended up being just fine ๐Ÿ˜‰) I would say it was 100% worth it from all the new things I learned, and the joy of pursuing my passions. In the end, while my Hibernate clone was admittedly a little crusty and nowhere near as good as Hibernate itself, I learned a ton more about some of the more advanced Java features I didn't know about before and had a ton of fun doing this.

After the project was finished, it was a single question I asked myself, a simple yet powerful one that you too can use to draw inspiration, that led me to the cool and ambitious idea of building Stir. The question was: "What cool thing could I build using the knowledge I just acquired?". This question has been the source of many cool project ideas I've had and certainly hasn't failed me here when it comes to Stir. Through this question, various thoughts came to my head but the one that really resonated with me was the idea of using annotations in a class to represent HTML elements that would later be generated from objects. Part of this came from what I've seen going on with Angular components and also a bit of a dislike of Thymeleaf. Nevertheless, it was from here that the idea of Stir came to fruition.

How Stir Was Built

I might try to be a bit briefer and more surface-level after that full novel on the circumstances that led to Stir and how you should follow your passion (I hope that was as interesting to you as I felt it was in my head but if I lost you by now then oh well). I will, however, try my best to give you relevant info on the tools I used and the processes I followed that you could use for your next project. Whether you are a Java developer or not, there are some useful notes here you can take from me that could increase your productivity and potentially the quality of your project.

Design Philosophy

One of the first things I would like to mention was that a good deal of the thought process that was there when building Stir was: "how can I make the best possible experience for my target audience". Thankfully for me, the target audience was myself, a Java developer. From this, I thought hard about "what would this need for it to be something I would genuinely use myself and enjoy in the process?". The answer to this led to my emphasis on trying to make as intuitive of an API as I could with solid documentation, and features to reduce the required amount of code.

While that design philosophy had great impacts on the end project, another design philosophy I had (or lack thereof) has hindered me in some ways. Part of me just wanted to add as many cool features as I could out of interest, excitement, and potentially a fear that Stir wouldn't be good enough in its niche to justify being used. This led to me almost adding totally unrelated and out-of-scope features from the essence of the framework, and design choices that did come into fruition that I admittedly question to this day.

Developmental Practices And Tooling

Project Management

Much of how I organized myself to work on this project came from the agile methodology I learned from school and practiced in my most recent internship (although I honestly slacked off from it later on as the next semester started and I began setting my eyes back to my other goals). Much of this organization came from the use of Zenhub, a GitHub-compatible project management tool I learned from a previous course. Using Zenhub, I set up different sprints (2 week periods where I set on achieving different developmental goals and working on set GitHub issues), created epics (larger goals comprised of a set of related issues), and set estimates for the amount of time for each issue (if possible). From there, I would systematically get goal after goal completed by following this schedule, creating a new branch for every issue, merging the branch when completed, and closing the issue. Following this process would give me a clear direction and keep me going by seeing one issue close after another and progress slowly but surely being made.

Continuous Integration and Deployment

Outside of this, I used GitHub actions for my continuous integration and deployment pipeline. Using the Maven Jacoco plugin (Jacoco meaning Java code coverage) along with, I was able to generate code coverage reports with a nice interface via a GitHub bot. Additionally, I used a GitHub action for continuous deployment to GitHub packages (and later Maven central) upon pushing to master or on creating a release, an action to push my Java docs to GitHub pages, and an action to run my tests upon the creation of a pull request. All of this was fairly easy to set up with just simple YAML files and a quick browse through the GitHub actions marketplace.


Lastly, I would like to talk about the practices I took regarding testing. Since the project is a library and not an application, it made it much more natural to incorporate test automation. This is because, unlike an application, I don't have anything to run but rather the end product is a set of classes, objects, and methods. The tools I used for testing were JUnit for the test setup and Mockito for creating mock objects. In general, I tried to keep my code coverage at around 80% for the classes that contained the core logic of my library. Meanwhile, for the classes meant to represent HTML elements, I was okay with a lot lower percentage because a lot of those classes were boilerplate/repetitive code like getters, setters, builders, etc that were generated by Lombok anyways. Still, I tried to add tests there for instances of the classes with all the builder fields set for future regression testing and to ensure that I did things correctly. Finally, for some of the more complex features I had to implement, I went about it using a test-driven development approach to try to simplify the process. By nature of test-driven development, I get to slowly build up functionality for that feature, test and ensure that functionality works, and iterate on it. That way, the process of implementing that feature becomes less overwhelming since I take it one step at a time and in the process get to build up my test suite.

What I learned and my Final Takeaways

Overall, there are a lot of lessons you and I can take from the experience I had with this project. On the design side of things, try to commit hard to the niche that you want for your project, not trying to overextend those boundaries and focusing more on fulfilling that niche as well as possible for your target audience. On the technical side of things, I talked about my agile processes, tools, and testing habits that are universal to any project. Lastly, on the philosophical or life skills side of things, I would say the main takeaway from this is to just pursue what you're really interested in and don't be afraid to be ambitious and passionate about things. I'm not sure how well you can relate to this but sometimes I feel like I'm not fully in tune with my ambitiousness and passion for my work because others may not relate to it, as well as just how hectic life can become. However, with this project, I was able to be more in tune with that part of me and was thus able to build something cool like this that I probably wouldn't imagine making before, all while embracing a good side of myself. By embracing this side of myself, I was able to live up to my fullest potential and achieve something pretty great which definitely made a positive impact on my confidence. With all that, I hope you could use my experiences to kickstart a super cool side project of your own and get the inspiration to follow your creative visions and passions.

If you like what you read, consider subscribing to my newsletter or following me on Hashnode to be notified of new blog posts. Also, check out my programming tutorials here.