During EmberConf 2017, I had the pleasure of attending Sarah Mei’s closing keynote on Livable Code. It encouraged me to think about making the current Ember application I work on more livable.
My goals were simple:
- Clean up the clutter that has accumulated.
- Prevent future clutter from accumulating.
But what patterns should I commit to following throughout the application to remove said clutter? How do I ensure that clutter does not accumulate going forward? Luckily, there is an ESLint plugin to help with this called eslint-plugin-ember.
This plugin provides ESLint rules that encourage developers to follow established best practices within Ember. Some of the rules I found rather interesting include:
Now that I had an addon that could tell me what clutter I needed to deal with, the only thing left to do was clean it up.
Dang! That is one cluttered Ember application! It almost seems too daunting to deal with, but I assure you that it’s manageable with a few simple techniques.
Regular Expressions Are Your Friend
To illustrate my point, I’ll use the metaphor of a dirty house. More specifically, let’s focus on the task of cleaning dirty dishes that were left in the sink. Would you take the time to wash each dish by hand, making sure to scrub each dish with soap and water before drying it off? Or would you rather put the dishes in the dishwasher and let it do all the hard work? Regular expressions are the dishwasher that washes the dishes for you (figuratively, of course).
Regular expressions are a great way to find occurrences of text that follow a specific pattern and manipulate them as necessary. This makes the task of replacing/rearranging text quite simple. For example, if I want to replace all violations of use-ember-get-and-set
(at least the getters), I can use a regular expression to do just that:
In short, do not wash every dish by hand. Regular expressions will save you time, effort, and sanity. If you would like some practice with regular expressions, check out RegExr.
Run Your Test Suite Often
While cleaning your house, it is imperative to make sure the house still functions as expected. You need to know if vacuuming the living room will unplug the television or if scrubbing the toilet will cause a pipe to leak. It is crucial to know if the changes you make are breaking the functionality of your application. It is undesirable to be in a situation where you finish fixing all the ESLint errors, only to have your tests fail and have no idea why.
When introducing a large amount of ESLint errors into an Ember project, there are going to be quite a few test failures. Tests are automatically generated to ensure your files adhere to the rules specified in your .eslintrc.js
file.
One trick to reduce the noise in tests during a refactor like this is to run all of the tests, excluding the generated ESLint tests. This can be done with the following command:
ember test -s --filter "\!eslint"
Running tests early and often during a large refactor ensures that the changes are not damaging the functionality of the application.
Do Not Clean Everything At Once
When I started this refactor, I attempted to turn on all the new ESLint rules and brute-force my way to a cleaner Ember application. This did not work for many reasons. I was working harder, not smarter. I do not clean my entire house in one day, and I should not expect to clean my entire codebase at one time.
Instead, make a list of the things you need to clean and complete them one at a time. Do not work on them all simultaneously. A collection of smaller, actionable tasks is more manageable than a large, daunting one. As you accomplish each task, cross it off and verify that things are still working properly. To get you started, here are all the rules that the plugin provides:
"ember/alias-model-in-controller": "off",
"ember/avoid-leaking-state-in-components": "off",
"ember/closure-actions": "off",
"ember/jquery-ember-run": "off",
"ember/local-modules": "off",
"ember/named-functions-in-promises": "off",
"ember/no-empty-attrs": "off",
"ember/no-function-prototype-extensions": "off",
"ember/no-observers": "off",
"ember/no-on-calls-in-components": "off",
"ember/no-side-effects": "off",
"ember/order-in-components": "off",
"ember/order-in-controllers": "off",
"ember/order-in-models": "off",
"ember/order-in-routes": "off",
"ember/routes-segments-snake-case": "off",
"ember/use-brace-expansion": "off",
"ember/use-ember-get-and-set": "off"
Do you have to implement all these rules to have a clutter-free Ember application? No, and that shouldn’t be your end goal. Making a codebase livable means making it comfortable for you. What is comfortable for you might not be comfortable for other developers, and that is okay.
Keep in mind that these rules are ideals, but some of them might be of less importance to you than others. For example, I do not benefit much from enforcing ordering in my components, whereas an addon author who desires well-organized and documented code might find these ordering rules invaluable.
These are a few techniques that I have used to make the Ember application I work on more livable. What techniques do you use to maintain a livable codebase?