Project Process and Documentation

In my previous post, I described a default architecture for a UI application. In this post, I will introduce the concept for a system that requires a UI application (as well as other software packages) and briefly describe a process for discovering system requirements (user stories, scenarios, and feature specifications). Once the system requirements are defined, and using system architecture guidelines like the one in the previous post, product requirements can be defined.

The first step in a project’s life-cycle is the establishment of a project charter. Given that this is a fictitious project, there isn’t a real project charter. However, I did create a wiki (warning: be sure to have an ad blocker running) to keep track of some overly simplistic artifacts to use as a place to keep my ideas straight as I walk through the process of developing this conceptual project. Included in that wiki, is the Circulade Project Charter.

The overview of the Circulade system is to create a platform for enabling people trying to ship cargo to connect with carriers trying to fill their cargo containers for a route. This connection will allow shippers to find better shipping rates by finding containers with available space that can be purchased at a discounted price compared to standard shipping rates. Carriers will be able to make more money by selling space that would otherwise be left empty on an already planned shipment.

Once a project charter has been approved by the stakeholders, the project initiation process begins. However, since I want to keep focused on the deliverables of a project, I won’t be describing that process. For more details on project management, see the following:

To use terms from the PRINCE2 methodology, this post will be focused on the procedures in the Managing Product Delivery process. The “work package” to be delivered is the System Requirements for the project. This is accomplished by applying the business analysis process. The initial delivery of the System Requirements will consist of the most prominent User Stories and their most prominent Scenarios along with a list of Features the project will be expected to deliver and the Quality of Service requirements that will constrain the delivery of those features.

Business Analysis Process

System requirements specify the features a system must have in order to assist users with completing processes. These processes are described as Scenarios which detail a specific set of steps that are used to accomplish a User Story’s goal. Scenarios and User Stories are referred to as Business Requirements.

Business Requirements

User Stories

It is beyond the scope of this post to list all of these requirements, especially since this is a fictional system. However, the wiki contains some examples of the user stories used to produce this project.

If this were a real business, a Business Analyst would work with subject matter experts to elicit and document User Stories. More in-depth descriptions of user stories can be found at the following links:

For each user story, the analyst further examines the processes and procedures required to accomplish the goal of the story. This examination results in Scenario descriptions.

Scenarios

A scenario describes the process an actor must step through in order to achieve a goal . It specifies what information is needed, what decisions must be made based on that information and what to do with the result of those decisions. Another way of thinking about scenarios is to consider them “user flows” or “use cases”.

For existing organizations with detailed business process and procedure documentation, this activity is much easier, as the scenarios are essentially the process descriptions or are slightly modified versions of them as projects are usually intended to provide a new or improved process for the organization.

Again, some simplistic examples can be found on the Circulade wiki.

For more detailed examinations of the scenario writing process, read the following articles:

System Requirements

Features

Based on the Project Charter, User Stories, and Scenarios, a business analyst can specify the features a system must provide in order to enable the users to more efficiently accomplish their goals. For each Feature, a set of Feature Requirements will be defined.

This post provides a good example of the difference between a Feature and a Feature Requirement.

Quality of Service

QoS requirements are non-functional requirements such as availability, maintainability, extensibility, etc. These are important to capture in order to meet the expectations of the users and the stakeholders. The FURPS+ system is a useful way of thinking about these types of requirements in order to elicit these needs from the stakeholders and subject matter experts.

For the Circulade project, the system requirements examples are on the wiki.


Solutions Architecture Process

With the first batch of system requirements defined, a solutions architect, along with a user experience architect, should analyze the business requirements in order to identify any subsystems, or natural boundaries, within the organization and use these bounded contexts to define deployable packages of software/hardware necessary to fulfill the business requirements of the subsystems. This analysis is best handled by using the principles described by Domain-Driven Design. For a deep dive into these principles, see the following resources:

Once a bounded context has been identified and the software/hardware requirements are being determined, if the context requires a user facing application (and almost all of them do), the architects design the wireframes of the UI screens and detail the information needed for display and manipulation.

The solutions architect uses the system requirements analysis along with the wireframes and information details to specify the product requirements as a set of interface definitions.

The next post will explore the product requirements for the Circulade system’s public context.

Default Architecture for a UI Application

In this post I’m going to cover the default/general architectural structure that I use when building a UI application.

Application Architecture Composition

When designing the architecture of an application I like to break the package down into components. Each component is responsible for providing an interface to a set of cohesive features that can be loosely coupled with other components to provide the full set of features required by the application.

As a general rule and default starting place for a GUI application, the primary components will be an implementation of the MVC architectural pattern. This decision encourages the notion that there should be at least three components in our application: Model, View and Controller. In order for these components to be loosely coupled, the application will likely need a few services such as a message broker and a dependency injection service. So I’ll add another component called Service. All applications need to have an entry point into the package, so I’ll add one more component to the solution that will be called UI as this is the component that is responsible for providing users access to the application.

Within the Model component, there are two subcomponents: Command and Event. The Model.Command component isolates data structures used to represent user commands sent from objects in the View to objects in the Controller. The Model.Event component isolates data structures used to represent events raised by objects in the Model changing state.

Below is a UML component diagram that shows the dependency chain of these components. I used UMLetino to create the diagram.

component-dependency-diagram

 

The Model and the Service components are the most important since all of the other components depend on them. Also notice that neither the Model nor the Service components depend on any thing.

Model Component

The Model component is responsible for providing the state of the application and encapsulating the logic the application is providing the user the ability to work with. It is also responsible for declaring Command and Event objects that are used to model the behavior the application is modeling. For example, if the application was supporting an Accounts Receivable Clerk’s ability to create invoices, then there would likely be an Account object in the Model component, a GenerateInvoice object in the Command component and an InvoiceGenerated object in the Event component.

Most applications will require some sort of user security where a user must authenticate their credentials to prove their identity to the system and once their identity is recognized, the system will grant them authorization to access and potentially manipulate resources controlled by the system.

If the application requires tracking the state of a user, they could be modeled in a Session object. An active Session would have properties such as an Identity representing the user’s information such as name, title, contact information, etc.; and a set of authorization Claims representing the authorizations granted the user. It would also provide a method to end the Session. The commands and events corresponding to the Session would include objects such as AuthenticateCredentials, AuthenticationFailed, SessionInitialized, SessionStarted, and SessionEnded.

View Component

The View component is responsible for providing a visual representation of the state of the  objects in the Model component. Objects in the View component will use a message broker to subscribe to one or more Model.Event(s) in order to be notified when a Model object has changed its state.

Objects defined in the View component are responsible for translating user interactions into the appropriate Model.Command objects and publishing those commands via a message broker. Typically, applications display a nameplate/masthead that display the organization’s logo, controls for accessing the user’s profile, as well as the ability to logout, and a menu of links to resources/features of the application. These nameplates come in many styles and each system will require the application’s display stylistically match the organization’s branding. To design an application with this minimal feature, we would need to include Masthead, Logo, Profile, and IdentityChallenge objects in the View component.

The Masthead would subscribe to the SessionInitialized event and would handle receiving notification of that event by checking if the Session that was initialized is currently active and if it is, render the Logo, Profile and itself. If the Session isn’t active, then the Masthead would remove the Profile from view and potentially even change the style of the Logo to be larger and/or in a different position.

Similarly, the IdentityChallenge would be subscribed to the SessionInitialized event and would check if the initialized Session was active. If it is active, the IdentityChallenge would remove itself from the UI as it is not required. If it isn’t active, it would append itself to the UI in order to allow the user to authenticate/start a new Session.

Controller Component

The Controller component is responsible for controlling the state of objects in the Model. Objects in the Controller component will use a message broker to subscribe to one or more Model.Command(s) in order to be notified when a View object has been interacted with by a user. Objects defined in the Controller component are responsible for calling the appropriate methods on a Model object based on the received Command and publishing the results as a Model.Event object. In some cases, the Model object’s method that corresponds with the received Command will require data that is external to the application. In those cases, the Controller object will use a service to make a call to the external data source and use the results of that request to fulfill the  Command.

