Kdo easily organizes and executes small functions or files (as "NodeJS Best Practices" recommended), more better than plain functions (why), makes the code clear, easy to read and maintain. Kdo requires Node.js 7.6+ for async/await.
Kdo itself spreads the code into multiple small functions and files too. Noapi (a light API framework for Node.js, easily define, I/O and test) is a good usage of Kdo, it is recommended to read its source code.
npm i kdo --save
Test:
git clone https://github.com/hiowenluke/kdo
cd kdo
npm install
npm test
See examples to learn more.
There are many benefits to using kdo + flow (object or files) instead of plain functions.
The code in main function is complicated, pass the same parameters to multiple tasks, return new parameters from the task, and pass the new parameters to the next tasks, these make the code look uncomfortable and not easy to read.
And, the main problem is that the main function performs data dis-assembly and transfer. When we change the input and output parameters of the sub-function, we have to modify the related code in the main function at the same time, which means that the sub-function are not completely encapsulated.
Each of the functions is very concise and the logic is clear and easy to understand.
- pass the arguments and data
- update the arguments via this.pass() or this.save()
- update the arguments via this.args
- update the arguments via return args
The code that handles flag === 1 is spread across two places, f2 and main. When we change the condition of flag === 1, we need to modify these two places. If the code is long, or these functions spread across many files, then we may miss something.
And, the code in main function will not elegant (yes, writing elegant code is one of my goals).
The condition flag ===1 is met in f2, so the f3 will be ignored. We do not need to add redundant code in main function.
Sometimes, in order to make the code structure clear, we classify the flow code into multiple files in a multi-level directory.
In the task flow, after a file is processed, if a non-undefined value is returned, kdo will terminate the subsequent processing and return it to the main function.
We do not need to write additional complex code. Yes, if we use plain functions instead of kdo, there must be a lot of redundant code to handle the same logic.
- return value, 09-flow
- return value via this.return
- return the specified argument
- return all arguments
We can use kdo to easily organize small files in multi-levels directories, require them as an object, and access the functions or any other properties of it.
When we spread our business flows across multiple files in multi-levels directories, managing these flows is a big problem. This problem can be easily solved with kdo.
Kdo can easily requires the entire directory (including sub-directories) as flow object. So, we can split the long code into multiple files in multi-levels directories, without any restrictions.
// require the directory (including sub-directories) as a flow object
const flow = kdo('./01-flow');
const main = async () => {
// execute all functions in flow object one by one
// according to the order of the directory name and file name.
const result = await kdo.do(flow);
return result;
};
module.exports = main;
If our directories and files are as following:
/f1
/f12
f121.js
f122.js
f11.js
f13.js
/f2
f21.js
f22.js
f3.js
Then the order of execution will be like following (cool, right?):
f11, f121, f122, f21, f22, f3
See below examples to learn more.
Further more, we can specify the order of execution in index.js under directory, like below:
// index.js
const options = {
first: 'f3', // execute these functions at first
last: ['f7', 'f4'], // execute these functions at last
exclude: 'f5', // do not execute these functions
};
module.exports = kdo.flow(options);
See below examples to learn more.
Kdo can easily requires the entire directory (including sub-directories) as a independent module, the main function does not needs to care about the details of it, just call it.
// index.js
const kdo = require('kdo');
// Kdo.flow() returns a function which does the following:
// 1. Requires the current directory (including sub-directories) as a flow object
// 2. Executes all functions in the flow object one by one
module.exports = kdo.flow();
Then require it in main function, and execute it.
// Require the sub-directory as a function which wrapped by kdo.
// Means, the sub-directory is a fully independent module, the main
// function does not needs to care about the details of it, just call it.
const flow = require('./01-flow');
const fn = async () => {
const args = {a1: 1, a2: 2, a3: 3};
// Execute the flow function, get the result.
const result = await flow(args);
return result;
};
module.exports = fn;
See below examples to learn more.
Why we should split long code into small functions or files?
As "Node.js Best Practices" said:
The worst large applications pitfall is maintaining a huge code base with hundreds of dependencies - such a monolith slows down developers as they try to incorporate new features. Instead, partition your code into components, each gets its own folder or a dedicated codebase, and ensure that each unit is kept small and simple.
Otherwise: When developers who code new features struggle to realize the impact of their change and fear to break other dependent components - deployments become slower and riskier. It's also considered harder to scale-out when all the business units are not separated.
Simply put, this can leads to MURDER which is a good thing (the answer comes from stackOverflow, by John Dibling):
- M - Maintainability. Smaller, simpler functions are easier to maintain.
- U - Understandability. Simpler functions are easier to understand.
- R - Reuseability. Encourages code reuse by moving common operations to a separate function.
- D - Debugability. It's easier to debug simple functions than complex ones.
- E - Extensibility. Code reuse and maintainability lead to functions that are easier to refactor in 6 months.
- R - Regression. Reuse and modularization lead to more effective regression testing.
- Unix principle: "Do one thing and do it well" — Doug McIlroy
- Clean Code: "The first rule of functions is that they should be small" — Robert C. Martin
- Clean Code JavaScript: "Prefer small functions over classes" — Ryan McDermott
- The Art of Writing Small and Plain Functions — Dmitri Pavlutin
- 12 tips for writing clean and scalable JavaScript — Lukas Gisder-Dubé
- “Function calls are expensive” vs. “Keep functions small” — Tomasz Nurkiewicz
- Clean Code vs. Dirty Code: React Best Practices — Donavon West
- JavaScript Best Practices: "Small functions rather than 'smart' functions" — Tomas Kirda
Copyright (c) 2019, Owen Luke