Redux…

I have mixed feelings about Redux. I really like the general ideas behind Redux, and how nice they’ve explained how and when to use it. I do not like the implementation however. The main reason for that, is that they invented their own vocabulary around existing design patterns. This distracts you from the patterns they use and that in turn complicates learning.

Why would one call something a “reducer” when it is in fact a “mediator”. Why would you call something an “action” when it is a “command”? The most important Redux framework method is called “dispatch” while it has nothing to do with events. As it invokes a command on the state, it should have been called “invoke” or “invokeCommand”. If they had done a better job on that it would have been clear that we are talking about a basic implementation of the Command pattern.

Another thing I struggle with is that they pass strings around to define which actual commands to execute. Inside the “dispatch” method they call the “reducer” which uses a switch statement to finally invoke the actual required command.

function counter(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1
    case 'DECREMENT':
      return state - 1
    default:
      return state
  }
}

This is very difficult to maintain and almost impossible to refactor. The only good part about it, is that you can easily serialize and store the list of executed “commands” and then deserialize and replay that list on the initial state, to get to the current state. How useful that is, depends on your application. I do think it is at least a bit smelly.

Eventually I decided to create my own predictable state container using TypeScript and standard design patterns.

My own predictable state container

Let’s start with the core.ts:

namespace Core {
    "use strict";

    export interface ICommand<S> {
        execute(state: S): S;
        undo(state: S): S;
    }

    export interface IInvoker<S> {
        invoke(command: ICommand<S>): void;
    }

    export interface IRecorder {
        canUndo: boolean;
        undo(): void;

        canRedo: boolean;
        redo(): void;
    }

    export interface IObservable {
        subscribe(callback: () => void): number;
        unsubscribe(id: number): void;
    }

    export interface IContext<S> {
        state: S;
    }

    interface ISubscription {
        id: number;
        callback: () => void;
    }

    export class Context<S> implements IContext<S>, IInvoker<S>, IObservable  {
        private _state: S;

        constructor(initialState: S) {
            this._state = initialState;
        }

        public get state(): S {
            return this._state;
        }

        protected setState(state: S): void {
            this._state = state;
            this.notify();
        }

        public invoke(command: ICommand<S>): void {
           const state: S = command.execute(this.state);
           this.setState(state);
        }

        private _subscriptionId = 0;
        private _subscriptions: ISubscription[] = [];

        public subscribe(callback: () => void): number {
            const id: number = ++this._subscriptionId;
            this._subscriptions.push({ id: id, callback: callback });
            return id;
        }

        public unsubscribe(id: number): void {
            this._subscriptions = this._subscriptions.filter((value: ISubscription) => {
                return value.id !== id;
            });
        }

        private notify(): void {
            this._subscriptions.forEach((value: ISubscription) => {
                value.callback();
            });
        }
    }

    export class RecordingContext<S> extends Context<S> implements IRecorder {
        private _commands: ICommand<S>[] = [];
        private _current: number = -1;

        constructor(initialState: S) {
            super(initialState);
        }

        public invoke(command: ICommand<S>): void {
            super.invoke(command);
            this._commands.splice(this._current + 1);
            this._current = this._commands.push(command) - 1;
        }

        public get canUndo(): boolean {
            return this._current >= 0;
        }

        public undo(): void {
            if (this.canUndo) {
                const command: ICommand<S> = this._commands[this._current--];
                const state: S = command.undo(this.state);
                this.setState(state);
            }
        }

        public get canRedo(): boolean {
            return this._current < this._commands.length - 1;
        }

        public redo(): void {
            if (this.canRedo) {
                const command: ICommand<S> = this._commands[++this._current];
                const state: S = command.execute(this.state);
                this.setState(state);
            }
        }
    }
}

The core consists of no more than a few interfaces and two generic classes. One class that maintains a list of executed commands, and one that does not. Why I like my implementation better is because I use the same commonly known design patterns, but with the standard vocabulary. Besides that my commands are also passed strongly typed. Which makes it refactorable and maintainable, and prevents you from making typo’s. The drawback is that they are not serializable anymore. Up to you to decide here. Compiled and minified to ECMAScript 6, the whole core takes up no more than 1kb.

Let’s have a look on how to use this core library when we create React.Components in a UI.tsx:

namespace UI {
    "use strict";