As an example, if the Profile object in the View component contains a button for logging out, when the user clicks that button the Profile will publish a new EndSession command. The SessionController object will be subscribed to that event and be notified. It will then send an HTTP request to the identity and access management API (examples are Auth0 or Google’s Firebase Auth) to end the user’s session. When it receives a success response it will call the End() method on the Session object.

Service Component

The Service component is responsible for providing application services to the other components. These services include a dependency injection container and a pub/sub message broker.

Objects defined in the Service component are responsible for handling the infrastructure duties required by any application to function in its host environment.

UI Component

The UI component is responsible for providing the entry point of the application. In the case of a browser-based application, the host environment is a browser DOM’s window object. When the window loads, it will fire a load event. The UI component makes use of the EventTarget interface and adds an EventListener which will use the Service‘s dependency injection Container to initialize the application based on configuration settings. Once the application is initialized, it will publish a SessionInitialized event via the MessageBroker. View objects subscribed to the SessionInitialized event will render the appropriate user interface and enable the application to respond to the user’s interactions as described in the View Component section above.

Next Steps

With the basic architectural guidelines defined, when a project needs a user interface application, this architecture can be used to provide a launching pad for defining the product requirements that a developer will need to implement. The next post in this series will be about defining these requirements for a fictional system.

Observing Events in an MVC Application

Continuing from the last post, I’m going to expand on the Profile “application” that was started. For this stage, the requirements will change to now allow the user to edit the Name.

I’ll restate again something that I wasn’t clear about in the first post. These posts are an exploration of which problems frameworks like React/Redux, Angular, Ember, etc. solve by coding myself into those problems and then identifying how different frameworks attempt to solve these problems.

To recap, the application displays a Profile that consists of a name, a profile image and a list of hobbies. The last post finished with a “minimum viable product” that looked something like the screen capture below.

final-0.0.0

In this fictitious software company, the change control board has met and the highest priority feature has been assigned: enable the user to edit their profile name. Our finished product will look like:

final-0.0.1

Retroactively Adding Tests

Something that wasn’t done in the previous post was to create unit tests. Working for a mid-sized business such as Fictitious Company, we use the QUnit as our testing framework. We have several JavaScript applications and we’ve not felt enough pain from it to warrant moving to Jasmine or Mocha or any of the other many options. Using this framework requires the application code to be placed in a separate file from the hosting document. So the contents of the script tag from the previous post have been moved into an app.js file. A new file has been added to the project called tests.html which will serve as the host for the test harness.

app.js:

var DATA = {    
    name: 'John Smith',
    imgURL: 'http://lorempixel.com/100/100/',
    hobbyList: ['coding', 'writing', 'skiing']
};

var App = {
    main: (function () {
        window.addEventListener('load', function () {
            var profile = new App.View.Profile(DATA);
            profile.render(document.body);
        });
    })()
 };

App.View = (function () { //the View 'class' library component
    var _library = {
            Profile: function (model) {
                         var _private = {
                                 div: document.createElement('div'),
                                 heading: document.createElement('h3'),
                                 img: document.createElement('img'),
                                 hobbies: new App.View.Hobbies(model.hobbyList)
                             },
                             _public = {
                                 render: function (container) {
                                             _private.heading.appendChild(document.createTextNode(model.name));
                                             _private.img.setAttribute('src', model.imgURL);
                                             _private.hobbies.render(_private.div);
                                             container.appendChild(_private.div);
                                         }
                             };
                         _private.div.appendChild(_private.heading);
                         _private.div.appendChild(_private.img);
                         _private.div.appendChild(_private.hobbies.element);
                         return _public;
                     },
            Hobbies: function (model) {
                         var _private = {
                                 div: document.createElement('div'),
                                 heading: document.createElement('h5'),
                                 list: document.createElement('ul')
                             },
                             _public = {
                                 element: _private.div,
                                 render: function (container) {
                                             model.map(function (hobby) {
                                                 var li = document.createElement('li');
                                                 li.appendChild(document.createTextNode(hobby));
                                                 _private.list.appendChild(li);
                                             });
                                             _private.div.appendChild(_private.list);
                                             container.appendChild(_private.div);
                                         }
                             };
                         _private.heading.appendChild(document.createTextNode('My hobbies:'));
                         _private.div.appendChild(_private.heading);
                         return _public;
                     }
        };
    return _library;
})();

