Before we joined, Markforged was having more software on their hands than they could handle. Users needed more features, but factors like the old code base, and not enough senior technical members in key teams, made that difficult.
The software was broadly used, but there was a need for more manpower to meet expectations.
Markforged was also about to go public and expected to grow very quickly. They needed something that would increase their software output and increase overall quality. So, a good foundation and readiness for the changes were necessary for the company to stay on top.
When we entered the Eiger Team, we found a small team of 4 (maybe 5) people and a 7-year-old code base, written in CoffeeScript.
- The foundation was all under Node.js, using AngularJS.
- The testing infrastructure was something that needed much care. Multiple frameworks had been used, and the code coverage was low.
- Authentication and file storage were handled with AWS.
- Managed PostgreSQL was used for data storage, which was able to handle the required load.
- The deployment infrastructure was in CircleCI, which was handled properly. We saw many opportunities in this area, which would bring the CI/CD processes to the next level.
- All this was running in a production environment under Heroku. However, this was about to change since there was already an initiative to use Kubernetes.
- Process-wise - there wasn't much legacy burden. Which was great, since we prefer to build this type of foundation where it is welcomed.
First, we needed to prove ourselves worthy.
You never get a second chance to make a first impression. So, we had to show our full potential, right from the start. The very first thing we've been assigned to do was to implement a feature called Print Backlog.
The goal was to finish that with high quality and in a short amount of time. And that's what we did!
After that, we were in the right position to be proactive.
There is an unwritten rule that we believe in: "You don't make major changes in a project in your first day/week/month". We also believe that if you are good enough and you introduce significant changes incrementally, you can win the trust of the team.
And that's what we did! And it was a success. It's why we introduced Jest.
You can't make quality changes without a good testing infrastructure!
Oh yeah, we believe in that!
Markforged was using Karma and Jasmine as their front-end testing frameworks, but they deserved something better. The engineers needed something better! We combined what was already in place with testing library, which was all the rage at that time. Jest was introduced without any friction and it was quickly picked up by all engineers. We even integrated all that with their critical deployment pipelines in CircleCI.
All this was also going to support our next big initiative...
It's hard to hire someone in 2021, with AngularJS being your primary front-end framework. It's an old framework, nobody chooses it anymore, and it just fades against its successor Angular or React.
Furthermore, AngularJS was facing the end of support. Due to the Covid19 pandemic that got delayed a bit, which was more time for us to execute our approach. But still, a pretty strong incentive by itself to move forward.
That's why we decided to lead the React migration initiative.
Incrementally! Most people might think that you either use one front-end framework or another. Ideally, yes.
But many projects are more complicated than that and code that has been written for years - well, it works. You don't want to break it. In our case, writing AngularJS (not Angular!) all day was ... let's say it was not ideal for anybody.
So, we based our evolutionary approach on this react2angular library. We kept the application state in AngularJS as is, but started migrating all components bottom-up. From the smallest components to whole pages.
The tricky areas were:
- Keeping the digest cycle update at the correct time.
- Managing the state changes between AngularJS and React as the format uses 2-way data binding.
- Handle async code correctly.
- Keep general components like modal dialogs consistent in both worlds.
- Keep React components as clean as possible, without any AngularJS dependencies.
Having decades of experience with many front-end stacks puts us in the right spot to solve these challenges. We had a simple plan to jump-start this migration:
- We would write all new components in React.
- If a new functionality required some component to be migrated to React first, we would do just that.
- We would extract common services to React hooks, so it would be easier to detach from old implementations.
Once we agreed on these rules, we produced the first POC PRs. From there, it was smooth sailing.
This is always a fun one.
Almost all of the code base was written in pure JavaScipt. Well, to be accurate, it was CoffeeScript. Which, in 2021... just got in your way. With ES6, you just don't need CoffeeScript.
But there was a desire to use TypeScript instead.
Just rewriting the whole code in TypeScript wasn't going to fly. Also, part of Markforged was still learning TypeScript. There had to be a good reason to go that path. Even just for new functionality.
Since there wasn't, we proposed that we don't go with TypeScript. At least for now.
Migrating from AngularJS to React was a big initiative all by itself. Combine that with a JS to TS migration, and you wouldn't have gotten new features any time soon. Even if you did that just for the back end. We had to cut this one off.
With the front-end framework migration and test automation increase initiatives set in motion, key features still had to be developed and delivered. Markforged was already convinced that ST6 was up to the task and would deliver more than expected.
- Subscriptions - the software purchase model was about to change to a subscription-based one. This was a huge change since it involved modifying the entire code base. From altering the database, and implementing the backend business logic to changing the front end and constructing the business use cases. Read more.
- Local storage migration - Markforged was offering their Eiger software in 3 forms: online, offline and a hybrid one. The hybrid one needed to go into sunset mode. In the course of a few months, we developed a migration strategy to either an online or full offline experience. Read more.
- Custom supports - originally, support material for overhanging 3D parts was generated automatically in Eiger. With this new feature, users could choose which sections of their 3D model needed support material or reinforcement. It was a critical and complex feature requested by users for a long time. Read more.
- Subfolders - working with a single level of folders is never enough. People needed to organize their parts into a hierarchical folder structure. We leveraged this PostgreSQL plugin, which made the feature possible. Read more.
- Increased front-end test coverage from less than 10% to over 50%.
- Enforced 100% code coverage - every new code should be 100% covered with tests 😈
- Introduced Webpack and decreased build time dramatically.
- Optimized CI pipelines and cut time in half - from 40min to 20min.
- Improve PR review quality - PRs wouldn't be approved without adding test(s). This slowly but effectively built the testing culture inside the teams. Priceless!
- No more code-style wars! Linting was there, but we added Prettier as well.
- UX improvements - as the boy scouts rule goes: "Always leave the campground cleaner than you found it". Every time we migrated a component from AngularJS to React, we didn't just migrate the component as it was. We always tried to bring something additional, which in the end only improved the end-user experience.
- We just get things done - quite often you would expect to have a single manager be responsible for a bunch of consultants. Even though we are not against that, we can operate quite well even without one. That's just in our culture. In times when management was struggling with even more important matters, we kept our productivity and managed to perform beyond expectations.
- Little golden nuggets for the next generation - we always try to implement features in such a way that the paradigms and abstractions used in those features are easily applied to other areas in the code. That's stuff like inter-component communication, async operations handling or unit test design.
- Visibility - code coverage was a mystical metric, so we made it visible. We even joined all tests (unit and system) to produce a single metric. Integrated that with the CI infrastructure and we were done. We also kept a log of how many components were migrated to React and how many remained in AngularJS.
- Organizational changes - we did push to have things like meeting check-ins and check-outs, retros (with real action items), kick-off meetings, and the "people over processes" rule.
Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime.
In the end, that's what we aim for! We can always just get the job done. But it's far more valuable when we share our knowledge, expertise and vision with everyone else. Every team member, including managers.
That's why we also talk openly about our culture and manifest it in everything we do.
Here are some highlights that Markforged shared about the way we craft software:
ST6 was instrumental in delivering key features for our product and platform during the time of their engagement - notably Overrides, Offline Eiger, Subscriptions, Webpack, React, among others. Each engineer had a positive contribution to our process, culture, and developing our team. The team was easy to work with, took assignments willingly and frequently volunteered their attention to tasks that might not be all that glamorous. ST6 paid attention to our domain and asked questions about our customers and how they use our products to better solve problems. It was not found that tickets had to be exceedingly exact for a solution to be simply implemented but rather they were able to solve problems.
Reach out to us through our Contacts page so we could talk. Cheers!