{"id":13673674,"url":"https://github.com/ericholiveira/studio","last_synced_at":"2026-01-12T02:30:46.154Z","repository":{"id":22318295,"uuid":"25653581","full_name":"ericholiveira/studio","owner":"ericholiveira","description":"A nodejs framework to create decoupled and scalable applications","archived":false,"fork":false,"pushed_at":"2024-03-25T20:59:46.000Z","size":1756,"stargazers_count":486,"open_issues_count":7,"forks_count":61,"subscribers_count":24,"default_branch":"master","last_synced_at":"2025-04-21T10:55:49.097Z","etag":null,"topics":["async","javascript","micro-services","nodejs","realtime-metrics"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ericholiveira.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-10-23T19:12:54.000Z","updated_at":"2025-03-03T20:47:18.000Z","dependencies_parsed_at":"2024-06-18T15:15:06.489Z","dependency_job_id":"19b4acb8-8dc4-4cc6-b9b9-cbf895c7118f","html_url":"https://github.com/ericholiveira/studio","commit_stats":{"total_commits":389,"total_committers":10,"mean_commits":38.9,"dds":0.03598971722365041,"last_synced_commit":"cffc74fa95e5889a24fdc0d4f634c36a66bcf31c"},"previous_names":[],"tags_count":67,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericholiveira%2Fstudio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericholiveira%2Fstudio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericholiveira%2Fstudio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericholiveira%2Fstudio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ericholiveira","download_url":"https://codeload.github.com/ericholiveira/studio/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251284872,"owners_count":21564686,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","javascript","micro-services","nodejs","realtime-metrics"],"created_at":"2024-08-02T10:00:54.258Z","updated_at":"2026-01-12T02:30:46.129Z","avatar_url":"https://github.com/ericholiveira.png","language":"JavaScript","readme":"Studio.js\n=========\n\n\u003cimg src=\"http://ericholiveira.com/studio/images/STUDIO_logo.png\" align=\"right\" width=\"300px\" /\u003e\n\nMicro services framework for Nodejs.\n\nStudio is a lightweight framework for node development to make easy to create reactive applications according to [reactive manifesto](http://www.reactivemanifesto.org/) principles. It uses micro-services (freely inspired by akka/erlang actors) implemented using [bluebird](https://github.com/petkaantonov/bluebird) a+ promises (or generators async/await) to solve the callback hell problem.\n\nDo you want clusterization? Realtime metrics? Easy async programming? Completely decoupled services? Stop worrying about throwing exceptions? Then I've  built this framework for you, because node needs a framework easy to use, yet giving your powerful features like realtime metrics and clusterization with no configuration (service discovery + rpc). Other frameworks relies on \"actors\", \"commands\", \"brokers\" and a lot of other complicated concepts, studio deals only with functions and promises, if you know both concepts you're ready to use and master it.\n\nThe main goal is to make all systems responsive, fault tolerant, scalable and maintainable. The development with Studio is (and always will be) as easy as possible, i'll keep a concise api, so other developers can create (and share) plugins for the framework.\n\nThe plugin system and the decoupled nature of it enables you to have real time metrics in your services , [ZERO CONFIGURATION CLUSTERIZATION ON DISTRIBUTED MACHINES](#cluster) and other improvements for your services.\n\nStudio isn't only a library, it's a framework. It's really important to learn how to program and not only what each method can do.\n\nI would love to receive feedback.Let me know if you've used it. What worked and what is wrong. Contribute and spread the word.\n\n\nWants to learn more???? Click here to join our slack channel \n\n[![Join the StudioJS chat](https://studiojs.herokuapp.com/badge.svg)](https://studiojs.herokuapp.com/)\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fericholiveira%2Fstudio.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fericholiveira%2Fstudio?ref=badge_shield)\n\n[![Build Status](https://travis-ci.org/ericholiveira/studio.svg?branch=master)](https://travis-ci.org/ericholiveira/studio)\n[![npm version](https://badge.fury.io/js/studio.svg)](http://badge.fury.io/js/studio)\n[![Dependency Status](https://david-dm.org/ericholiveira/studio.svg)](https://david-dm.org/ericholiveira/studio)\n\n[![NPM](https://nodei.co/npm/studio.png?downloads=true\u0026downloadRank=true\u0026stars=true)](https://nodei.co/npm/studio/)\n\nTable of contents\n========\n\n- [Install](#install)\n- [Intro](#intro)\n- [Why](#why)\n- [Getting Started](#getting-started)\n- [Examples](#examples)\n- [Modules / namespacing](#modules)\n- [Co / Generators and flow-control](#generators)\n- [Proxy](#proxy)\n- [Es6 Class](#es6-class)\n- [Plugins](#plugins)\n- [Filters](#filters)\n- [Timeouts](#timeouts)\n- [Realtime metrics](#realtime-metrics)\n- [Retry](#retry)\n- [Clustering](#cluster)\n- [Pro tips](#pro-tips)\n- [From Zero To Hero](#from-zero-to-hero)\n- [Dependencies](#dependencies)\n- [Build](#build)\n- [Test](#test)\n- [License](#license)\n\nInstall\n========\n\nTo install execute:\n\n    npm install studio --save\n\nIntro\n========\n\nWe all want our systems to be responsive, scalable, fault tolerant, maintainable and for the last, but not least, easy and fun to develop. With this goals in mind i decided to build a [micro-services](http://martinfowler.com/articles/microservices.html) framework for nodejs using and architecture freely inspired on [actors model](http://en.wikipedia.org/wiki/Actor_model). I present you [Studio](https://github.com/ericholiveira/studio)\n\nStudio makes easy to create code without ANY dependency between your services, so you can deploy all in a single machine or just easily change to each one in a different machine or anything in between. It also enables operations timeouts, zero-downtime reload, let-it-crash approach (stop to be afraid of exceptions, Studio handles it to you), plugins and makes it nearly impossible to falls in a callback hell. Supports any web framework (we have examples with express) and helps you with flow-control using [bluebird](https://github.com/petkaantonov/bluebird).\n\nStudio encourages you to use the best practices of nodejs, it helps you to write simple, clean and completely decoupled code. And makes it very easy and fun.\n\nFirst of all, everything in a Studio-based application is a service.\n\nSo if you're used to build SOA or micro-services all your services (and possible layers, as DAOs for instance) are going to be declared as a STATELESS SINGLETON services. Services have an unique identifier and communicate (always) asynchronously through message passing. The benefits of this approach is that it is really easy to take just some of your services to different servers and make a better use of it. Also, your services have the free benefit of deep copying the parameters before the message is delivered (so one service can't mess with the objects of another service) increasing your code security.\n\nAnd this is it... this is all you need to create [reactive](http://reactivemanifesto.org) applications.\n\nWhy\n========\n\nNow you might be wondering why systems created with Studio can be called a reactive system. As stated by the [reactive manifesto](http://www.reactivemanifesto.org/), reactive systems are those who follow 4 principles:\n\n- Responsive : \n\u003e Responsive systems focus on providing rapid and consistent response times, establishing reliable upper bounds so they deliver a consistent quality of service.\n\nUsing Studio you just add a thin layer over your functions without compromising the responsiveness while giving you the power to interact with your application in runtime as in [aspect-oriented programming](https://en.wikipedia.org/wiki/Aspect-oriented_programming)\n\n- Resilient :\n\u003e The system stays responsive in the face of failure. This applies not only to highly-available, mission critical systems any system that is not resilient will be unresponsive after a failure. \n\nThis is critical for thoses using nodejs, Studio enforces you to use the best practices to avoid your process or any of workers to crash. And as all your services are written with async flow in mind it also makes easy to add redundance\n\n- Elastic : \n\u003e The system stays responsive under varying workload.\n\nThis is critical for Studio. All service calls are async so you never release [zalgo](http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony), also every service call receives a copy of the parameters so a service cant mess with other service code. And for the last but not least using Studio plugins you can have measures of your code in realtime as using the [timer plugin](#timer) you can check the time needed to execute every single service call in your application and you can even send it easily for a statsd/grafana metrics dashboard. So this way you have an application ready to scale horizontally and also with the metrics to help you to decide when to do this.\n\n- Message driven :\n\u003e Reactive Systems rely on asynchronous message-passing to establish a boundary between components that ensures loose coupling, isolation, location transparency, and provides the means to delegate errors as messages.\n\nAll service calls in Studio are async, even if youre doing some sync code, Studio will make it run async. Also all call goes through the Studio router which enforces a deep clone of the parameters for security reasons, and all services are COMPLETELY DECOUPLED and isolated from each other\n\nSo the main reason to use Studio is because it makes it to reason about your code and make it scalable as hell.\n\nGetting Started\n========\n\nTo create a service all you need to do is pass a NAMED function to studio\n\n```js\nvar Studio = require('studio');\nStudio(function myFirstService(){\n   return 'Hello World';\n});\n```\n\nTo call a service all you need to do is pass the identifier of a service to studio (remember all service calls returns a promise)\n\n```js\nvar Studio = require('studio');\nvar myFirstServiceRef = Studio('myFirstService');\nmyFirstServiceRef().then(function(result){\n\tconsole.log(result); //Prints Hello World \n});\n```\n\nYour service can receive any number of arguments.\nAnd also, you can get a reference to a service even if it was not instantiated yet (you only need it when calling) as in:\n\n\n```js\nvar Studio = require('studio');\n//Get the reference for a non initialized service works perfectly\nvar myServiceNotInstantiatedRef = Studio('myServiceNotInstantiated');\n\nStudio(function myServiceNotInstantiated(name){\n\treturn 'Hello '+name;\n});\nmyServiceNotInstantiatedRef('John Doe').then(function(result){\n\tconsole.log(result); //Prints Hello John Doe \n});\n```\n\nIs that simple to run over Studio. No boilerplate required.\n\nNow the things can get more interesting if youre running on node \u003e= 4 or using the flag --harmony-generators, because studio supports generators out-of-the-box if they are available as in:\n\n```js\nvar Studio = require('studio');\nvar myFirstServiceRef = Studio('myFirstService');\nStudio(function myFirstService(){\n   return 'Hello World';\n});\n\nStudio(function * myFirstServiceWithGenerator(result){\n\tvar message = yield myFirstServiceRef();\n    console.log(message); // Prints Hello World\n   \treturn message + ' with Generators';\n});\nvar myFirstServiceWithGeneratorRef = Studio('myFirstServiceWithGenerator');\nmyFirstServiceWithGeneratorRef().then(function(result){\n\tconsole.log(result); //Prints Hello World with Generators\n});\n```\n\nYou can yield Promises, Arrays of promises (for concurrency), Regular Objects or even Thunkable (node callbacks) you can see hthe examples in the [generators](#generators) session\n \nAlso if youre running on node \u003e= 6 or using the flag and --harmony-proxies. You can access the services easier:\n\n```js\nvar Studio = require('studio');\n//Get a reference to all services, even those not created yet\n// So magical :)\nvar allServices = Studio.services();\n\nStudio(function myFirstService(){\n   return 'Hello World';\n});\n\nStudio(function * myFirstServiceWithGenerator(result){\n\tvar message = yield allServices.myFirstService();\n    console.log(message); // Prints Hello World\n   \treturn message + ' with Generators';\n});\n\nallServices.myFirstServiceWithGenerator().then(function(result){\n\tconsole.log(result); //Prints Hello World with Generators\n});\n```\n\nYou can enable Studio logs via environment variable:\n```bash\nDEBUG=Studio node my-studio-app.js\n```\n\n\nExamples\n========\n\nFollow the link to see all available [examples](https://github.com/ericholiveira/studio/tree/master/examples)\n\nStudio works with any web framework.\n\nHere i'm going to put just a basic hello world with express, on [examples](https://github.com/ericholiveira/studio/tree/master/examples) folder you can see the best practices and more practical examples ( with promises, errors, filters...):\n```js\nvar express = require('express');\nvar Studio = require('studio'); //require Studio namespace\nvar app = express(); // create an express app\n\n//Gets reference to helloService\nvar helloService = Studio('helloService');\n//If you pass a String to Studio function it returns a reference for that service\n\napp.get('/', function(req, res) {\n  /* When this route is requested we send the message to the responsible\n   service using the 'helloService' function, all references returns a promise\n   when the promise is fulfilled the 'then' method is executed, if it is\n   rejected the 'catch' method is executed\n   */\n  helloService().then(function(message) {\n    res.send(message);\n  }).catch(function(message) {\n    res.send('Sorry, try again later =\u003e ' + message);\n  });\n});\n//Create a service\n\nStudio(function helloService() {\n    /*\n    When Studio receives a NAMED function it will create a service with that name.\n    As stated before the since the decoupled nature of Studio you dont need to export a service\n    */\n    console.log(this.id + ' was called');\n    return 'Hello World!!!';\n  }\n);\napp.listen(3000);// Listen on port 3000\n```\n\nOn examples folder you can learn how to deal with errors, filter messages and much more.\n\nModules\n========\n\nStudio have a built-in module system to prevent service identifier collision and it is insanely easy to use, all you have to do is prepend Studio calls with Studio.module(\"someModuleName\")\n\n```js\nvar Studio = require('studio'); //require Studio namespace\nvar helloModule = Studio.module('hello');//Creates hello module\n\n//Creates service under hello module\nhelloModule(function say(){\n\treturn 'hello';\n});\n\n/*\nModules object have all the properties from Studio, but running only for that module\nso  helloModule('say'); return a reference to the service 'say' inside the module hello\n*/\nvar sayService = helloModule('say');\n\nStudio(function someServiceOnRootModule(){\n\treturn sayService();\n});\n\nvar someServiceOnRootModuleRef = Studio('someServiceOnRootModule');\n\nsomeServiceOnRootModuleRef().then(function(result){\n\tconsole.log(result);\n});\n\n```\n\n\nGenerators\n========\n\nStudio supports generators out-of-the-box if they are available (only available for node \u003e4 or older versions running with --harmony-generators flag) as in:\n\n```js\nvar Studio = require('studio');\nvar myFirstServiceRef = Studio('myFirstService');\nStudio(function myFirstService(){\n   return 'Hello World';\n});\n\nStudio(function * myFirstServiceWithGenerator(result){\n\tvar message = yield myFirstServiceRef();\n    console.log(message); // Prints Hello World\n   \treturn message + ' with Generators';\n});\nvar myFirstServiceWithGeneratorRef = Studio('myFirstServiceWithGenerator');\nmyFirstServiceWithGeneratorRef().then(function(result){\n\tconsole.log(result); //Prints Hello World with Generators\n});\n```\n\nYou can yield Promises, Arrays of Promises, Objects, and even callbacks using Studio.defer().\n\nExamples:\n\n```js\nvar Studio = require('studio');\nvar myFirstServiceRef = Studio('myFirstService');\nStudio(function myFirstService(){\n   return 'Hello World';\n});\n//Yielding promise\nStudio(function * myWithGeneratorYieldsPromise(result){\n\tvar message = yield myFirstServiceRef();\n    console.log(message); // Prints Hello World\n   \treturn message + ' with Generators';\n});\n//Yielding array\nStudio(function * myWithGeneratorYieldsArray(result){\n\tvar message = yield [myFirstServiceRef(),myFirstServiceRef()];\n    console.log(message[0]); // Prints Hello World\n    console.log(message[1]); // Prints Hello World\n   \treturn message[0] + ' with Generators';\n});\n\n//Yielding Object\nStudio(function * myWithGeneratorYieldsObject(result){\n\tvar message = yield 'Hello World';\n    console.log(message); // Prints Hello World\n   \treturn message + ' with Generators';\n});\n\nvar fs = require('fs');\n//Yielding Callback\nStudio(function * myWithGeneratorYieldsObject(result){\n\t// just place Studio.defer() instead of the callback function\n\tvar message = yield fs.readFile('SOME_FILE_NAME',Studio.defer());\n    console.log(message); // Prints the file content\n   \treturn message + ' with Generators';\n});\n```\n\nProxy\n========\n\nIf youre running on node \u003e 4 or using --harmony-proxies flag. You can access the services easier:\n\n```js\nvar Studio = require('studio');\n//Get a reference to all services, even those not created yet\n// So magical :)\nvar allServices = Studio.services();\n\nStudio(function myFirstService(){\n   return 'Hello World';\n});\n\nStudio(function * myFirstServiceWithGenerator(result){\n\tvar message = yield allServices.myFirstService();\n    console.log(message); // Prints Hello World\n   \treturn message + ' with Generators';\n});\n\nallServices.myFirstServiceWithGenerator().then(function(result){\n\tconsole.log(result); //Prints Hello World with Generators\n});\n```\n\nEs6 Class\n========\n\nIf you're running on node \u003e=4 or using --harmony flag, you can create your services easier:\n```js\nvar Studio = require('studio');\nclass Foo{\n\tbar(){\n\t\treturn this.hello();\n\t}\n\thello(){\n\t\treturn 'hello';\n\t}\n\tuseExternal(){\n\t\tvar someExternalService = Studio('someExternalService');\n\t\treturn someExternalService();\n\t}\n}\nStudio.serviceClass(Foo);\n\n//To acess from outside or other classes\nvar fooModule = Studio.module('Foo');\nvar barService = fooModule('bar');\nbarService();\n```\n\nThis way Studio automatically creates a namespace with the class name and a service for each function of this class\n\nPlugins\n========\n\nPlugins lets you have full control of whats going on with your services, this way you can enhance your services with a lot of cool capabilities like realtime metrics, timeout and any other cool stuff if you decide to create your own plugins. To use a plugin all you have to do is:\n\n```js\n\tStudio.use(MY_SUPER_COOL_PLUGIN);\n```\n\nPlugins can listen to services creation and destruction(this way you can intercept messages). The officially maintained plugins are available under Studio.plugin parameter. You can check the [tests folder](https://github.com/ericholiveira/studio/tree/master/tests) to understand better how to use plugins.\n\nStudio.use method also receives an optional second parameter to filter the services that are going to receive the plugin this filter can be a string (to match only the service with that name), a regular expression, an array of strings or a function as:\n\n```js\n\tStudio.use(MY_SUPER_COOL_PLUGIN_1, 'myService');\n    Studio.use(MY_SUPER_COOL_PLUGIN_2, /myService/g);\n    Studio.use(MY_SUPER_COOL_PLUGIN_3, ['myService1','myService2']);\n    Studio.use(MY_SUPER_COOL_PLUGIN_4, function(serviceId){\n    \treturn serviceId === 'myService';\n    });\n```\n\nFilters\n========\n\nValidation and filters are a common use for your services, so Studio already make it as a built-in resource. Any service can have a \"filter\" function to handle this (if you know [guards](https://en.wikipedia.org/wiki/Guard_(computer_science)) or asserts you know what a filter is). As any other action on Studio, it already deals with async or sync results automatically.\n\n```js\nStudio(function helloFiltered(value){\n\tconsole.log('Received message to actor = ' + userActor.id);\n    return 'Hello';\n}).filter(function(value){\n  /* Let's say you have a rule where the body needs to be greater than 0.\n  You could implement this logic on helloFiltered\n  function, but a better approach would be to keep your filter logic away from\n  your business logic code. So all services have the 'filter' method, this method can return any \n  sync value or a promise, on this example we returns a boolean value.\n  A message pass through the filter when:\n  - it returns true or returns any truthy value\n  - it resolves a promise with true or any truthy value\n  A message is rejected by the filter when:\n  - it returns false or returns any falsy value\n  - it resolves a promise with false or returns any falsy value\n  - it throws an exception\n  - it rejects a promise\n  */\n\treturn value\u003e0; // As said before, you can also return a promise for async\n});\n```\n\nTimeouts\n========\n\nStudio also supports timeouts and is really easy to use.\nYou can easily make sure that a service is going to respond in a timeframe or it fails, to do this, you will need to add the timeout plugin:\n\n```js\nStudio.use(Studio.plugin.timeout);\nStudio(function myServiceWithTImeout(){\n\tvar randomTime = Math.floor(Math.random()*100);\n    return Studio.promise.delay(randomTime);\n}).timeout(50);//Time in milliseconds\n```\n\nReal time metrics\n=================\n\nOne of the cool things you can do with Studio plugins is to have real time metrics of all your services, if you want to log\nthe time needed to execute every call of every service you can do it easily with the timer plugin. This plugin also\nshows you the power you can get from a custom plugin and [aspect-oriented programming](https://en.wikipedia.org/wiki/Aspect-oriented_programming)\n\nThe timer plugin uses process.hrtime() for sub-millisecond precision.\n\n```js\nvar Studio = require('studio');\n\nStudio.use(Studio.plugin.timer(function(res){\n    /*\n     * Here you define what to do with the execution info, now we are going just to print in the console, but\n     * in production you could send it to statsd or some other metric aggregator.\n     */\n    console.log('The receiver %s took %d ms to execute', res.receiver, res.time);\n}));\n\nStudio(function myService(){\n\tvar randomTime = Math.floor(Math.random()*100);\n\n    // Time in milliseconds\n    return Studio.promise.delay(randomTime);\n});\n\nvar myServiceRef = Studio('myService');\n\nsetInterval(myServiceRef, 500);\n```\n\nRetry\n=====\n\nStudio supports retry a service call in the occurrence of error.\n\n```js\nvar Studio = require('studio');\n\nStudio.use(Studio.plugin.retry());\n\nStudio(function myService(){\n\tthrow new Error('');\n}).retry({max:2});\n\nvar myServiceRef = Studio('myService');\n\nsetInterval(myServiceRef, 500);\n```\n\nIt supports multiple configurations, and all can be applied for all services and overriden for individual services.\n\n```js\nvar Studio = require('studio');\n\nStudio.use(Studio.plugin.retry({max:3})); //set the service to retry 3 times as default \n\nStudio(function myService(){\n\tthrow new Error('');\n}).retry({max:2}); //set the service to retry 2 times\n\nStudio(function myOtherService(){\n\tthrow new Error('');\n}).retry();//set the service to retry. Will use the default max attempts \n\nStudio(function yetAnotherService(){\n\tthrow new Error('');\n}); // this service will never retry (YOU MUST CALL .retry() to enable retry)\n\nvar myServiceRef = Studio('myService');\n\nsetInterval(myServiceRef, 500);\n```\n\n\nName                | Description                                                                                                      | Default\n--------------------|------------------------------------------------------------------------------------------------------------------|---------------\nmax                 | Number of retry attempts                                                                                         | 0\nfilter              | A function to filter certain errors from retry (must return a boolean)                                           | retry for all errors\ninitialInterval     | Interval between retries                                                                                         | 0\nfactor              | A multiplication factor between retries                                                                          | 1\nbeforeCall          | Function called BEFORE every service call, can be used to support stateful retries                               | -\nafterCall           | Function called AFTER all retries, can be used to support stateful retries (called on both, success and failures | -\n\nCluster\n========\n\nTo clusterize your application without any configuration you need to add the [studio-cluster](https://github.com/ericholiveira/studio-cluster) plugin, follow the link to see how to use and examples of implementations, like the [distributed merge sort](https://github.com/ericholiveira/studio-cluster/tree/master/examples/mergesort)\n\nPro tips\n========\n\n- The most important tip is LEARN HOW TO DEAL WITH A+ PROMISES, i think this [blog](https://blog.domenic.me/youre-missing-the-point-of-promises/) have a incredible explanation of what A+ promises means and how it saves you from callback hell\n- You should avoid mutatins states , Studio helps you to achieve this delivering to each service a copy of the original message.\n\nFrom Zero To Hero\n========\n\nI've also started a series of posts on my medium explaining the motivation and creating a small project with studio\n\n[Nodejs microservices. From Zero to Hero Pt1 - Motivation](https://medium.com/@ericholiveira/nodejs-microservices-from-zero-to-hero-pt1-279548cb4080)\n\n[Nodejs microservices. From Zero to Hero Pt2 - Basic Usage](https://medium.com/@ericholiveira/nodejs-microservices-from-zero-to-hero-pt2-72fbb2a1b1c4#.dpz6adn7c)\n\n[Nodejs microservices. From Zero to Hero Pt3 - Plugins and cluster](https://medium.com/@ericholiveira/nodejs-microservices-from-zero-to-hero-pt1-plugins-and-clustering-ddb60e9a8ee0#.v3m1jh2l5)\n\nDependencies\n========\nStudio depends on:\n- [bluebird](https://github.com/petkaantonov/bluebird) for a+ promises usage\n- [harmony-proxy](https://github.com/Swatinem/proxy) to help with proxy usage on node 0.11 and 0.12 (if you want to enable it) \n\nBuild\n========\n\nTo build the project you have to run:\n\n    npm install\n    npm run start\n\nThis is going to install dependencies, lint and test the code\n\nTest\n========\n\nRun test with:\n\n    npm run test\n\nLicense\n========\n\nThe MIT License (MIT)\n\nCopyright (c) 2015 Erich Oliveira [ericholiveira.com](http://ericholiveira.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n\n## License\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fericholiveira%2Fstudio.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fericholiveira%2Fstudio?ref=badge_large)","funding_links":[],"categories":["JavaScript","Frameworks/Libraries"],"sub_categories":["Node"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fericholiveira%2Fstudio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fericholiveira%2Fstudio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fericholiveira%2Fstudio/lists"}