tests.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset='utf-8'>
        <title>Testing: Your First JavaScript Project</title>
        < script src="../app.js></ script >
        <link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-1.20.0.css">
        < script src="http://code.jquery.com/qunit/qunit-1.20.0.js"></ script >
    </head>
    <body>
        window.addEventListener('load', function () {
            QUnit.test("Given , when ...", function (assert) {
            });
        };
    </body>
</html>

Looking at the code base from the last post, there is one object representing the Model component but it isn’t really anything more than a representation of a Data Transfer Object, two objects in the Views component, and there is no Controller (yet). Based on the previous “requirements”, the filled in tests might look like the following:

Testing the Hobbies View

In the simplistic example from the previous post, calling this a View object is a bit of hyperbole, but we’ll go with it anyway. The public interface of the Hobbies view also has two members, an element attribute and a render method. It is responsible for displaying the current state of the model’s hobbyList attribute. So to test, we need to verify that instantiating a View results in a DOM element that contains an h5 heading and an ul element with li elements for each of the hobbies specified in the model.

Starting at line 15 of the tests.html:

QUnit.test("Given an instance of the Hobbies view, when it is rendered...", function (assert) {
    var mockModel = {
            name: 'John Smith',
            imgURL: 'http://lorempixel.com/100/100/',
            hobbyList: ['coding', 'testing', 'refactoring'],
            addEventListener: function (eventType, listener) {
            }
        },
        hobbiesView = new App.View.Hobbies(mockModel.hobbyList, document.createElement('div'));
    

    assert.equal(hobbiesView.element.children.length, 2, '...then it has 2 HTML elements.');
    assert.equal(hobbiesView.element.children[0].tagName, 'H5', "...then the first child is an H5.");
    assert.ok(hobbiesView.element.children[0].textContent === 'My hobbies:', "...the the H5 contains text: 'My hobbies:'");
    assert.equal(hobbiesView.element.children[1].tagName, 'UL', "...then the second child is an UL.");
    mockModel.hobbyList.forEach(function (hobby, index) {
        assert.ok(hobby === hobbiesView.element.children[1].children[index].textContent, "...then list items match.");
    });
});

To break that down, the testing style is in the given-when-then phrasing. This says which unit of the application and what behavior of that unit is being tested. In this case the rendering of the Hobbies view object. Which is fairly simple, it should contain 2 elements: a level 5 heading with the text “My hobbies:” and an unordered list of items that match the items in the model the view is presenting.

Adding the above to the code results in something like:

test-hobbies

Testing the Profile View

The public interface of the Profile view has a two members, the element attribute and the render method. It is responsible for displaying the current state of the model on the screen. So to test that we need to verify that instantiating a Profile results in a div element with a class of ‘profile-view’ that contains an h3 heading, an img element, and a div with a class of ‘hobbies-view’.

Immediately after the last test, add the following:

QUnit.test("Given an instance of the Profile view, when it is rendered...", function (assert) {
    var mockModel = {
            getName: function () {return 'John Smith';},
            imgURL: 'http://lorempixel.com/100/100/',
            hobbyList: ['coding', 'testing', 'refactoring'],
            addEventListener: function (eventType, listener) {
            }
        },
        profileView = new App.View.Profile(mockModel, document.createElement('div'));


    assert.equal(profileView.element.children.length, 5, '...then it has 5 HTML elements.');
    assert.equal(profileView.element.children[0].tagName, 'H3', '...then the first child is an H3.');
    assert.equal(profileView.element.children[0].textContent, 'John Smith', '...then the H3 contains text: "John Smith".');
    assert.equal(profileView.element.children[1].tagName, 'INPUT', '...then the second child is an input element.');
    assert.equal(profileView.element.children[1].getAttribute('type'), 'text', '...then the input element is a text field.');
    assert.equal(profileView.element.children[1].classList.contains('hidden'), true, '...then the input element is not visible.');
    assert.equal(profileView.element.children[2].getAttribute('class'), 'scl-edit-save-cancel', '...then the third child is the SCL edit-save-cancel component.');
    assert.equal(profileView.element.children[3].tagName, 'IMG', "...then the fourth child is an image.");
    assert.equal(profileView.element.children[3].getAttribute('src'), 'http://lorempixel.com/100/100/', "...then the image url matches the model.");
    assert.equal(profileView.element.children[4].getAttribute('class'), 'hobbies-view', '...then the fifith child is a hobbies-view class.');
});

After modifying the app.js file to include setting the class attribute on the root element of each view, running the tests result in the something like:

test-profile

With all of the previous requirements covered and passing, it’s now time to write the tests that will drive the design for implementing the current set of requirements.

The use case:

Use Case: Edit a Profile Name

Primary Actor: Member (Registered User)

Scope: a fictitious system

Level: User goal

User Story:

As a customer I want to be able to update my profile name so that my identity in the system is accurate.

Preconditions:

  • The profile with editing enabled is presented to the member.

Triggers:

  • The member invokes an edit request on the profile name.

Postconditions:

  • The profile name is saved and an updated view is shown.

Basic flow:

  1. The system provides an editable area populated with the current value of the Profile Name.
  2. The member modifies the Profile Name value until satisfied.
  3. The member saves the edit.
  4. The system saves the new Profile Name, logs the edit event and finishes any necessary post processing.
  5. The system presents the updated view of the Profile Name to the member.

Extensions:

3a. Cancel the edit:

  1. The member invokes a cancel request on the edit profile name.
  2. The system discards any change the member has made, then goes to step 5.

After reviewing the use case that the Business Analysts have documented, it’s time to consult the Profile View section of the UI Specification Document that the User Experience Architect has defined:

7.2.1 Profile View

Description

The Profile View enables the user to review their profile to see how other users of the site will see their identity.

This element will inherit the core styling of the app.css file (see Appendix A).

Behavior

The behavior of this element is contained in its constituent elements.

Elements

7.2.1.1 Profile Name View

Description

The Profile Name View enables users to see and edit the current value of their profile name as it appears on the site.

Behavior

The behavior of the Profile Name View is contained in its elements.

Elements

7.2.1.1.1 Profile Name Label

Description

A text label that displays the current value of the user’s profile name. Positioned at the top left of the Profile Name View as a level 3 heading.

Behavior

N/A

Elements

N/A

7.2.1.1.2 Profile Name Input Field

Description

A text entry field that accepts character string input from the user.
Positioned at the top left of the Profile Name View.

Behavior

Default HTML input @type=text behavior. Defaults to being hidden from view.

Elements

N/A

7.2.1.1.3 Edit-Save-Cancel Component

Description

The Fictitious Company’s Standard Component Library’s Edit-Save-Control.
See Reference 2 for a complete description.

Behavior

See Reference 2 for default behaviors.

For this specification, clicking the Edit button will hide the Profile Name Label and reveal the Profile Name Input Field.

Clicking the Save button will hide the Profile Name Input Field, update the supporting data model with the value entered in the Profile Name Input Field, and reveal the Profile Name Label.

Clicking the Cancel button will hide the Profile Name Input Field and reveal the Profile Name Label.

Elements

See Reference 2.

7.2.1.2 Profile Picture View

Description

The Profile Picture View enables users to see the avatar image associated with their profile. The image will be 100 x 100 pixels.

Behavior

N/A

Elements

N/A

7.2.1.3 Profile Hobbies View

Description

The Profile Hobbies View displays a list of hobbies that the user provided when they joined the site.

Behavior

N/A

Elements

7.2.1.3.1 Profile Hobbies Header

Description

A text label displays the value: “My hobbies:” as a level 5 heading.

Behavior

N/A

Elements

N/A

7.2.1.3.2 Profile Hobbies List

Description

A bulleted list of each hobby.

Behavior

N/A

Elements

N/A

Time to create the feature branch and begin coding; or is it?

Looking back to the UI specification, there is a requirement to use the company’s Standard Component Library for the Edit button that is required on the Profile Name section of the Profile view.

A Standard Component Library (SCL) is a way to keep the “look and feel” of the user interfaces consistent across the various applications that the company has implemented. It helps the user base have a sense of familiarity with an app even if it’s the first time they’ve used it. It also helps the development team with producing new applications a little faster since they don’t have to build everything from scratch with each new application/project.

The Fictitious Company’s SCL has an Edit-Save-Cancel control that allows the user to indicate they would like to Edit a value on the screen, the Edit button is hidden and in its place the Save and Cancel buttons are displayed. This control is to be used to edit the Profile Name. The first step toward implementing will be to configure the Profile View to include the Edit-Save-Control component.

Packaging and utilizing a library from a package management tool is a subject for a different post, but the SCL would normally be brought into the application with a dependency manager. For this post, the library is just going to be added via a script tag.

< script >../scl.js</ script>

The View has a dependency on this library, so that gets passed into it:

App.View = (function (scl) { //the View 'class' library component
    var _library = {
            Profile: function (model) {
                         var _private = {
                                 div: document.createElement('div'),
                                 heading: document.createElement('h3'),
                                 img: document.createElement('img'),
                                 hobbies: new App.View.Hobbies(model.hobbyList)
                             },
                             _public = {
                                 element: _private.div,
                                 render: function (container) {
                                             _private.heading.appendChild(document.createTextNode(model.name));
                                             _private.img.setAttribute('src', model.imgURL);
                                             _private.hobbies.render(_private.div);
                                             container.appendChild(_private.div);
                                         }
                             };
                         _private.div.setAttribute('class', 'profile-view');
                         _private.div.appendChild(_private.heading);
                         _private.div.appendChild(_private.img);
                         _private.div.appendChild(_private.hobbies.element);
                         return _public;
                     },
            Hobbies: function (model) {
                         var _private = {
                                 div: document.createElement('div'),
                                 heading: document.createElement('h5'),
                                 list: document.createElement('ul')
                             },
                             _public = {
                                 element: _private.div,
                                 render: function (container) {
                                             model.map(function (hobby) {
                                                 var li = document.createElement('li');
                                                 li.appendChild(document.createTextNode(hobby));
                                                 _private.list.appendChild(li);
                                             });
                                             container.appendChild(_private.div);
                                         }
                             };
                         _private.div.setAttribute('class', "hobbies-view");
                         _private.heading.appendChild(document.createTextNode('My hobbies:'));
                         _private.div.appendChild(_private.heading);
                         _private.div.appendChild(_private.list);
                         return _public;
                     }
        };
    return _library;
})(FC.SCL);

The library is declared in the Fictitious Company namespace FC as SCL. The View library will refer to it as scl.

Now we can start implementing the view as specified in section 7.2.1.1.2 of the UI Spec.

The Profile View needs a new element: a profile name input field. First thing to do is write a test for it:

QUnit.test("Given an instance of the Profile view, when it is rendered...", function (assert) {
    var dto = {
            name: 'John Smith',
            imgURL: 'http://lorempixel.com/100/100/',
            hobbyList: ['coding', 'testing', 'refactoring']
        },
        v = new App.View.Profile(dto);

    v.render(document.createElement('div'));

    assert.equal(v.element.children.length, 4, '...then it has 3 HTML elements.');
    assert.equal(v.element.children[0].tagName, 'H3', '...then the first child is an H3.');
    assert.equal(v.element.children[0].textContent, 'John Smith', '...then the H3 contains text: "John Smith".');
    assert.equal(v.element.children[1].tagName, 'INPUT', '...then the second child is an input field.');
    assert.equal(v.element.children[1].getAttribute('type'), 'text', '...then the input element is a text field.');
    assert.equal(v.element.children[1].getAttribute('style'), 'display:none', '...then the input element is not visible.');
    assert.equal(v.element.children[2].tagName, 'IMG', "...then the second child is an image.");
    assert.equal(v.element.children[2].getAttribute('src'), 'http://lorempixel.com/100/100/', "...then the image url matches the model.");
    assert.equal(v.element.children[3].getAttribute('class'), 'hobbies-view', '...then the third child is a hobbies-view class.');
});

Then run the test and see the page fill up with red:

test-input-fail

Now we update the Profile to make it pass:

Profile: function (model) {
             var _private = {
                     div: document.createElement('div'),
                     heading: document.createElement('h3'),
                     input: document.createElement('input'),
                     img: document.createElement('img'),
                     hobbies: new App.View.Hobbies(model.hobbyList)
                 },
                 _public = {
                     element: _private.div,
                     render: function (container) {
                                 _private.heading.appendChild(document.createTextNode(model.name));
                                 _private.input.value = model.name;
                                 _private.img.setAttribute('src', model.imgURL);
                                 _private.hobbies.render(_private.div);
                                 container.appendChild(_private.div);
                             }
                 };
             _private.div.setAttribute('class', 'profile-view');
             
             _private.div.appendChild(_private.heading);
             
             _private.input.setAttribute('type', 'text');
             _private.input.setAttribute('style', 'display:none');
             _private.div.appendChild(_private.input);
             
             _private.div.appendChild(_private.img);
             
             _private.div.appendChild(_private.hobbies.element);
             
             return _public;
         },

And now are test runner is nice and green again!

test-input-pass

The next specification was to add the Edit-Save-Cancel component to the Profile. Again, we go back to the test script:

QUnit.test("Given an instance of the Profile view, when it is rendered...", function (assert) {
    var dto = {
            name: 'John Smith',
            imgURL: 'http://lorempixel.com/100/100/',
            hobbyList: ['coding', 'testing', 'refactoring']
        },
        v = new App.View.Profile(dto);

    v.render(document.createElement('div'));

    assert.equal(v.element.children.length, 5, '...then it has 5 HTML elements.');
    assert.equal(v.element.children[0].tagName, 'H3', '...then the first child is an H3.');
    assert.equal(v.element.children[0].textContent, 'John Smith', '...then the H3 contains text: "John Smith".');
    assert.equal(v.element.children[1].tagName, 'INPUT', '...then the second child is an input element.');
    assert.equal(v.element.children[1].getAttribute('type'), 'text', '...then the input element is a text field.');
    assert.equal(v.element.children[1].getAttribute('style'), 'display:none', '...then the input element is not visible.');
    assert.equal(v.element.children[2].getAttribute('class'), 'scl-edit-save-cancel', '...then the third child is the SCL edit-save-cancel component.');
    assert.equal(v.element.children[3].tagName, 'IMG', "...then the fourth child is an image.");
    assert.equal(v.element.children[3].getAttribute('src'), 'http://lorempixel.com/100/100/', "...then the image url matches the model.");
    assert.equal(v.element.children[4].getAttribute('class'), 'hobbies-view', '...then the fifith child is a hobbies-view class.');
});

Which results in the predictable test run:

test-esc-fail

Update the code to make the tests pass:

Profile: function (model) {
             var _private = {
                     div: document.createElement('div'),
                     heading: document.createElement('h3'),
                     input: document.createElement('input'),
                     img: document.createElement('img'),
                     hobbies: new App.View.Hobbies(model.hobbyList)
                 },
                 _public = {
                     element: _private.div,
                     render: function (container) {
                                 _private.heading.appendChild(document.createTextNode(model.name));
                                 _private.input.value = model.name;
                                 _private.img.setAttribute('src', model.imgURL);
                                 _private.hobbies.render(_private.div);
                                 container.appendChild(_private.div);
                             }
                 };
             _private.div.setAttribute('class', 'profile-view');
             
             _private.div.appendChild(_private.heading);
             
             _private.input.setAttribute('type', 'text');
             _private.input.setAttribute('style', 'display:none');
             _private.div.appendChild(_private.input);

             _private.input.editComponent = new scl.EditSaveCancel(_private.div);
             
             _private.div.appendChild(_private.img);
             
             _private.div.appendChild(_private.hobbies.element);
             
             return _public;
         },

Which passes:

test-esc-pass

And the application looks almost as specified:

preview-with-edit

The layout will be addressed at the end. The next requirement in the specification 7.2.1.1.3: Behavior is to swap the H3 with an input when the Edit button is clicked. Time for a new test:

QUnit.test("Given a rendered Profile view, when its Edit button is clicked...", function (assert) {
    var dto = {
            name: 'John Smith',
            imgURL: 'http://lorempixel.com/100/100/',
            hobbyList: ['coding', 'testing', 'refactoring']
        },
        v = new App.View.Profile(dto),
        editButton, inputField, nameLabel;

    v.render(document.createElement('div'));
    
    editButton = v.element.getElementsByClassName('scl-edit-button')[0];
    editButton.click();
    
    inputField = v.element.children[1];
    nameLabel = v.element.children[0];

    assert.equal(inputField.classList.contains('visible'), true, '...then the profile name input field is visible.');
    assert.equal(nameLabel.classList.contains('hidden'), true, '...then the profile name label is not visible.');
});

Run the test.

edit-click-fail

A user initiated event is going to occur – the click event on the Edit button. The View is responsible for responding to user actions. So we need to “wire up” the Profile view to listen for a click event on the Edit button. The SCL component we’re using provides an addEventListener method that allows us to define a function that can be executed when the component dispatches an editClicked event.

Profile: function (model) {
             var _private = {
                     div: document.createElement('div'),
                     heading: document.createElement('h3'),
                     input: document.createElement('input'),
                     img: document.createElement('img'),
                     hobbies: new App.View.Hobbies(model.hobbyList),
                     editButtonClickHandler: function () {
                        _private.heading.classList.remove('visible');
                        _private.heading.classList.add('hidden');
                        _private.input.classList.remove('hidden');
                        _private.input.classList.add('visible');
                     }
                 },
                 _public = {
                     element: _private.div,
                     render: function (container) {
                                 _private.heading.appendChild(document.createTextNode(model.name));
                                 _private.input.value = model.name;
                                 _private.img.setAttribute('src', model.imgURL);
                                 _private.hobbies.render(_private.div);
                                 container.appendChild(_private.div);
                             }
                 };
             _private.div.setAttribute('class', 'profile-view');
             
             _private.div.appendChild(_private.heading);
             
             _private.input.setAttribute('type', 'text');
             _private.input.setAttribute('class', 'hidden');
             _private.div.appendChild(_private.input);

             _private.input.editComponent = new scl.EditSaveCancel(_private.div);
             _private.input.editComponent.addEventListener('editClicked', _private.editButtonClickHandler);
             
             _private.div.appendChild(_private.img);
             
             _private.div.appendChild(_private.hobbies.element);
             
             return _public;
         },

Run the test.

edit-click-pass

The next requirement states:

Clicking the Save button will hide the Profile Name Input Field, update the supporting data model with the value entered in the Profile Name Input Field, and reveal the Profile Name Label.

There’s a requirement to modify the data model. We’re only testing the Profile View right now, so to verify that we’re accomplishing that aspect of the requirement the test will focus on verifying that the input field is hidden and the label is visible. After that test is passing, we’ll focus on the Model updates.

QUnit.test("Given a rendered Profile view, when its Save button is clicked...", function (assert) {
    var dto = {
            name: 'John Smith',
            imgURL: 'http://lorempixel.com/100/100/',
            hobbyList: ['coding', 'testing', 'refactoring']
        },
        v = new App.View.Profile(dto),
        saveButton, inputField, nameLabel;

    v.render(document.createElement('div'));
    v.element.getElementsByClassName('scl-edit-button')[0].click();

    saveButton = v.element.getElementsByClassName('scl-save-button')[0];
    saveButton.click();

    inputField = v.element.children[1];
    nameLabel = v.element.children[0];

    assert.equal(inputField.classList.contains('hidden'), true, '...then the profile name input field is not visible.');
    assert.equal(nameLabel.classList.contains('visible'), true, '...then the profile name label is visible.');
});

(This post is getting really, really long, so I’m going to skip the screen shots of the test runner for the failing tests from here on.)

The application is supposed to be following the MVC design pattern as mentioned in the previous post. To this point, there has been no Controller. Now that the Model is going to be updated, an object needs to be responsible for that logic. So we’ll build a Profile Controller that will observe events in the View and update the Model accordingly:

Profile: function (model) {
             var _private = {
                     div: document.createElement('div'),
                     heading: document.createElement('h3'),
                     input: document.createElement('input'),
                     img: document.createElement('img'),
                     hobbies: new App.View.Hobbies(model.hobbyList),
                     editButtonClickHandler: function () {
                        _private.heading.classList.remove('visible');
                        _private.heading.classList.add('hidden');
                        _private.input.classList.remove('hidden');
                        _private.input.classList.add('visible');
                     },
                     saveButtonClickHandler: function () {
                        _private.heading.classList.add('visible');
                        _private.heading.classList.remove('hidden');
                        _private.input.classList.add('hidden');
                        _private.input.classList.remove('visible');
                     }
                 },
                 _public = {
                     element: _private.div,
                     render: function (container) {
                                 _private.heading.appendChild(document.createTextNode(model.name));
                                 _private.input.value = model.name;
                                 _private.img.setAttribute('src', model.imgURL);
                                 _private.hobbies.render(_private.div);
                                 container.appendChild(_private.div);
                             }
                 };
             _private.div.setAttribute('class', 'profile-view');
             
             _private.div.appendChild(_private.heading);
             
             _private.input.setAttribute('type', 'text');
             _private.input.setAttribute('class', 'hidden');
             _private.div.appendChild(_private.input);

             _private.input.editComponent = new scl.EditSaveCancel(_private.div);
             _private.input.editComponent.addEventListener('editClicked', _private.editButtonClickHandler);

             _private.input.editComponent.addEventListener('saveClicked', _private.saveButtonClickHandler);
             
             _private.div.appendChild(_private.img);
             
             _private.div.appendChild(_private.hobbies.element);
             
             return _public;
         },

Run the test.

save-click-pass

Lather, rinse, repeat for the cancel button.

Now the last piece of the puzzle is that the View is supposed to display the current value of the Model’s name attribute when displaying the H3 element. But if you execute this code, and change the value in the input field, the value is not updated in the header. This is because the View is not “listening” to the Model and the Model is not publishing any events for the View to listen for anyway.

Update the tests to ensure that we verify that the View renders the correctly when the Profile Name is modified. Then modify the Model so that it can dispatch events and modify the View so that it listens for the nameChanged event coming from the Model.

QUnit.test("Given a rendered Profile view, when the value in the Profile Name Input Field is modified and Saved...", function (assert) {
    var dto = {
        name: 'John Smith',
        imgURL: 'http://lorempixel.com/100/100/',
            hobbyList: ['coding', 'testing', 'refactoring']
        },
        v = new App.View.Profile(dto),
        saveButton, inputField, nameLabel;

    v.render(document.createElement('div'));
    v.element.getElementsByClassName('scl-edit-button')[0].click();
    saveButton = v.element.getElementsByClassName('scl-save-button')[0];

    inputField = v.element.children[1];
    nameLabel = v.element.children[0];

    inputField.value = 'New Value';
    saveButton.click();

    assert.equal(nameLabel.textContent, 'New Value', '...then the profile name label displays the modified value.');
    assert.equal(dto.name, 'New Value', '...then the name attribute of the model is set to the modified value.');
});

We are trying to adhere to the MVC pattern. However, the model that we have is just a DTO. The View can’t subscribe to any events on this model, so we first have to redefine the Model to provide the addEventListener method. We also don’t have a mechanism for mutating the state of the Model – which means that we have no mechanism for dispatching those events.

App.Model = (function () {
    var _library = {
        Profile: function (name, imgSrc, hobbies) {
            var _private = {
                    name: name,
                    imgURL: imgSrc,
                    hobbyList: hobbies,
                    handlers: {
                        profileNameChanged: []
                    },
                    dispatchEvent: function(evt) {
                        _private.handlers[evt.type].forEach(function (handler) {
                            handler(evt);
                        });
                    }
                },
                _public = {
                    getName: function () {
                        return _private.name;
                    },
                    setName: function (value) {
                        if (value !== _private.name) {
                            var profileNameChanged = new CustomEvent('profileNameChanged', {detail:{oldValue:_private.name, newValue:value}});
                            _private.name = value;
                            _private.dispatchEvent(profileNameChanged);
                        }
                    },
                    addEventListener: function (eventType, listener) {
                        _private.handlers[eventType].push(listener);
                    },
                    imgURL: _private.imgURL,
                    hobbyList: _private.hobbyList
                };
            return _public;
        }
    };

    return _library;
})();

After redefining what the Model.Profile’s interface is, we need to go refactor the previous test cases so that the mock Model.Profile object provides the same interface. See the finished code at the end of the post or in my GitLab repo.

With event listeners, testing was a little awkward. The mock objects needed to either receive and event listener or dispatch events to one. Here’s an example of verifying that an object successfully subscribed an event listener:

QUnit.test("Given a Profile view, when the view is constructed...", function (assert) {
    var mockModel = {
            getName: function () { return 'foo'; },
            addEventListener: function (eventType, listener) {
                assert.equal(eventType, 'profileNameChanged', "...then the Profile subscribes to the Model's 'profileNameChanged' event.");
            },
            hobbyList: []
        },
        profile = new App.View.Profile(mockModel, document.createElement('div'));
});

And here is an example of testing that an object dispatches events:

QUnit.test("Given a Profile model, when a subscriber exists and the name is changed...", function (assert) {
    var profile = new App.Model.Profile(),
        subscriber = function (evt) {
            assert.equal(evt.detail.newValue, 'My New Name', '...then the subscriber is notified of the event.');
        };

    profile.addEventListener('profileNameChanged', subscriber);
    profile.setName('My New Name');
});

Now the last piece is to modify the CSS so that the elements are laid out according to the UI Specification:

.visible {
    display: inline-block;
}

.hidden {
    display: none;
}

.profile-view h3  {
    float: left;
    margin: 3px;
}

.profile-view .scl-edit-save-cancel {
    float: left;
}

.profile-view input {
    float: left;
}

.profile-view img {
    display: block;
    clear: both;
}

Which results in:

final-with-css final-with-css-editmode

And there it is, an implementation of the MVC pattern without the need for a framework – yet. We are making use of a library, which was modified to keep it consistent with the concepts presented so far. The render method has been refactored out of the Views and replaced with an event based architecture. This allows the Model objects to store the logic for determining if a state change has occurred, and when it does, it dispatches events to the View object(s) that handle those events by updating only those elements that display the mutating attributes of the Model.

One thing to notice is the public addEventListener method and the private handlers and dispatch members. This code was duplicated in all of the objects. It would have been better to define an object that manages that work and have the M-V-C objects inherit that behavior. The next post will introduce a Publish-Subscribe pattern from the Fictitious Company’s standard libraries as well as a little more clean up in the View library. Data access has also not yet been explored and will introduce even more complexity to the system.

Full code is available at: https://gitlab.com/pct/YourFirstJavaScriptProject-0.0.1/tree/master/

 

My Reaction to React

EDIT: Some people were rightly complaining about the code snippets being screen captures rather than <code> blocks. I’ve updated accordingly.

Also, many have rightfully commented that the code in this post is not realistic and if used in a production environment would be nightmarish for maintainers and likely even for scalability. I didn’t clearly articulate what my intentions were, so I’ll try to do better in this update: I am a proponent of using libraries and frameworks. They allow a developer to “stand on the shoulders of giants” so to speak. This post and the ones that I’m going to publish that build on this are an exploration of which problems frameworks like React/Redux, Angular, Ember, etc. solve by coding myself into those problems and then identifying how different frameworks attempt to solve these problems.

The interwebs are buzzing about React.js and redux and flux and angular and ember and…

It’s rather tiring to try and learn all of these.

I thought that I’d make a parallel post to this post: Building Your First React.js App.

If you want to use React, fine, I am not trying to convince anyone not to. I just want to show that components in a JavaScript application are quite simple to do and do not require any framework at all to do so.

The concept is to follow the MVC pattern. Where the Models are being observed by the Views which are observed by the Controllers. A user interacts with a View, that event is handled by the Controller which updates the Model accordingly. The View observes the Model and handles those events by rendering itself accordingly. In the aforementioned post, there is no controller, nor events. So I’m going to keep my example as simplistic as the one provided. In a future post, I plan on expanding this idea example to utilize Models and Controllers.

Below is my parallel universe version of Per Harald Borgen’s post:

This article will take you through every step of building the simplest JavaScript app possible. Even simpler than a to-do list.

Why so simple? Because I’ve found that when I’m trying to learn a new technology, even the simplest features can add unnecessary complexity.

If you’re overwhelmed with the wide variety of frameworks and libraries being published, this tutorial is for you.

There are no prerequisites other than basic JavaScript skills. Though if you’d like to read some basic theory before getting started with the coding, you can read the article below and then return.

MDN: JavaScript Guide

Looking at the final project

To claim you’ll be building an app is actually an exaggeration. It’s only a profile page, as you can see below. (The image is taken randomly from http://lorempixel.com/)

Step 1: Splitting the page into components

An application is built around components; everything you see on the screen is a part of a View component. Before we start coding, it’s a good idea to create a sketch of the views, as we’ve done above.

The main component — which wrap all other components — is marked in red. Since we’re targeting this application to run in a browser, we’ll call this one document.body or Body.

Once we’ve figured out that Body is our main viewport, we’ll need to ask ourselves: which view is a direct child of the Body?

I’d argue that the name and the profile image can be grouped into one View, which we’ll call Profile (green rectangle), and the Hobbies section can be another View (blue rectangle).

The structure of our components can also be visualized like this:

- Body
    - Profile
    - Hobbies

We could split the Views further; like ProfileImage and HobbyItem, though we’ll stop here for the sake of simplicity.

Step 2: Hello World

Before you begin coding, you’ll need to download the source file. It’s available at this GitLab repo. Simply copy or clone it and open the index.html file in the browser. (The full code is available in the finished_project.html file.)

I’ve setup the file properly, so you’ll see no links to any unnecessary libraries in the <head/> section of the file. Your code will start at line 9.

For a proper JavaScript project, you wouldn’t use this non-minified setup. But I don’t want this tutorial to be about anything else than coding, so we’ll keep it simple.

Let’s write our first View:

var App = {};

App.View = (function () { //the View component - a 'class library' of views
    var _library = {
        Hello: (function () {
            var _private = {
                div: document.createElement('div')
                },
                _public = {
                    render: function (container) {
                        _private.div.appendChild(document.createTextNode('Hello World'));
                        container.appendChild(_private.div);
                    }
                };
            return _public;
        })()
    };
    return _library;
})();

As you can see on the first line, we created an object namespace called App. We then created a View object as a component to house all of the views that are going to be in our application. Finally, we declare the Hello object using the Definitive Module Pattern and the Immediately Invoked Function Expression.

Each View object can have as many members you want, though the most important one is the render method. In the render method, you’ll pass in a reference to the DOM element that will contain the output of this view and then append the contents of the view to that container. In our case, we simply want a div tag with the text “Hello World”.

Then follow up with this inside the App object:

var App = {
    main: (function () {
        window.addEventListener('load', function () {
            App.View.Hello.render(document.body);
        });
    })()
};

This is how we specify where on the page we want the Hello view to be rendered. This is done by adding a load event handler to the window that calls Hello.render, passing in the document.body as the container parameter. I throw this into a function called main, but that is just a convention that I use due to familiarity with C-based programming languages.

The syntax shouldn’t look too weird, we’re just declaring an object that utilizes the DOM API and adhering to a couple of tried and tested software development patterns.

Load the page in a browser and you’ll see ‘Hello World’ printed out on the screen.

Step 3: More components

Let’s add some more views. Looking back at our application overview, we see that the App component has got two views called Profile and Hobbies.

Let’s write out these two views. We’ll begin with Profile:

Profile (function () {
    var _private = {
        div: document.createElement('div'),
        heading: document.createElement('h3'),
        img: document.createElement('img')
    },
    _public = {
        element: _private.div,
        render: function (container) {
            _private.heading.appendChild(document.createTextNode('My name'));
            _private.img.setAttribute('src', 'example.jpg');
            container.appendChild(_private.div);
        }
    };
    _private.div.appendChild(_private.heading);
    _private.div.appendChild(_private.img);
    return _public;
})(),

There is actually nothing new here. Just a bit more content in the render function than it was in the Hello view.

Let’s write the Hobbies component:

Hobbies (function () {
    var _private = {
        div: document.createElement('div'),
        heading: document.createElement('h5')
    },
    _public = {
        render: function (container) {
            container.appendChild(_private.div);
        }
    };
    _private.heading.appendChild(document.createTextNode('My hobbies:'));
    _private.div.appendChild(_private.heading);
    return _public;
})()

If you refresh the page again though, you won’t see any of these components.

This is because nothing has told these views to render to the screen. We need to update our main function to render the Profile and Hobbies view instead of the Hello view.

This is what we’ll need to do:

var App = {
    main: (function () {
        window.addEventListener('load', function () {
            App.View.Profile.render(document.body);
            App.View.Hobbies.render(document.body);
        });
    })()
};

If you refresh the page again you’ll see that all the content appears on the page. (Though the image wont appear, as we’ve only added a dummy link to it).

Step 4: Get the data

Now that we have the basic structure setup, we’re ready to add the correct data to our project.

A good practice when implementing the MVC pattern is something called a one directional data flow, meaning that the data is passed down from parent to child components.

Above all the components, paste in the following code:

var DATA = {    
    name: 'John Smith',
    imgURL: 'http://lorempixel.com/200/200/',
    hobbyList: ['coding', 'writing', 'skiing']
}

You can imagine this data being fetched from an API of something.

The next thing you’ll need to do is add this data to the App components as its model.

Data in the MVC pattern is maintained in the Model objects and mutated by the Controller objects. In this simplistic example, I’m going to overlook that aspect and just deal with the single object. In a future post, I’ll explore a more complex data model for the application.

Below, you’ll see how you pass the data into the views, by simply changing the constructor method of the views to accept a model, we’ll initialize our view objects and then render them.

var App = {
    main: (function () {
        window.addEventListener('load', function () {
            var profile = new App.View.Profile(DATA),
                hobbies = new App.View.Hobbies(DATA);
            profile.render(document.body);
            hobbies.render(profile.element);
        });
    })()
};

There’s no new syntax, no new Domain Specific Language, just plain old JavaScript.

Now we’re able to access this data from within the View objects through model.[member-name]. We’ll also restructure the views a bit to make the Hobbies a child of the Profile view. This makes it so the application just initializes an instance of the Profile view and data is where it needs to be.

We use the profileImage and name in the Profile view while only the hobbyList array is passed into the Hobbies view. This is because the Hobbies component doesn’t need the rest of the data; it’s simply going to display a list of hobbies.

Let’s look at how we’ll need to rewrite the Profile view in order to use the data we’ve passed down to it:

Profile: function (model) {
             var _private = {
                     div: document.createElement('div'),
                     heading: document.createElement('h3'),
                     img: document.createElement('img'),
                     hobbies: new App.View.Hobbies(model.hobbyList)
                 },
                 _public = {
                     render: function (container) {
                         _private.heading.appendChild(document.createTextNode(model.name));
                         _private.img.setAttribute('src', model.imgURL);
                         _private.hobbies.render(_private.div);
                         container.appendChild(_private.div);
                     }
                 };
             _private.div.appendChild(_private.heading);
             _private.div.appendChild(_private.img);
             _private.div.appendChild(_private.hobbies.element);
             return _public;
         },

I removed the IIFE pattern and added the Hobbies view to the Profile‘s members. Then access the members of the passed in model in order to present the resource’s current state to the user.

In the Hobbies component we’ll need to use a technique for looping through the of hobbies.

Hobbies: function (model) {
             var _private = {
                     div: document.createElement('div'),
                     heading: document.createElement('h5'),
                     list: document.createElement('ul')
                 },
                 _public = {
                     element: _private.div,
                     render: function (container) {
                                 model.map(function (hobby) {
                                     var li = document.createElement('li');
                                     li.appendChild(document.createTextNode(hobby));
                                     _private.list.appendChild(li);
                                 });
                                 _private.div.appendChild(_private.list);
                                 container.appendChild(_private.div);
                             }
                 };
             _private.heading.appendChild(document.createTextNode('My hobbies:'));
             _private.div.appendChild(_private.heading);
             return _public;
         }

As you can see, we’re looping through the hobbies array stored in model. We’re using the array prototype method map, which creates a new array based on whatever we return within the callback function.

Notice that I didn’t create a key attribute on the list items. There is no reason to at this point in the development of this application as nothing outside of the Hobbies view is concerned with this list of data as it is presented on the screen.

This is the full code:

<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>Your First JavaScript Project</title>
</head>
type="text/javascript">
/*Add your application code here*/
var DATA = {    
    name: 'John Smith',
    imgURL: 'http://lorempixel.com/100/100/',
    hobbyList: ['coding', 'writing', 'skiing']
};

var App = {
    main: (function () {
        window.addEventListener('load', function () {
            var profile = new App.View.Profile(DATA);
            profile.render(document.body);
        });
    })()
};

App.View = (function () { //the View 'class' library component
    var _library = {
            Profile: function (model) {
                         var _private = {
                                 div: document.createElement('div'),
                                 heading: document.createElement('h3'),
                                 img: document.createElement('img'),
                                 hobbies: new App.View.Hobbies(model.hobbyList)
                             },
                             _public = {
                                 render: function (container) {
                                             _private.heading.appendChild(document.createTextNode(model.name));
                                             _private.img.setAttribute('src', model.imgURL);
                                             _private.hobbies.render(_private.div);
                                             container.appendChild(_private.div);
                                         }
                             };
                         _private.div.appendChild(_private.heading);
                         _private.div.appendChild(_private.img);
                         _private.div.appendChild(_private.hobbies.element);
                         return _public;
                     },
            Hobbies: function (model) {
                         var _private = {
                                 div: document.createElement('div'),
                                 heading: document.createElement('h5'),
                                 list: document.createElement('ul')
                             },
                             _public = {
                                 element: _private.div,
                                 render: function (container) {
                                             model.map(function (hobby) {
                                                 var li = document.createElement('li');
                                                 li.appendChild(document.createTextNode(hobby));
                                                 _private.list.appendChild(li);
                                             });
                                             _private.div.appendChild(_private.list);
                                             container.appendChild(_private.div);
                                         }
                             };
                         _private.heading.appendChild(document.createTextNode('My hobbies:'));
                         _private.div.appendChild(_private.heading);
                         return _public;
                     }
        };
    return _library;
})();

</html>

 

An analogy of an IT department as a pro football team

The captain of the cheerleading squad is now the Head Coach…
The sports journalist who wrote an especially damning article about the team last season is now the Defensive Coordinator…
The water boy is now the Offensive Coordinator…
The veteran Offensive Coordinator has been demoted to Offensive Line Coach, but he may not last because the cheerleaders think he’s ugly…
The Offensive Line is stacked with rookies and Arena League subs…
There is one good receiver and they’ve put me in as quarterback.
It’s going to be an interesting season.

Virtual Pair Programming

I recently experienced a new (to me) approach to pair programming. Given a set of user stories, my teammate and I were ready to begin coding the core domain library for a project. The problem: we are located about 500 miles apart. Our solution: Jitsi and Git.

With the solution created and the projects defined and waiting for us in the repo, we established a video chat. One of us shared the screen so the other could see the IDE. We talked our way through the appropriate Unit Tests which would ensure the domain entities were coded to match the requirements. As I was writing the tests, my teammate started writing the code to make the tests pass. As soon as a set of unit tests were complete, I’d commit/push my changes to the repo. My teammate pulled the changes into his local and then ran the tests. Tests passed, he committed his changes and pushed them to the repo. In less than three man-hours, we had working code with a great test coverage and a respectable portion of the requirements addressed.

This was the most efficient pair programming and the most gratifying TDD experience that I’ve had. It helps to be working with a competent engineer that understands the benefits of TDD. But it also makes pair programming a little bit easier when you don’t have to literally share a desk.

What is the Enterprise Software Product Management Process

At the base level the process for managing software products in an enterprise is very straightforward. Senior Management identifies a need for a product and a Product Manager works with Business Process Analysts to begin planning the product. Once an initial vision for the product is well understood, BPAs work with Subject Matter Experts to develop the Operational Concept. As the operational concept becomes clearly defined, Architecture and Engineering identifies a solution and begins iterating to build and deploy the software. During this phase, two key sub-processes are concurrently being executed: Manage User Feedback and Manage Change. These two processes feed into the queue for the iterations by way of the processes for managing the operational concept.

Each of these processes will be decomposed into smaller processes and their constituent activities in future posts. Regardless of the tools used, these processes should be followed. The procedures – the “How” of the methodology – defines the tools used, but for continuous improvement purposes, the process should not constrain a team to a given tool set. If the process is failing, focus on improving the process; if the tools are not enabling the team to properly complete the process, then that is a separate problem to be addressed. Sometimes the tools will force a change to the process, and that’s OK as long as the team is cognizant about the impacts of a change to the process and accept that the benefit of using the tool is worth changing the process.

Process work flow

From this perspective, it looks quite simple. And it really is, it just requires discipline to adhere to the process and self inspection to ensure that the process is meeting the needs of the team. Also, the ability to recognize when an aspect of the process is not adding value and willingness to change or even remove it when these aspects are discovered.

RACI

Processes are defined by the activities that must be completed in order to achieve the goal of the process. When talking about process we need to know the parties involved, the “Who” in the “who, what, when, where, why and how”. There are several roles that participate in an Enterprise Software Product Management process. An individual may fulfill the responsibilities of more than one role, but the scope of the duties are defined by the role in which they are acting.

Each process activity has a defined RACI – Responsible, Accountable, Consulted, and Informed – matrix which determines the participating level of each role in the context of the activity.

Responsible

The role(s) actually doing the work required by the process activity. An activity may have more than one role responsible for its completion.

Accountable

The role ensuring that the process activity is being completed in a timely and correct manner. An activity will only have one role that is accountable for its completion.

Consulted

The role(s) most likely to have necessary information in order to complete the process activity. An activity may be able to be completed without the need to consult with another role.

Informed

The role(s) that need to be informed that the process activity is in work/complete. Typically the role(s) accountable and responsible for carrying out a successive activity.

Key Roles

Below are the key roles that I believe are necessary to participate in the process of managing enterprise software products.

Senior Management

This role provides the business case and finances for the product. They control the governance of the development effort and are responsible for defining the product need/vision and for approving the team’s understanding of the Business Objectives that the product is being built to meet. The people that fulfill this role are functional area managers all the way up to the Chief Executive Officer.

Product Manager

The product manager role is the proxy for the end consumer of the product. The product manager has overall product mix responsibility for the requirements. The product manager must insure that the product vision is met through the requirements and the acceptance tests developed to verify/validate the product. The product manager must show that the product aligns with the organization’s strategic planning and fits the market segment(s) intended in the original vision statement. The product manager will insure that the product stays within budget and that the business case is realized.

Subject Matter Expert

A subject matter expert can be anyone who happens to have the knowledge of an area of the business that aligns with the product vision. A subject matter expert is responsible for communicating and transferring their knowledge to other members of the team, such that the appropriate area of the product vision can be realized.

Business Process Analyst

This role acts as the liaison between the roles that identify the business problem and the roles that will produce a solution. The term “analyst” in this role’s title comes from the fact that people in this role spend a lot of time analyzing the actions performed and the information processed by the business. The Business Process Analyst interviews Senior Management and Subject Matter Experts to define the user community and the processes that they must work through in achieving the business objectives that are aligned with the product. As these become defined, the BPA will begin working with the Test and Architect roles to define the features of the product that will be put in place to aid the users with those processes. Future posts will delve deeper into the notion of Business Process Analyst instead of the traditional role of Business Analyst.

Solutions Architect

The Solutions Architect takes responsibility for the continuous improvement and learning in the software engineering team. An architect’s role is to lead and to communicate on behalf of other engineers. A Solutions Architect lends experience and skill and shows leadership by coaching fellow engineers. The Solutions Architect is Accountable for overall system design, code reviews, and iteration tasking. The architect is also responsible for maintaining the architectural integrity of the product and ensure the success of the project by designing the foundations on which all the value can be realized. This includes defining both the organizational structure of the application and the physical structure of its deployment. In these endeavors, the architect’s goal is to reduce complexity, decrease coupling and regression effects, and increase the cohesiveness of components by partitioning the system into parts which can be built and tested independently. The resulting architecture is extremely important because it not only dictates how the system will be built going forward but also establishes whether the system will exhibit the many traits that are essential for a successful product. These include its usability, whether it is reliable and maintainable, whether it meets performance and security standards, and whether it can be evolved easily in the face of changing requirements.

Software Engineer

The software engineer is responsible for the bulk of the work coding the product. The software engineer should suffer a minimum of communication overhead allowing for a maximum effort on construction of code. In addition, during the early stages of a product, engineers may be expected to help specify product requirements not included in the system requirements and to work on analysis and architecture activities as part of a multi-disciplinary team. Enterprise software should be written with a suite of unit tests. In my opinion, using Test Driven Design is the most efficient way to achieve a clean code base. In order to write effective unit tests, the software engineer must be intimately familiar with the context for the requirements which means that interacting with the BPA heavily in the first few days of an iteration are essential to a positive outcome.

Build Engineer

A build engineer is a specialist role who performs the function of facilitating the build or integration of the source code. The build engineer will run the build, develop scripts for automation of the build and automated reporting mechanisms such as the build report. As the requirements for an iteration are solidified, the Solutions Architect will create the necessary folder structure within the source code repository to represent the required components of the system (in .NET terms, the solution and project files). It is the Build Engineer’s responsibility to ensure that for each iteration, any new components are added to the build and deployment scripts.

Test Manager

The Test Manager must understand the context for the project and help others to make informed decisions based on this context. The Test Manager works very closely with the Business Analyst in order to gain this understanding.The Test Manager is responsible for conducting test case reviews to ensure that the test cases will exercise the system sufficiently. The Test Manager also coaches fellow testers as a mentor.

Tester

The tester is responsible for writing the test cases for the requirements. A key goal for the tester is to find and report the significant bugs in the product by testing the product. Once a bug is found, it is also the tester’s job to accurately communicate its impact and describe any workaround solutions that could lessen its impact. The tester writes bug descriptions and steps for recreating the bugs easy to understand and follow. The tester participates with the entire team in setting the quality standards for the product. The purpose of testing is to prove that known features work correctly.

Quality Assurance

This role is responsible for assessing the quality in the product as measured by quality control and the quality assurance measured as conformance against process definition. QA reports variance from specification, variance from plan, and variance from process definition. QA reports can be used to assess the likely quality of the product and whether or not the organization exhibits control in its operations. With proper tooling, this role can be almost entirely automated.

Systems Administrator

The Systems Administrator is responsible for the upkeep, configuration, and reliable operation of computer systems; especially multi-user computers, such as servers. The system administrator seeks to ensure that the uptime, performance, resources, and security of the computers required to host the product, without exceeding the budget. To meet these needs, a system administrator may acquire, install, or upgrade computer components and software; automate routine tasks; write computer programs; troubleshoot; train and/or supervise staff; and provide technical support.The Systems Administrator works closely with the Solutions Architect and the Build Engineer to ensure that systems conform to the requirements as well as to provide physical constraints of available systems that may impact architectural decisions.

Why Is Process Important?

For enterprise software management, process is important because having a documented way of doing things enables adding new team members more efficiently and provides a mechanism for improvement. Process is important to the business as well as to the engineering team.

What is “Process”?

Process describes what needs to be done, not how it is done. Process allows an organization to see the information that needs to move from one state to another without prescribing how to make this transition. In this way, a process describes the nature of the business without constraining it to a particular toolset.

For an example, the process of writing a research paper hasn’t changed. You look for information in authoritative sources, then copy important quotes with their attribution. You outline what you want to say about your discoveries and then you expand on those thoughts. We used to do this with a lot of notebook paper and books, magazines and journals at the library. Now we do this with word processing software and search engines. The process – the what – hasn’t changed, but the procedure – the how – has.

In developing and implementing a process for enterprise software development, I believe the principles that should be the guiding force are: Balanced Priorities, Collaborative Understanding, Architectural Planning and Continuous Improvement. These four principles correlate nicely with the Core Principles of the Eclipse Foundation‘s Open Unified Process.

Core Principles

Balance competing priorities to maximize stakeholder value

For a software product to be successful, stakeholders and team members must converge on a clear consensus of the following factors:
  1. Constraints placed on the development team (cost, schedule, resources, regulations, etc.)
  2. Constraints placed on the solution
The challenge for all involved is creating a solution that maximizes the value delivered to the stakeholders subject to those constraints. Balance is about making the critical, cost-benefit trade-offs between desired features and the subsequent design decisions that define the architecture of the system.

Collaborate to align interests and share understanding

For a software product to be managed and built successfully, those involved must overcome the fact that there is a diverse range of interests and skills that are brought together by the common goal of bringing the product to fruition. An Enterprise Software Product Management Process should enable a team to live up to the principle of healthy collaboration by

Focus on the architecture early to minimize risks and organize development

Without an architectural foundation, a system will evolve in an inefficient and haphazard way. Such a system often proves difficult to extend, reuse, or integrate without substantial rework. Architecture is the description of the organization of the components of a system and the interfaces by which these components interact. Ways to adhere to this principle typically include:
  • Leveraging the architecture as a collaborative tool
  • Cope with complexity by raising the level of abstraction
  • Organize the architecture into loosely coupled, highly cohesive components
  • Reuse of existing assets
  • Simplifying processes and optimize on strategic systems

Evolve to continuously obtain feedback and improve

Knowing all of the stakeholders’ needs at the inception of a product is impossible and even if it were, those needs are likely to change over time. The intention behind this principle is to continuously get feedback in order to improve both the product and this process. A team can adhere to this principle by:
  • Developing in iterations
  • Focusing iterations on defined management milestones
  • Embracing and managing change
  • Establishing objective measures of progress
  • Continuous improvement through iteration retrospectives