The document discusses various topics related to reactive and functional programming including NGRX, RxJS, Redux, Reactive Streams specification, and computing derived data using Reselect. It provides code examples for setting up an NGRX application with state management, effects, selectors, and composing the root reducer. It also discusses hot and cold streams, converting cold streams to hot, and the anatomy of RxJS operators.
3. 3
NGRX Apps in Depth
State management, event sourcing, DDD, reactive
programming, and stream based service architectures
Flux, Redux & NGRX: Reactive Extensions for Angular
Composing NGRX Reducers, Selectors & Middleware
Computing derived data (memoization): Reselect, RxJS
Observable (hot) streams of async actions – isolating
side effects using @Effect & RxJS reactive transforms
NGRX-Router integration, Material Design, PrimeNG
Normalization/denormalization, local data – IndexedDB
Example app – code structure, lazy loading, etc.
4. Where to Find the Demo Code?
4
Angular and NGRX demos are available @GitHub:
https://github.com/iproduct/course-angular
ipt-knowledge-manager – NGRX, Reselect, RxJS
@Effects, modules lazy loading, AOT
angular2-change-detection-demos – modified from
https://github.com/thoughtram/angular2-change-
detection-demos
ngrx-example-app – NGRX official demo from
https://github.com/ngrx/example-app, IndexedDB
5. Data / Event / Message Streams
5
“Conceptually, a stream is a (potentially never-ending)
flow of data records, and a transformation is an
operation that takes one or more streams as input,
and produces one or more output streams as a
result.”
Apache Flink: Dataflow Programming Model
6. Data Stream Programming
6
The idea of abstracting logic from execution is hardly
new -- it was the dream of SOA. And the recent
emergence of microservices and containers shows that
the dream still lives on.
For developers, the question is whether they want to
learn yet one more layer of abstraction to their coding.
… there's the elusive promise of a common API to
streaming engines that in theory should let you mix and
match, or swap in and swap out.
Tony Baer (Ovum) @ ZDNet - Apache Beam and Spark:
New comopetition for squashing the Lambda Architecture?
7. Listen to Quark:
7
“Good things come in small packages”
Quark – Star Trek DS9 character
https://en.wikipedia.org/w/index.php?curid=12544179, Star Trek: Deep Space Nine, "Emissary", Fair use
8. Lambda Architecture - I
8
https://commons.wikimedia.org/w/index.php?curid=34963986, By Textractor - Own work, CC BY-SA 4
9. Lambda Architecture - II
9
https://commons.wikimedia.org/w/index.php?curid=34963987, By Textractor - Own work, CC BY-SA 4
10. Lambda Architecture - III
10
Data-processing architecture designed to handle
massive quantities of data by using both batch- and
stream-processing methods
Balances latency, throughput, fault-tolerance, big data,
real-time analytics, mitigates the latencies of map-
reduce
Data model with an append-only, immutable data
source that serves as a system of record
Ingesting and processing timestamped events that are
appended to existing events. State is determined from
the natural time-based ordering of the data.
11. Druid Distributed Data Store
11
https://commons.wikimedia.org/w/index.php?curid=33899448 By Fangjin Yang - sent to me personally, GFDL
Apache
ZooKeeper
MySQL /
PostgreSQL
HDFS /
Amazon S3
14. 14
Performance is about 2 things:
– Throughput – units per second, and
– Latency – response time, responsiveness - especially
important from end user perspective (front-end)
Real-time – time constraint from input to response
regardless of system load.
Hard real-time system if this constraint is not honored then
a total system failure can occur.
Soft real-time system – low latency response with little
deviation in response time
100 nano-seconds to 100 milli-seconds. [Peter Lawrey]
What High Performance Means?
16. Tracking Complexity
16
We need tools to cope with all that complexity inherent in
real world applications.
Simple solutions are needed – cope with problems through
divide and concur on different levels of abstraction:
Domain Driven Design (DDD) – back to basics:
domain objects, data and logic.
Described by Eric Evans in his book:
Domain Driven Design: Tackling Complexity in the Heart of
Software, 2004
17. Microservices and DDD
17
Main concepts:
Entities, value objects and modules
Aggregates and Aggregate Roots:
value < entity < aggregate < module < BC
Aggregate Roots are exposed as Open Host Services
Hexagonal architecture :
OUTSIDE <-> transformer <->
( application <-> domain )
18. Imperative and Reactive
18
We live in a Connected Universe
... there is hypothesis that all
the things in the Universe are
intimately connected, and you
can not change a bit without
changing all.
Action – Reaction principle is
the essence of how Universe
behaves.
19. Imperative and Reactive
Reactive Programming: using static or dynamic data
flows and propagation of change
Example: a := b + c
Functional Programming: evaluation of mathematical
functions,
➢ Avoids changing-state and mutable data, declarative
programming
➢ Side effects free => much easier to understand and
predict the program behavior.
Example: Observable.from(['Reactive', 'Extensions','JS'])
.take(2).map(s => `${s}: on ${new Date()}`)
.subscribe(s => console.log(s));
20. Functional Reactive (FRP)
20
According to Connal Elliot's (ground-breaking paper
@Conference on Functional Programming, 1997), FRP is:
(a) Denotative (Compositional): Observables can be
composed with higher-order combinators
(b) Temporally continuous (Lazy): Observables do
not start emitting data until an Observer has
subscribed
22. 22
Message Driven – asynchronous message-passing
allows to establish a boundary between components
that ensures loose coupling, isolation, location
transparency, and provides the means to delegate
errors as messages.
[Reactive Manifesto]
Scalable, Massively Concurrent
26. 26
RxJS – JS ReactiveX (Reactive Extensions)
[http://reactivex.io, https://github.com/ReactiveX]
ReactiveX is a polyglot library for composing asynchronous
event streams (observable sequences).
It extends the observer pattern by declarative composition of
functional transformations on events streams (e.g. map-filter-
reduce, etc.)
Abstracs away low-level concerns like concurrency,
synchronization, and non-blocking I/O.
Follows the next - error - completed event flow
Allows natural implementation of Redux design pattern
Alternative (together with promises) for solving “callback hell”
problem
31. Hot and Cold Event Streams
31
PULL-based (Cold Event Streams) – Cold streams are
streams that run their sequence when and if they are
subscribed to. They present the sequence from the start
to each subscriber.
PUSH-based (Hot Event Streams) – Hot streams emit
values independent of individual subscriptions. They
have their own timeline and events occur whether
someone is listening or not. An example of this is
mouse events. A mouse is generating events regardless
of whether there is a subscription. When subscription is
made observer receives current events as they happen.
36. Source: RxJS docs, https://github.com/ReactiveX/rxjs/blob/master/doc/tutorial/applications.md
Redux in Plain RxJS
import Immutable from 'immutable';
import someObservable from './someObservable';
import someOtherObservable from './someOtherObservable';
var initialState = { foo: 'bar' };
var state = Observable.merge(
someObservable,
someOtherObservable
).scan((state, changeFn) => changeFn(state),
Immutable.fromJS(initialState));
export default state;
37. Source: RxJS docs, https://github.com/ReactiveX/rxjs/blob/master/doc/tutorial/applications.md
Redux in Plain RxJS
state.js:
import Immutable from 'immutable';
import someObservable from './someObservable';
import someOtherObservable from './someOtherObservable';
var initialState = { foo: 'bar' };
var state = Observable.merge(
someObservable,
someOtherObservable
).scan((state, changeFn) => changeFn(state),
Immutable.fromJS(initialState));
export default state;
38. Redux in Plain RxJS
client.js:
import state from './state';
state.subscribe(state => {
document.querySelector('#text').innerHTML =
state.get('foo');
});
Source: RxJS docs, https://github.com/ReactiveX/rxjs/blob/master/doc/tutorial/applications.md
39. NGRX: Reactive Extensions for Angular
core – core functionality for the ngrx platform
store – RxJS powered state management for Angular
applications, inspired by Redux
router-store – bindings to connect the Angular Router to
@ngrx/store
effects – side effect model for @ngrx/store
db – RxJS powered IndexedDB for Angular apps
notify – Web Notifications powered by RxJS for Angular
store-devtools, store-log-monitor - dev tools, monitoring
example-app – example app showcasing ngrx platform
42. NGRX: Composing Root Reducer
in root.reducer.ts:
const developmentReducer: ActionReducer<S> =
compose(storeFreeze, combineReducers)(reducers);
const productionReducer: ActionReducer<S> =
combineReducers(reducers);
export function rootReducer(state: any, action: any) {
if (environment.production) {
return productionReducer(state, action)
} else {
return developmentReducer(state,action)
}
}
Store Middleware Composition
Needs to be statically importable by AOT
43. NGRX Selectors
A selector function is a factory for mapping functions.
Returned function maps from larger state tree into a feature
substate tree (destructing the larger state).
Selectors are used with the `select` ngrx Store operator.
Following example shows selector selecting the `users`
sub-state:
class ClientComponent {
constructor(store$: Observable<State>) {
this.usersState$ = store$.select(getUsersState);
}
}
46. Computing Derived Data: Reselect
Selectors can compute derived data, allowing Redux to
store the minimal possible state.
Selectors are efficient. A selector is not recomputed
unless one of its arguments change.
Selectors are composable. They can be used as input
to other selectors.
Works correctly only when combined with immutability.
48. Can You Spot the Problem Here?
const isFirstTodoCompleteSelector = createSelector(
state => state.todos[0], todo => todo && todo.completed)
export default function todos(state = initState, action)
{
switch (action.type) {
case COMPLETE_ALL:
const allMarked = state.every(todo => todo.completed)
return state.map(todo => {
todo.completed = !allMarked
return todo
})
default: return state
}}
49. Can We Memoize without Reselect?
In users/components/user-list.component.ts:
public ngOnInit() {
this.store.dispatch(this.userActions.loadUsers());
this.subscription = this.selectedId$
.filter(id => !!id)
.distinctUntilChanged()
.subscribe(id => this.store.dispatch(
go(['users', id])));
51. State Normalization / Denormalization
[http://redux.js.org/docs/recipes/reducers/NormalizingStateShape.html]
When a piece of data is duplicated in several places, it
becomes harder to make sure that it is updated
appropriately
Nested data means that the corresponding reducer
logic has to be more nested or more complex. In
particular, trying to update a deeply nested field can
become very ugly very fast.
Since immutable data updates require all ancestors in
the state tree to be copied and updated as well, an
update to a deeply nested data object could force
totally unrelated UI components to re-render even if the
data they're displaying hasn't actually changed.
52. Example: Users State Normalization
export interface State {
ids: IdentityType[];
entities: { [id: string]: User };
selectedUserId: IdentityType | null;
loading: boolean;
};
export const initialState: State = {
ids: [],
entities: {},
selectedUserId: null,
loading: false
};
export function usersReducer(state = initialState,
action: Action): State {
switch (action.type) { ...
53. IndexedDB
IndexedDB is a low-level API for client-side storage of
significant amounts of structured data (key-value pairs),
including files/blobs.
API uses indexes to enable high-performance searches
of this data. Web Storage - useful for smaller data.
IndexedDB is built on a transactional database model –
everything you do in IndexedDB always happens in the
context of a transaction.
The IndexedDB API is mostly asynchronous – you have
to pass a callback function.
IndexedDB uses DOM events to notify you when
results are available - type prop ("success" or "error").
58. export function addReducer<S>(name: string, reducer:
ActionReducer<S>): void {
reducers[name] = reducer;
devProdReducers['developmentReducer'] =
compose(storeFreeze, combineReducers)(reducers);
devProdReducers['productionReducer'] =
combineReducers(reducers);
}
export function rootReducer(state: any, action: any) {
if (environment.production) {
return devProdReducers.productionReducer(state, action)
} else {
return devProdReducers.developmentReducer(state,action)
}
}
How to Lazy Load Reducers? - II
This works happily with AOT!
59. in lazy loaded module (users/user.module.ts):
@NgModule({ ... })
export class UserModule {
constructor() {
addReducer<UserState>('users', usersReducer);
}
}
export interface RootState extends OldRootState {
users: UserState;
}
Then everywhere in lazy loaded module import augmented
RootState from that lazy loaded module (from
users/user.module.ts, not from root.reducer.ts).
Adding New Lazy Loaded Reducer
60. Where to Find the Demo Code?
60
Angular and NGRX demos are available @GitHub:
https://github.com/iproduct/course-angular
ipt-knowledge-manager – NGRX, Reselect, RxJS
@Effects, modules lazy loading, AOT
angular2-change-detection-demos – modified from
https://github.com/thoughtram/angular2-change-
detection-demos
ngrx-example-app – NGRX official demo from
https://github.com/ngrx/example-app, IndexedDB
61. Thank’s for Your Attention!
61
Trayan Iliev
CEO of IPT – Intellectual Products
& Technologies
http://iproduct.org/
http://robolearn.org/
https://github.com/iproduct
https://twitter.com/trayaniliev
https://www.facebook.com/IPT.EACAD
https://plus.google.com/+IproductOrg