    export interface ICounterProps<S> {
        context: Core.Context<S>;
        getValue: (context: Core.Context<S>) => any;
        incrementCommand: Core.ICommand<S>;
        decrementCommand: Core.ICommand<S>;
    }

    export interface ICounterState {
        value: number;
    }

    export class Counter<S> extends React.Component<ICounterProps<S>, ICounterState> {
        private _subscription: number;

        constructor(props: ICounterProps<S>) {
            super(props);
            this.state = {
                value: this.props.getValue(this.props.context)
            };
        }

        public componentDidMount(): void {
            this._subscription = this.props.context.subscribe(() => {
                this.setState({
                    value: this.props.getValue(this.props.context)
                });
            });
        }

        public componentWillUnmount(): void {
            this.props.context.unsubscribe(this._subscription);
        }

        public render(): JSX.Element {
            const buttonStyle: React.CSSProperties = { minWidth: "50px" };
            const {context, incrementCommand, decrementCommand} = this.props;
            const {value} = this.state;

            return (<div>
                Value: {value}
                <div>
                    <button
                        style={buttonStyle}
                        onClick={() => context.invoke(incrementCommand)}>
                        +
                    </button>
                    <button
                        style={buttonStyle}
                        onClick={() => context.invoke(decrementCommand)}>
                        -
                    </button>
                </div>
            </div>);
        }
    }

    export interface IUndoRedoProps {
        context: Core.IRecorder & Core.IObservable;
    }

    export class UndoRedo extends React.Component<IUndoRedoProps, {}> {
        private _subscription: number;

        constructor(props: IUndoRedoProps) {
            super(props);
        }

        public componentDidMount(): void {
            this._subscription = this.props.context.subscribe(() => {
                this.forceUpdate();
            });
        }

        public componentWillUnmount(): void {
            this.props.context.unsubscribe(this._subscription);
        }

        public render(): JSX.Element {
            const buttonStyle: React.CSSProperties = { minWidth: "50px" };
            const {context } = this.props;

            return (<div>
                <button
                    style={buttonStyle}
                    disabled={!context.canUndo}
                    onClick={() => context.undo()}>
                    undo
                    </button>
                <button
                    style={buttonStyle}
                    disabled={!context.canRedo}
                    onClick={() => context.redo()}>
                    redo
                    </button>
            </div>);
        }
    }
}

The important part here is that we pass Core.ICommand<S> for binding to events instead of strings.

So let’s have a look at the App.tsx

namespace App {
    "use strict";

    const update: (value: any, spec: React.UpdateSpec) => any = React.addons.update;

    interface IState {
        number: number;
        char: string;
    }

    class Context extends Core.RecordingContext<IState> {
        constructor() {
            super({ number: 0, char: "a" });
        }
    }

    const Commands = {
        IncrementNumber: {
            execute: (state: IState): IState =>
                update(state, { number: { $set: state.number + 1 } }),
            undo: (state: IState): IState =>
                update(state, { number: { $set: state.number - 1 } })
        },
        DecrementNumber: {
            execute: (state: IState): IState =>
                update(state, { number: { $set: state.number - 1 } }),
            undo: (state: IState): IState =>
                update(state, { number: { $set: state.number + 1 } })
        },
        IncrementChar: {
            execute: (state: IState): IState =>
                update(state, { char: { $set: String.fromCharCode(state.char.charCodeAt(0) + 1) } }),
            undo: (state: IState): IState =>
                update(state, { char: { $set: String.fromCharCode(state.char.charCodeAt(0) - 1) } })
        },
        DecrementChar: {
            execute: (state: IState): IState =>
                update(state, { char: { $set: String.fromCharCode(state.char.charCodeAt(0) - 1) } }),
            undo: (state: IState): IState =>
                update(state, { char: { $set: String.fromCharCode(state.char.charCodeAt(0) + 1) } })
        }
    };

    export function init(): void {
        const root: HTMLElement = document.getElementById("root");
        const context: Context = new Context();

        type Counter = new () => UI.Counter<IState>;
        const Counter: Counter = UI.Counter as Counter;

        ReactDOM.render(<div>
            <Counter
                context={context}
                getValue={(context: Context) => context.state.number}
                incrementCommand={Commands.IncrementNumber}
                decrementCommand={Commands.DecrementNumber} />
            <Counter
                context={context}
                getValue={(context: Context) => context.state.char}
                incrementCommand={Commands.IncrementChar}
                decrementCommand={Commands.DecrementChar} />
            <hr />
            <UI.UndoRedo
                context={context} />
        </div>
            , root
        );
    };
}

window.addEventListener("load", (ev: Event) => {
    App.init();
});

There are a lot of way’s to define commands now. In the above example I’ve created a const Commands object that contains the command objects as I do not need any per command state or properties. You could of course do something like this to define a custom command just as well:

class CustomIncrementCommand implements Core.ICommand<IState> {
    private properties:ICustomIncrementCommandProps;
    constructor(properties: ICustomIncrementCommandProps) {
        this.properties = properties;
    }

    public execute(state: IState): IState {
        return update(state, { number: { $set: state.number + properties.incrementValue} });
    }

    public undo(state: IState): IState {
        return update(state, { number: { $set: state.number - properties.incrementValue} });
    }
}

You could then pass the constructor to your components and in the component itself, create a new instance of the command, with the properties based on the current component state.

All in all we now have a complete, generic, strongly typed predictable state container using TypeScript and standard design patterns, that also uses the proper vocabulary.

UPDATE:
That same friend asked me if he should now use my implementation of a predictable state container or the standard Redux implementation. That should be the Redux implementation of course! There are a lot of people working on maintaining Redux and there are a lot of (browser)plugins that you can use with the standard Redux implementation. The value of Redux is not just in Redux itself, but also the eco-system around it. The reason I wrote this article and a sample on how I would do it, is just because I think that if they’d at least adhered to the standard design patterns, it would have been a lot easier to learn how to use Redux.

Have fun,

Wesley

Who needs documentation?

While working on a solution that is supposed to list Azure Resources using client side code, I came into contact with Azure Resource Manager REST API. And honestly this is a pretty awesome collection of API’s! Now the whole issue with this API is that it is actually a constantly changing collection of API’s and that there is no documentation available at all. How useful is that?

Sure they’ve written an article with the title “Azure Resource Manager REST API Reference”, but it contains high level information only. They actually tell you that the best way you can find out what will be returned by the API, is by using a tool they call Azure Resource Explorer.

The first issue I have with that, is that you can only execute calls on resources that you’ve got in your Azure Subscription. So if you would like to find out what response will be returned when you request information on a Storage Resource, you will first have to create such a resource in your Azure Subscription. You can then use the Azure Resource Explorer, to see the JSON result returned. This will tell you nothing of course about the actual schema that you can expect.

The second issue I have with that, is that I have no way of creating a decent client side proxy with something like T4 templating. So it took me a couple of weeks to create a client side proxy to get only the basic information and it’s all based on guessing. Good job Microsoft!

Did nobody at Microsoft every heard about something like Swagger?

UPDATE:
Microsoft did hear about Swagger! Their own PowerApps product can connect to custom API’s as long as you can provide the definition file in… Swagger format! But wait. “Does that mean that I cannot connect to Microsoft’s own Graph API to fetch person details into my PowerApp unless I create the Swagger definition file manually?” Yes… sigh.

ADAL JS and zones in IE and Edge

Active Directory Authentication Library for JavaScript (ADAL JS) is actually a very nice library to take care of your authentication against Azure Active Directory. Unfortunately the library doesn’t work with IE or Edge as soon as the web application that is using the ADAL JS library is in a different security zone than “https://login.microsoftonline.com”. The reason for this is that IE and Edge don’t allow cookie sharing between zones. Since “https://login.microsoftonline.com” should not reside in any security zone this means that your application cannot be in any zone either. Now why is this such a huge problem?

Most of the applications you register in Azure Active Directory will in fact be internal applications. And most of these applications will reside in the “Local intranet” zone or “Trusted sites” zone. And exactly those applications won’t work with the ADAL JS library if the client is using IE or Edge, unless you add “https://login.microsoftonline.com” to that same zone.

Adding “https://login.microsoftonline.com” to a specific zone, might solve you issue for one application, but if you have applications in both the “Local intranet” zone and the “Trusted sites” zone, you are out of luck as sites (including “https://login.microsoftonline.com”) cannot be part of multiple zones.

In each and every other browser you will not encounter any of these issues as the don’t have this cookie sharing limitation.

I wonder if when they will solve this issue, because the advice to just remove “protected mode” for the “Internet zone” on the ADAL JS GitHub site, makes me shiver when I realize that these same people wrote this authentication library.