Sunday, June 5, 2016

Sprint 1

This week, I wanted to make sure to deliver some working software based off of last week's epic. Typically, working and demonstrable software is delivered following a sprint. I will lay out the stories in this sprint shortly, but first, I wanted to talk a little bit about NodeJS and some of its quirks.

Node has been around since 2009 and takes a different approach than other programming languages. It is a JavaScript framework that can be used to make server applications. It runs in a single non-blocking thread. Where different frameworks, such as Java, support multiple concurrent threads, this may seem like a major weakness. However, since Node executes in a non-blocking manner, it can support a large number of concurrent users without having to synchronize objects in memory across threads. Both approaches have their strengths and weaknesses, but this concept is critically important to Node development and seems really strange at first.

In my git repository (more on this later), I have included three really basic node scripts that demonstrate some weird behavior. Example 1 looks like this:


var i = 1;
console.log('Initial value ' + i);
addOneHunder();
console.log('Value after function called ' + i);


function addOneHunder() {
    i += 100;
}

In this humble example, a global variable called i is instantiated (this is a big fancy word meant to intimidate non-programmers, all it means is we are creating a new variable or object). The console displays an initial value for i of 1. A function is called adding 100 to the global variable and the console displays the final value of i as 101. All of this should seem perfectly normal.

Example 2:
var i = 1;
console.log('Initial value ' + i);
setTimeout(addOneHunder, 2000);
console.log('Value after function called ' + i);


function addOneHunder() {
    i += 100;
}

Again, a global variable is instantiated with a value of 1. The value is displayed and the setTimeout tells the process to wait for two seconds and then call the addOneHundred function. If you were to run this from your command line, the output would be:
Initial value 1
Value after function called 1

The command window would seem to hang for a few moments and then the command prompt reappears. What the heck just happened??? This demonstrates the non-blocking nature of Node. The first two console statements execute, then the addOneHundred function is called two seconds later, and the process ends because there is nothing else to do. Things are not flowing from top to bottom which seems really strange at first, but it is also powerful.

In my final example, the code looks like this:
var i = 1;
console.log('Initial value ' + i);
setTimeout(callAddOneHundred, 2000);
console.log('Value after function called ' + i);

function callAddOneHundred() {
    addOneHunder(function() {
        console.log('After waiting two seconds i = ' + i);
    })
}

function addOneHunder(cb) {
    i = 'magic!';
    cb();
}

In this simple example, I have added the concept of a callback. Callbacks are usually anonymous functions that are passed as part of the signature. That's right Node/JavaScript allows a function to be passed to a function. The function callAddOneHundred calls addOneHundred and then executes the anonymous function. Additionally, the variable i started out as an integer and then became a String. If this were Java, the compiler would have thrown a fit. However, Node simply shrugs its shoulders.

When I describe NodeJs versus Java, imagine you have two different English professors. For a mid-term assignment, you write a ten page essay. You work on it very hard, do your research, make compelling points, and add a little humor. You are very proud of your essay. You give the essay to Professor Java and this professor gives you an F because you accidentally used "there" instead of "their" in the middle of the very last paragraph. Then you give the exact same essay, typo and all, to Professor Node. Professor Node gives you an A and says that she knew what you meant and it did not negate all of the effort over one little mistake. Neither approach is right in programming and some like the strictness that Java enforces.

Another little goody to Node is it comes bundled with NPM. NPM is a repository of (mostly) open source code that can be added to your application with almost zero effort. From the command line, simply type:

sudo npm (package name) --save

The project's package.json is updated and the package is installed as a dependency. In my git repo, I do not include the third party packages I used. Instead, the user is expected to run npm install. If any changes are made to the packages, I can either lock the version to what I have tested against or run npm update. Although Java has integrations like Maven, it is not part of standard Java. I have worked at plenty of places that steadfastly refuse to use Maven, making it nearly impossible to bring in third party software. Given the wide variety of excellent free and open source software that is readily available, this approach is quite limiting.

