A long time ago, in a galaxy far, far away, an engineer realized that every time they start a new project, they have to write the same piece of code over and over again:
- Install some HTTP framework, some database adapter, maybe some validation library and a bunch of other things
- Decide where each part of the code will live
- Write the "glue code" which starts and configures all these frameworks, adapters and other libraries and makes it available from other parts of the app
On small-scale/demo apps, this is not a problem — you only have one, at most two, stateful components (an HTTP server and a database connector) and some business logic stored somewhere in the src/ directory. But as with most projects which we initially consider "small-scale," they soon outgrow their pants, and we have to spend time re-thinking how the startup process should work. What's even worse, many developers rarely consider the shutdown phase of their application and believe that simply killing the Node.js process is OK. Well, sometimes it is, but you may end up killing the process in the middle of an uncommitted transaction or, even worse, killing the process in the middle of some complex operation and not being in a transaction. 😱
At this point, many developers would start thinking: I'd just use a full-fledged framework that takes care of all these things for me! And yes, they would be right. However, we soon also realized some caveats of this approach:
- It forces you to write your code in a specific manner / structure it in some specific way
- Sometimes it forces you to use specific technology / library / database / etc.
- Maintenance or extensibility of this framework is not always on the level you might require in the future (and you usually only realize this when you are half-through with your project)
- There are as many framework preferences as there are developers and deciding on one might be too difficult a feat to accomplish
It was at this time when we realized we do not need nor want a full-fledged framework — we want something that would take care of the basic application lifecycle and configuration and get the hell out of our way, allowing us to compose the tech stack that best fits our project goals or preferences.
Atlas.js is not a framework nor will it ever be. It is simply a glue to set up and tear down components — pieces of your application which you need to have in order to achieve your goals. There are many existing, pre-made components available, and it is quite easy to write your own. You can find all of them in the repository.
You use a component by either installing it using npm or writing your own and then adding it to Atlas via a declarative API. Since all components share the same API surface, Atlas knows exactly how to start or stop that component to make it work. By having that component on npm, it is super easy to share it across projects or use the same component multiple times in the same project (i.e. one app which connects to multiple Postgres databases).
Atlas takes care of the following for you:
- Application startup / shutdown sequence
- Connecting to / disconnecting from external services (databases etc.)
- Application configuration
That's it. That's all it does.
Let's briefly look at some of these things in more detail.
The order in which you start some parts of your application is quite important — you do not want to start your HTTP server to accept incoming traffic before you have established a working connection to the database. Atlas starts all components in the order you define and only moves on to the next component once the current one is up and running.
Again, Atlas will stop all the components in the reverse order as when it started them. Usually, this means that the user-facing interfaces will be stopped first (in a graceful manner) and only once they are fully stopped will it move on to the next component. This ensures that you do not forcibly terminate pending requests and that you do not shut your database connection down before you stop your HTTP interface to avoid new requests coming in. And since all your components can shut down gracefully, you don't even need to call
process.exit() to stop the app. Node.js will simply quit on its own, because there will be no more work for it to do.
Atlas will load up your configuration from several places and make it available inside your components and also from other parts of your code:
- General configuration from some main configuration file
- Environment-specific overrides from a different configuration file (i.e. specific options only applicable to production deployments, etc.)
- A local, non-version-controlled, developer-specific configuration file (because various developers have various development setups)
This is the one area where Atlas tries to go a little bit further. We realized that this pattern is the same in almost every backend project we ever developed, and so it warrants a standardized solution directly in Atlas.
While that's probably the core of Atlas, it does provide some additional and optional extras, which you may or may not like and use. But the important part is that it's completely up to you. You can use Atlas to start your stateful components and then continue writing code outside of Atlas. It's best to check the repository and dig through the examples and tutorials available there. To give you a taste, here’s the list of some of the most commonly used components:
- Check them all
You can get started with Atlas quickly either by following the examples or by using our Yeoman generator to scaffold the important parts. We have to admit, the generator is somewhat lacking currently as it spits out code which requires Babel to compile and not everyone likes Babel in a Node.js project, but it is a good start to understand how Atlas is supposed to work. And the boilerplate code is small enough that you might just manually rewrite all the files to vanilla JS afterwards in a matter of few minutes.
Give it a try, and leave feedback by opening an issue in the Github repo!
You might also like...
Getting to Know Monorepo
As a concept, Monorepos have been around for more than a decade. Google, Facebook and Microsoft have been using this architecture for ages. But it’s only now, as better tooling hits the market, that startups and open source projects are jum...
Kotlin Coroutines, Threads, Concurrency and Parallelism 101
Kotlin coroutines have been stable since Kotlin 1.3. As a result, we can finally get rid of the experimental flag and start our exciting journey into the uncharted magical world of concurrency.But wait a second…we can’t just dive in unprepa...
News From DockerCon19
Docker Containers are hands down one of the most popular ways to deploy apps. So, of course, STRV’s Backend Team couldn’t miss the biggest Docker conference of the year: DockerCon.Even though the conference focused primarily on Enterprise f...