In this article I describe our plan to migrate portal.melonport.com from Blaze to React. It should help our devs as a guideline for the transition, but also inspire others who face similar challenges.

I’ll assume that you (the reader) have already heard about Blaze, React, Redux and Meteor. It’s furthermore crucial to understand that they are both “only” the view-layer of the app.

Why?

I think Blaze is an awesome view library for people coming from the jQuery/HTML world to get started with reactive apps because it’s easy to learn Handlebars-syntax and compatibility with the jQuery ecosystem. Furthermore, prototyping an app with Meteor/Blaze is still incredibly fast thanks to packages like Autoform (is there something similar to this in the React-world?). But it has some flaws that start to hurt as soon as the application/team grows. Most of them are already addressed in React (and supposedly also in other newer view layers like Angular.js or vue.js). So here are the main points:

jQuery: Although I think jQuery is a great library, it’s original intention and ecosystem focuses on building web-pages instead of web-apps (this distinction is really important). We should get rid of it completely.

Sessions: We worked with Meteor-Sessions on the v0.1 which helped to speed development up in the first place but is a technical dept on the long run. Working with Blaze/ReactiveDict doesn’t fell that much better. Session state management should be done by Redux.

Redux: It can be hard at the beginning, but once I really understood it, I can’t imagine how to manage state in a bigger application without these principles! Say goodbye to `console.log` thanks to the Redux-Devtools. Although it is possible to integrate Blaze with Redux (see our transition hack), it feels like forcing your mind to think in 2 different paradigms at the same time.

Modularity/Isolation/Testing: The ultimate goal is to have a decoupled component library following the Atomic Design principles. They should be decoupled from Meteor in general to have them ready to be used in a real Ðapp without a Meteor server and on other services. These properties also make them perfectly testable and auto documenting with Storybook. I don’t even know how to achieve something similar with Blaze.

Building software can feel like building a card house (CC0)

Don’t rewrite from scratch

Although every programmer knows the feeling when looking at foreign code (it even does not have to be bad code in the first place): I’ll rewrite this from scratch: perfectly organised, scalable, maintainable, modular, isolated, [insert more positive properties of the perfect code base here]. But you shouldn’t. Here are my points:

It’s approximately 10 to 100 times harder (=more expensive) than it seems to be

If you already have some users on it, which we have, you end up managing two code bases in parallel which is waste of time, or your users get angry because their bug/feature request aren’t addressed on time: “Because, you know, we work on the rewrite. It will be better, faster, easier to use, prettier and super awesome in general. — No, we don’t know when we will release it yet. It takes a little bit longer than expected *cough*. — Yes I know, that you filed this bug a month ago, just wait for the rewrite.”

As a side note: When to do a rewrite?

The answer lies in the difference between a MVP and a prototype:

Sometimes, you created a prototype but you thought it was a MVP. To identify this really rare case, the following properties apply to the outcome:

You have almost zero real users

AND there are significant architectural errors

Then, maybe, you could do a rewrite.

The Battle Plan of Salerno (From Wikimedia)

Modus Operandi

So how to evolve from a hacky MVP that was pushed out with the brute force of long nights and high pressure to a clean, maintainable and scalable code base without rewrite or refactoring camps?

1. Define the goal

The goal is long-term. Like how the whole system should look like in 6 months or so. There is also no rush getting there asap. It’s meant to be a mental lighthouse that gives direction.

Modularised and reusable components with loose coupling and high cohesion. Like a proper subsystem decomposition how it’s teached in software architecture classes.

Ensure unidirectional data flow accross components / services: User input → Redux → Blockchain → Mongodb → Redux → User Interface (But mask this tedious behaviour with an optimistic UI)

100% ESLint (maybe with the help of Prettier)

100% Flow Typed

95% Unit Test Coverage

As less as possible dependencies to Atmosphere. I.e. try to only use packages from NPM.

All business critical scenarios are end-to-end tested (i.e. automated browser tests)

Completely remove Blaze from the code base in favour of React

Completely remove SCSS in favour of JSS

Await/Async instead of Promise-Chains/Callback hell

… (I’ll update this list if new things arise)

2. The transition state

Until we reached the goal, we are in a transition state. That means, we do not fully comply with the goal yet, but every single commit regardless of a bugfix or working on a new feature should bring the project nearer to the goal. This list follows a lot of the principles of Working With Legacy Code.

No new code without unit tests

No new code that does not pass eslint

Utilize the boy scout rule: “Leave your code better than you found it.” That means: If you touch some code, try to clean it a bit first, write unit tests, refactor it here and there a little and add your improvements afterwards.

Do bigger refactoring regularly. 1–4h tasks weekly, bigger tasks monthly.

If you find architectural flaws that need to be addressed somewhen in the future, add in issue on Github.

Write end-to-end test before changing the code.

On a more technical side, during the transition state we have Blaze and React running side by side. Also SCSS and JSS.

But it is really important to note that this transition phase should be finished at one point. Otherwise, the codebase is worse because of the use of multiple view modules, etc.

Modularise

One important technique to manage large code-bases, so called monoliths, is modularising:

Identify functionality that could be reused somewhere even if it is just hypothetical and you know for sure, that this functionality will only be used in this particular project.

Then, extract this functionality into its own folder < npm module < micro-service. Fully unit-tested of course. Whereas “<” means: the best would be a micro-service, but it’s still better to have it in it’s own folder.

Depend on this now extracted module from your monolith.

Feel good about it.

An example from our codebase is the refactoring of all Javascript methods that interact with our smart contracts into its own folder. We plan to further isolate it into its own NPM module to enable other Javascript developers easily building other portals to the Melon Protocol. You don’t need to trust us.

Conclusion

This was my first article as a Senior Fronted/UX Engineer at Melonport.com. The goal of these articles is to open source our internal knowledge and documentation, so that others can learn from it or give us feedback, so we can learn from others. I hope it was not too long.

I’m happy for any comment, feedback or criticism. Also I’d like to hear which other topics you would like me to write about. I have the following topics in mind: