Genix
genix
is a library for build event driven applications in a easy way.
Through genix
we should be able to create applications with very low levels of coupling which are easy to tests, as main goals it has:
- Decoupling
- Maintainability
- Reliability
- Testing
Events
First of all we should say that genix
supports events
and commands
as main building blocks, the differences between them are mainly semantic.
Events should indicate actions that already happened, is common use them to notify that something changed in the application, for example data-loaded
, order-ready
, payment-done
etc. One event have one or more handlers associate to it, for example:
; { ;} { const data = user: 'user' ; ;} ;; // {user: 'user'}
In the above functions, the first one register a handler for data-loaded
event and in the second this event is emitted.
genix
allow chain any numbers of events in a way that events can be emitted from handlers, so the following can be done:
; { ;}
In the previous example first data-loaded
is emitted and then data-processed
.
Commands
In other hand commands
are meant to indicate something which should happen.
commands
They should be named with a verb in imperative mood.
When we trigger a command genix
execute the handler associate with this command and return its value.
The main differences between events
and commands
are that genix
only allow one handler per command and we can get a return value after execute a command which can't happen in the case of events
.
Examples of commands can be load-data
, prepare-order
, execute-payment
.
; { const user = Bob: job: 'Software developer' userId: 1 ; ;} { const userInfo = ; console; // {userId: 1, job: 'Software Developer'}} ;;
Commands handlers can be any kind of function sync or async it doesn't matter genix
will handle them correctly, and also from commands handlers we can emit events
.
Testing
Before was mentioned that low coupling is one of the main goals of genix
making in this way applications easier to test. In order to achieve that genix
allow us wrap our function to emit events and commands against them, let's see an example:
Suppose that we have a counter
function which is in charge to increment and decrement a specific value, this function wil react to increment
command, also it expose a command get-value
that return the actual value of our counter. Also this function has a handler for state-restored
event which will cause that our counter goes to zero.
; { let value = 0; ; ; ;} ;
Now is time to test this function so we can ensure that it work correctly, let's see how genix
can help us with that:
;; ;
Before continue with more tests a few things should be notice. First as we mention genix
allow us wrap our functions so we can exec
commands against it and also emit
events.
This operations are lazy in the sense that they are executed when the run
function is called not before that. The run
is asynchronous so this has as consequence that every test that use a genix
wrapper should be an async
test.
After executed run
we got and object that have a data
property with the return value of the last command executed in our chain of operations for example if we execute this operations increment
, state-restored
, get-value
then data
will have the return value of get-value
because it was the last command executed.
Last but not least **functions using genix
capabilities always should be wrapped in order to be tested, this is highly recommended in order to avoid race conditions and incorrect behaviors during testing.
Being said this let's write a few more tests:
; ;
Mocked commands
Sometimes we use a command inside of some handler, for example let's say that in the previous example our handler for increment
event execute a get-amount
command that return how much should be increased
;
In this example our handler depends on get-amount
command, with genix
is very simple mock this command in order to test our increment
handler:
;
Using the onCommand
function we are able to set the response to any command used when our wrapper run, this is very util when we have handlers using commands from external dependencies like databases.
This are basic examples but show some of the capabilities of genix
during testing, there missing parts here as inject fake commands during tests, capture events triggered during function execution. All of this will be covered in a section dedicated to fully cover the testing API in depth.
Examples
Future Plans
- Improve documentation.
- Add more examples.
- Improve type coverage in the source code.
- Integrate with React.js.
- Integrate
genix
to use web workers under the hood.