5 examples of Ruby’s best usage
Have you ever wondered what we can do with Ruby? Well, the sky is probably the limit, but we are happy to talk about some more or less known cases...
The day when you need to get familiar with a different technology is actually every day in a developer’s life. In this particular scenario, I’ve landed in a project that turned out to be the last within the company which uses Redux to manage the state in React app.
Sooner or later, we will move it to the MobX state, just as we did with the other apps. That is why I decided to have a quick look at it. There will not be that much code here and I believe you have already heard about Redux. Let’s start.
As stated at redux.js.org, it’s “a predictable state of container for JS Apps.” It was created by Dan Abramov and Andrew Clark in 2015.
It can be described by 3 principles:
No surprise here, MobX is also a library for state management, it transparently applies functional reactive programming (TFRP) to make it simple and scalable. Similarly to the preceding library, its philosophy is described in 3 points:
1. Straightforward – minimalistic, boiler-free code and no special tools required to operate it,
2. Effortless optimal rendering – it makes sure all computations are optimized well and there is no need to manually do so,
3. Architectural freedom – implementation is unopinionated and can be used without any UI framework.
React is known for the serious boilerplate around the initial setup. You cannot neglect it. Especially when you have a bigger application with a lot of reducers and actions, you have probably already decided to keep the action types as constants in the strings, which is a good approach, but then there is even more code! Fortunately, the Redux Toolkit is getting more popularity and it is now recommended to write Redux logic. If you ask me, I like it! Still, there is a lot to learn, but the simple basic setup with the Toolkit does the job.
When I looked at the MobX documentation, I was like a kid who accidentally landed in a chocolate factory. I was going through the examples and I kept asking how that could work, but it does and apparently does it well. But maybe handling all of the reducers, actions, middlewares, and other stuff makes it so easy to get fascinated by something else. Nevertheless, if you are familiar with OOP, MobX will come naturally to you. There is much less initial coding and many things happen behind the scenes, so you do not need to care about them in most cases.
In Redux, we have to use primitives, arrays, or plain JS objects as data for our state.
Also, there is a common practice when you store data in arrays, namely to normalize it for performance reasons. Unfortunately, even with the helper functions in Redux’s Toolkit (e.g., createEntityAdapter
) that still adds additional code.
In MobX, we make properties, entire objects, arrays, Map and Sets observable.
Yes, primitives are not mentioned here because their values in JS are immutable and because of that they need to be treated differently. All you need to know if you go with an observable
is that it will wrap the primitive in “a box” and the actual value getter and setter will be available via .get()
and .set(newValue)
respectively see observable.box(value)
import { observable, autorun } from "mobx"
const cityName = observable.box("Vienna") // same as observable("Vienna")
autorun(() => {
console.log(cityName.get())
})
// Prints: 'Vienna'
cityName.set("Amsterdam")
// Prints: 'Amsterdam'
There is no need for normalization of data, as MobX observable
` clones the object, makes it observable and, therefore, makes sure that all changes are reflected in the store once we update any of the observable properties.
We have a single source of truth in Redux. By keeping the state in one location, we make sure the data is not duplicated all over the app and it becomes easier to debug.
MobX actually encourages having at least two separate stores, one for the UI state and one or more for the domain state. That separation allows us to reuse the domain in different applications.
Because we are not limited to JS plain objects, it seems natural to create its own classes for particular domain objects, as the authors suggest. Here, Mobx shines for those of you who like object-oriented programming. You can have methods, control over what should be observable or not. In addition, we can combine multiple stores and share the references.
Redux requires that the update of state does not mutate the original state. So, if we want to add a new item to an existing array, we need to return a new instance instead of just adding that item to the current one.
function todoReducer(state = [], action) {
// here we create a new array and use a spread operator to keep the old values
return [
...state,
action.payload
]
}
Then, in MobX, we can mutate the observable properties, here: the todos
array. Notice we mutate the original array in addTodo
class ObservableTodoStore {
todos = [];
constructor() {
makeObservable(this, {
todos: observable,
addTodo: action,
});
autorun(() => console.log(this.todos.length))
}
addTodo(task) {
//here we are just pushing the new item to the existing array!
this.todos.push({
task: task,
completed: false,
});
}
}
const observableTodoStore = new ObservableTodoStore();
observableTodoStore.addTodo("Some tough thing to do");
What’s more, we can even directly update the todo
list and we will see that autorun
will be fired (it will notice a change in the observable array of todos
).
observableTodoStore.todos.push("Some other tough task");
// What is more interesting, only when you update the particular to-do property
// will MobX warn you (while in strict mode) that you shouldn’t do that directly
observableTodoStore.todos[1].task = ("Maybe something more effortless");
Personally, I really like the Chrome Redux DevTools extension. It allows you to have a quick look at your app’s state and has nice capabilities to go back and forth for every change to the state (time travel!). All that is possible because of the principle that you do not mutate the previous state.
The additional layer of abstraction to the store makes the process of debugging more difficult. The MobX Chrome extension seems so cumbersome to me, especially if compared to the previous experience, but maybe I need some time to get used to it.
But we have, e.g., the autorun
track function that you probably will use a lot when starting to use the MobX and wanting to check when the state changes. You need to note that the function will only track the changes it observes. That is determined once the function runs for the first time. MobX will subscribe to all observables that were read during that first invocation and then it will be triggered every time they change.
When you look at the popularity, Redux prevails here. Near 4M downloads from npm per week compared to 450k for MobX. Also, the number of contributors (~870 > 270) and stars (57k > 24k) on GitHub’s repository for each library shows that Redux is a well-known brand.
On the other hand, State of JS 2020 report shows the satisfaction from using them at almost the same level, so it definitely won’t help you decide which one to pick for your next project.
The satisfaction in this chart was described as “would use again / (would use again + would not use again)”
There arent winners in this contest… yet! BTW, there was no contest at all 😉 I believe both libraries are doing a great job with accomplishing their basic task, which is taking care of having a solid management state in your JS application . I will need more time to see how the daily work with MobX differs from Redux and for which cases I could recommend it.
For now, I can say I am already missing the “time travel” from Redux’s DevTools, but on the other hand setting a state with MobX seems so straightforward and the written code looks much more readable.
Nevertheless, I am so curious how the observable
handles the performance, as whenever I see some magic, I wonder how much of the resources of my PC (whether it is CPU time, memory or drive) are used and how efficient it is. That will definitely be my next stage of research.
Hopefully, I will get back to you with some really exciting explanations on how you can solve particular problems with MobX. See you then!