In this presentation speaker considered theoretical basics of using the redux-saga library, which was created for facilitating the organization of the so-called “side effects” (for example, asynchronous operations). The event participants obtained practical tips on using saga in real-life projects.
This presentation by Igor Nesterenko (Lead Software Engineer, Consultant, GlobalLogic, Kharkiv) was delivered at GlobalLogic Kharkiv JS TechTalk #2 on August 17, 2018.
4. 4
Problem
1. Side-effects are roots of errors and mistrust
• Async (aka concurrency) is hard
2. A program without side effects is useless
3. React and redux don’t solve that all issue
15. 15
Terms
1. Effect - is a single, atomic predefined instruction or command
(POJO)
2. Saga - collection of effects, realized in form of ES6 generator
3. Saga Middleware - redux middleware to execute sagas
4. Effect Creator - function to create effect objects
5. Channels - queues for actions
6. Helper and Untils - helper functions for day to day tasks, factory
function to wrap external IO or event channels
32. 32
Fork Model - Error PropagationFork Model
Fetch All
Fetch Comments
Fetch Users
main
Blocking Call
Non-blocking Call
Catch All Errors Catch Forks Errors
45. 45
Channels - Communication Between Sagas
Fork 1
Fork 2
Fork 3
Saga
Shared Channel
aka load balancing
Push message to free fork
create
46. 46
Channels - Communication Between Sagas
function* watchRequests() {
const chan = yield call(channel)
for (var i = 0; i < 3; i++) {
yield fork(handleRequest, chan)
}
while (true) {
const {payload} = yield take('REQUEST')
yield put(chan, payload)
}
}
47. 47
Channels - Communication Between Sagas
function* handleRequest(chan) {
while (true) {
const payload = yield take(chan)
// process the request
}
}
56. 56
Unit Testing - Clonable Generator - First Branch
const gen = cloneableGenerator(doStuffThenChangeColor)();
// ...
const clone = gen.clone();
assert.deepEqual(
clone.next(chooseNumber(2)).value,
put(changeUI('red')),
'should change the color to red'
);
57. 57
Unit Testing - Clonable Generator - Second Branch
const gen = cloneableGenerator(doStuffThenChangeColor)();
// ...
const otherClone = gen.clone();
assert.deepEqual(
otherClone.next(chooseNumber(3)).value,
put(changeUI('blue')),
'should change the color to blue'
);
74. 74
Invest in Error Handling
1. Acton Error Naming Convention
• like “*_ERROR” postfix in actions naming
2. Unified way to make requests, I/O
3. Logger and some UI to show error to the user
78. 78
Unit Testing Strategy
1. Start from covering top flows for example
• must have watchAuth, watchCheckout
• nice to have watchEntities
2. Cover reusable sagas like standartRequest, runAfterAuth
82. 82
Summary
1. Inspired by Saga pattern, however it’s not exact implementation of Saga
pattern
2. Provides constraints to handle side-effects in one place
3. Allows maintainable unit testing of side-effect (without mocking)
4. Saga works great for side-effects, but produces code smells if used for
other tasks like routing, data massaging (aka reducers logic)
88. 88
Side-Effects
● State/Assignments
● Read/Write Data
● Communicate Over Network
● Raise Exception
● DOM
In computer science, a function or expression is said to have a
side effect if, in addition to producing a value, it also modifies
some state or has an observable interaction with calling
functions or the outside world
89. 89
Give Me a Label
const label = await this.getLabel();
90. 90
May Launch Missiles
async function getLabel () {
const val = Math.random();
if (val > 0.5){
await launchMissles();
return `foo foo ${val}`
}
return `blah blah ${val}`;
}
91. 91
Why should I care about side effects ?
“Side effects are lies. Your function promises to do one thing,
but it also does other hidden things...they are devious and
damaging mistruths that often result in strange temporal
couplings and order dependencies.”
Clean Code, Robert Martin
92. 92
Things to remember
● A program without side effects is useless
● Side effects are neither evil nor taboo
● The key is to
○ limit side effects
○ clearly identify them
○ avoid scattering them throughout the code.
93. 93
Minuses
● issues with stacktrace
● more boilerplate code
● structuring sagas
● learning curve
96. 96
Basics Concepts
1. Separate Instructions from Execution
2. Use ES6 generator to define set of instructions
3. Use redux middleware to execute instructions
4. Execution works with `pull-future-actions` approach
97. 97
Saga
1. Improve Loose Coupling (SR, Component and Actions)
2. Something on top of async/await, Observables
3. Maintainable Unit Testing (without mocks)
4. Makes important business flows explicitly defined in code
5. More explicit error handling techniques