Finally, I've been blathering about my git repo. Git is simply a source control tool. It might be overkill for this modest project, but I am trying to demonstrate concepts that would be used by a real agile team. Using git, multiple people can work on the same code simultaneously. Typically, a developer will clone the original repo and then create a feature branch. When the developer is satisfied that they have met the requirements of the feature, they check it into the repo and create a pull request. Usually, another team member will review the pull request. Using github, it is easy to see what modifications have been made between the original branch and the feature branch. If everything looks good, they feature branch is merged. At any point developers can pull code from the repo so that their feature branch does not deviate too far from the main branch. Tools exist to handle the dreaded merge conflict, but these should not happen often.

As promised, I took the first part of the epic and broke them into stories below. Each story represents a branch in my git repo and since I'm the sole developer, I merged my own pull requests although this is considered a worst practice.


Daemon-01
As a… Security-minded person,
I want to… Require the server to start with the Dexcom Share username and password as a parameter from the command line.
So that… No passwords or usernames are stored in text files that might accidentally get committed and then cached forever on the Internets.
In order to keep usernames and passwords out of text files, I would like the server to require two parameters on startup. The command to start the server should be node app.js [username] [password]. The Dexcom Share username and password must never be stored anywhere. Before attempting to login, the system should do a basic sanity check and make sure there are exactly two parameters passed to it.
Daemon-02
As a… Developer,
I want to… Connect to the Dexcom Share service with my username and password,
So that… I get a session ID for subsequent requests and know that my Share username and password are valid.
Once an administrator has started the service with node app.js [username] [password], the server should attempt to log into the Share service. If the credentials are not recognized, the program should immediately come to an end with a message to the administrator. If it is successful, the server should hold onto the session ID for subsequent requests.
Daemon-03
As a… Developer,
I want to… Start a process that gets the latest glucose reading from the Share service,
So that… I can apply the reading to the rules engine to see if any texts or calls should be sent.
Once a login and session ID have been obtained, I want to continually poll the Dexcom service every five minutes and receive a reading. For now, the reading can simply be output to the console.
Daemon-04
As a… Developer,
I want to… attempt to login again if my reading fails due to authentication,
So that… I can continue monitoring without interruption even if my session ID expires.
If the session ID expires, the login should be reattempted to prevent any interruption in service.
Daemon-05
As a… Person who worries about fault tolerance,
I want to… Wrap my node application in a process monitor,
So that… If something unexpected and bad happens that would normally cause Node to crash, it will restart itself.
If Node comes across a catastrophic error, the polling mechanism should restart itself.
Daemon-06
As a… caregiver who tends to think about setting alerts in local time,
I want to… set alerts based on my timezone,
So that… I don’t set alerts incorrectly.
The timestamp provided by Dexcom Share will be used as the single source of truth. However, the time is provided in UTC time. This could lead to confusion on behalf of the user. The user should set the alerts based on their local timezone and the UTC time should be converted before determining alerts.
So, in one week, I created six smallish stories and use those stories to check in feature branches. I can now demonstrate working software by cloning the git repo and following the instructions in the readme. Nothing here is earth shattering, but it shows some nice progress towards the ultimate goal. I have created a service that is fault tolerant and capable of polling Share every five minutes. This will be used to build on as I add in additional functionality. Here is the evidence that everything is working:
Thankfully, Zoe's glucose is at a reasonable number and I do not have to expose my shoddy parenting with a glucose of over 300. One quick note, I was planning on banging out each part of the epic a week until the project was completed, but I decided to do a quick detour and use the little engine built in Sprint 1 to make a 100% browser based tool to connect to Share. Right now, using Share the only way to get a reading is to download the Dexcom Follower App on an iOS device. While I, personally, like iOS devices, I find this policy baffling/insane. Given that Apple has only 15-18% of the smart phone market, Apple devices are typically more expensive than Android devices, and that caregivers of diabetics might resent having to shell out a lot more cash to buy an Apple device just to get readings; I think Share users deserve better. Stay tuned as next week I plan to release the browser based tool. So the next time you hire a baby sitter and she has a shiny new Samsung phone, just grab the closest laptop, point it at the website, enter your Share username and password, and the babysitter can receive updates and alarms without installing any software.