We have a custom form component that we built before we started using Flux, so it does not follow the Flux pattern. A new colleague was using this component for the first time, and since it is fairly complicated, he didn’t quite understand how it worked. He managed to make his form work, but he wasn’t using the component correctly, since he expected it to be “fluxy.” I tried to explain to him that just because the code was working, that doesn’t mean that it was right. My lesson didn’t sit right with him, because I didn’t have a good example to help explain it at the time.
Thank goodness for Jacques Pepin
Jacques Pepin’s method of removing kernels from an ear of corn is fairly unique. He moves the knife towards him, sliding it from the heel to the tip, which mimics the motion of slicing on a cutting board and uses the full blade. The knife moves cleanly through the corn. Inevitably when he does this, he also shows us the wrong way to cut kernels off the ear by holding the knife blade perpendicular to the ear and pulling towards yourself. It puts too much pressure directly on the blade and requires you to use a lot more force. It works, but it is not the right way to use a knife.
As a faithful reader, I’m sure you are aware that I don’t care for analogies too much. They are often left open to interpretation; so let me explain what I mean with this one. Jacques Pepin shows us two different ways to use a knife. Both accomplish the job of removing kernels from the cob, but one is difficult and dangerous, and the other is effortless and safe. Both work, but one is right. In this case, right is not subjective – there are always correct and incorrect ways to use tools. The correct way to use a knife is in a slicing motion – it is designed to work that way.
How about an example we can relate to, Jeff?
If you are into React, and you have read the documentation, then you
are probably well aware of the
forceUpdate function. It
forces a re-render of your component. And, even if you haven’t read the
documentation, you probably know about
setState, which changes the
state of your component and re-renders it. If you really wanted to, you could
change the state of your component by doing something like this:
this.state.foo = 'bar';
Just executing that code won’t re-render your component, because React does not
know that state changed, but if you were to call
forceUpdate afterwards, then
you would get the same behavior as if you had called
setState. Well, almost.
Everything would appear to work, and it would probably be ok for a while. But
sooner or later, you would run into some edge case when you needed
shouldComponentUpdate to be called (it isn’t called when
invoked), or when a call to
setState somewhere else in your component
overwrote the value of
foo that you set explicitly. It works, but it is not
right. Fortunately, the good authors of React gave a big fat warning to let
NEVER mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.
Lots of room for error in “working” code
The difference between making something work and doing it right reminds me of a saying my freshmen year comp sci professor told us:
Make it work;
Make it right;
Make it fast;
Make it light.
The saying may not originally be his, and it is quite open to interpretation, but here’s how I see it applying to this use case. Getting a piece of code to work – to just do the function we want it to do – is our most basic job. It is only the starting point of a job well done. If you know enough about your tools, you can get it to work by doing the right thing from the start. And when you are doing the right thing, then you are more likely to keep that code working correctly for a longer time. It will have fewer bugs; it will be easier to refactor; and it will be easier to understand in the future.