Domain Modeling For Better Contracts

In the post about communicating contracts through enforcing endpoint contracts, we took a look at some basic types which are available in Signet. Today we are going to talk about how to add more information to your types by creating your own data types.

Last week we took a look at how to build types as sets with characteristic functions. This week we will apply that information in order to add extra information to our types.

By this point I’m certain there are plenty of people who are thinking I’ve gone completely off the rails. Javascript, after all, is a dynamically typed language. Don’t burden yourself with all of this type stuff and just write some code!

Although this is true, most people view types as a constraint which only causes pain. Though this might be true if you are coming from a language like Java which contains lots of artificial constraints around type creation, and after all is said and done, the types are still weak and restrictive.

On the other hand, if we consider types as a way to add a layer of correctness checking and a tool for communicating with others, types become less a restriction and more a tool we can use to make our programs better. Good types will make a program transparent and predictable. These are traits we definitely want in our programs.

Just as a refresher, let’s have a look at where we left off with our purchase API from the enforcing endpoints blog post. This way we have a common position to understand where we started and where we’re going.

Now that we have our API defined with regard to basic types, we can start to ask more meaningful questions. Instead of asking things like “what does this function do,” we can ask directed questions to inform our programming better: What kind of numbers are they? What is in the array? What kind of argument must the function take?

The last two questions are easiest to answer since we don’t have to look any farther than higher-kinded types. This is, of course, scary sounding the first time you hear it. I had no clue what a higher-kinded type was the first time I heard the word. Fortunately, many of you may already be familiar with them even if you don’t know the word. Java and C# both support higher-kinded types.

Higher-Kinded Types and You

First and foremost, let’s discuss what a higher-kinded type actually is. (It’s a type.) Once we have a better grasp on that, we will use it in code to make everything a little more clear.

A higher-kinded type is simply a type which takes a type as an argument and returns a type. I know, that sounds weird. How does a number take a string and return a type? I asked the same thing.

It turns out, however, that it’s not nearly as foreign as it might seem. One very common type we rarely think about in Javascript which could easily be handled as a higher-kinded type is an array. An array is, itself, a type, but it contains values which are also typed. This means, if we had a language to express it, we could declare an array which contains only a single type.

As it turns out, there are potentially infinite different types which are, or could be, higher-kinded. In this post we are going to look at just two: array and function. With the type signature language available with signet, we can explicitly declare an array type as needed. This means we can do things like the following.

We can see both of the tested arrays are completely valid Javascript arrays, but the second is not an array of exclusively numbers. There are ways we could create an array which would support numbers and strings, but that’s beyond the scope of this post.

Just like we can declare information about arrays, we can also say something about the expectations around a function. Instead of simply saying a value is “function,” we can actually say a value is a “function which takes a number.” In much the same way we declare our types in arrays, our function type declaration is “function.”

Now that we have an expanded type language to draw upon, let’s update our API and clarify the communication of our domain model.

Subtyping With Characteristics

Now we just have the ‘number’ type scattered everywhere throughout our code. Although this is better than nothing, it would be SO MUCH better if we actually knew something about those numbers. What do they mean? How are they used? What are the constraints?

It turns out we have just the thing to remedy this pain, it’s called characteristic functions. As we know from our earlier discussions on characteristics, we can add richness to our type system through set-describing predicate functions. (Protip: all predicates describe sets)

Before we dive into creating new types willy-nilly, let’s take a moment to account for the different number types we have. By properly identifying the actual domain language we care about, we can create better types which will allow us to clearly describe our application to people who might know nothing about it.

Ultimately, we care about tax, price, amount of tax to pay (tax amount) and purchase total. If we were to simplify this list a bit, we can identify a couple of distinct bits of information.

First let’s consider tax. Tax is a percentage amount. Since, where I live, taxes are always greater than or equal to 0%, but always less than 100%, I am going to say tax is a percent value which will always fall between 0 and 1. For example, in San Diego, sales tax is currently around 8% or 0.08.

Now, we can take a look at price, tax amount and purchase total. Each of these is a value which is related to a value an amount our customer will be paying. This means we can roll these all into some aspect of price. We will say a price value will be greater than or equal to 0. This describes our data pretty accurately for the moment, so let’s go with that.

With our base types sorted out in a way we can jump off from, we can start building characteristics. By clearly defining our characteristics, we give our new types programmatic meaning. Let’s see what our basic characteristic functions will look like for price and percent.

The other piece of this puzzle is, we need to register our types with Signet. Fortunately, this is a simple process. We know that each of these types is actually a number, so we can simply use the subtype function and declare these two functions as new types, inheriting from number. This is also why we didn’t need to test each value to see if it is a number, our subtyping will guarantee we only verify numbers.

We can use our price type to create our other two types by simply aliasing them and using the price definition to ensure our data constraints are clear.

Let’s have a look at our updated API and see how our types are coming along!

Duck Typing our Object

At this point, our API is pretty clear, but there is still one last type which just doesn’t quite convey the information we want to know. Our array of purchases is still described, simply, as an array of objects. This could be much better, if only there were a way to check it.

As it turns out, the Go language has popularized the notion of object similarity through duck typing and that is precisely what we are going to do here. If we know enough information, we can tell whether our object satisfies the Liskov substitution principle, and can be used in place of our intended object.

Signet provides a means to perform duck typing as well, so we don’t have to build our characteristic function from the ground up every time, because that could end up being a LOT of repeated code. Let’s build a duck typing characteristic and finish up our API types.

Now we have a name for our purchase object type, which means we can easily check whether our array of purchases actually adheres to our expectations. Plus this will provide a way for others to understand what we intended when we wrote the code, making it much easier to write new code against the existing API.

Wrapping Things Up

Although this just scratches the surface of using types in your program, hopefully this exercise helps you communicate intent and define a clear domain model. By taking core types we already know and applying a small amount of predicate logic, we surface a new way to talk about our program and the data we use.

Instead of simply using old code as a reference for what it does, add a little annotation, a little bit of logic and get a lot more bang for your buck. In the end, types don’t make everything correct all the time, but they do a lot to make you and others like you a lot more awesome!

Comments Off on Domain Modeling For Better Contracts

Types, Sets and Characteristics

A couple weeks ago, we looked at using Signet and some of the core types to add type information to function calls. Although it is handy to have a variety of base types available to provide signatures for your functions, sometimes you want more control and finer-grained behavior.

At the most foundational level, applied types can be viewed as sets of values. This means, for any type, we can easily construct a set which will describe that type. For instance, the type ‘string’ can be written as the set of all values which are strings. Although this may seem like a trivial way to perform a conversion of a type to a set, it gives us a way to start rethinking the way we interact with type information.

Sets as Types

We can, somewhat informally, say that sets are types. Although this doesn’t capture the nuance of types, it allows us to capture a lot of power in a simple idea. We looked at defining the string type as a set of values. What this really means is, strings are a certain set of values within all values assignable.

If we begin our sets by considering all values assignable and available in within Javascript, we can refer to that set as our “universe.” Within that universe, we could choose a variety of different sets, but regardless of which set we choose, the new set will be contained completely within the original universe.

Using this universal definition, we can consider our strings again and consider how we might describe our set of all strings. First of all, we can ask if a value is contained within our universe. A good example of a value which is distinctly NOT in the Javascript universe is 1000! (1000 factorial). Although this is an integer which actually exists, Javascript will simply evaluate it as infinity. This is not something we will need to test for, it is simply the indication of an upper bound in Javascript.

We could, however, define a set of numbers we declare as our domain set. We can call this an explicit set definition. By turns, we can define a set by way of excluding items which are not in the set. This inverse set can, equally, be declared explicitly, or we can define a function which will simply tell us whether something is in the set or not. This implicit method of creating a set can be referred to as an induced set.

Let’s take a look at a meaningful question we could ask. Let’s ask if a value is a number. This means we are going to call a function which accepts type of * and returns a boolean. This kind of function is called a characteristic function.

Although this function, by itself, is not a big step away from what we already know, it lays the groundwork for defining a richer set of types we can interact with. From the function isNumber, we get an induced set of all values which are numbers, rather than defining the type set explicitly.

Propositions and Predicates

It has been shown in the academic community that propositions are types. What this means is we can actually consider propositions such as A and B in the expression A ∨ B as types unto themselves.

Any proposition can either resolve to a theorem (⊤) or an antitheorem (⊥) which roughly equates to the idea of true or false. In other words, we can ask a question and the answer will either be “yes” or “no.” Although this seems non-obvious, at its face, this is the foundation we will use to construct a richer set of types within Javascript.

We have already seen type construction where we use a predicate to manage inclusion in a type set. We are stating that a value α must be in the set of numbers if α is a number. Even stronger than that, we can say, since our set contains ONLY values which are numbers that if α is in the set of numbers it has a type of number. This relationship between sets and type implementations is important for capturing greater amounts of information about a value as we construct subsets from sets we have defined. Let’s have a look at the logical notation to see predicates in action, so we can tie that together with our predicate notation.

Njs = the set of all values which are Javascript numbers
A: α is a Javascript number
B: α ∈ Njs;

A → B
B → A

Of course in our implementation we really only worry about the second relation, i.e. that if a value is in the set of values which conform to the number type, the value must also conform to the number type. Given the definition of B, α ∈ Njs;, we can actually conclude that the first relation is true given the definition of Njs.

We can actually reformulate this to express the type-set relation more generally. If we simply replace our specific number set with a set of any type Τ we get a new, very useful formulation we can use to extend our type reach well beyond the specifics of the language.

Τjs = the set of all values expressible in Javascript of type τ
A: ατ is a Javascript value of type τ
B: ατ ∈ Τjs

A → B
B → A

That’s a lot of symbols, words and relations. What this really means is we can identify and define any arbitrary type logically and, in turn, define a set containing all values of that type, which will induce an “if and only if” (iff) relationship. That’s a lot of words and symbols. Let’s take a look at how we might use this to implement our own type.

Defining a New Javascript Type

Clearly we won’t be able to build our type into the core language without getting on TC39, issuing a new standard and waiting for several years while everyone adopts it, but we can induce our type through a new predicate function. Let’s suppose we want to define a new type, Integer. We could express our type in the following way:

Intjs = the set of all values expressible in Javascript of type number which are integers
αint ∈ Intjs

With this, we can define a function expressing this relationship, which we can use to verify whether a value is in our set Intjs or not. With regard to the relation between types, expressible values in Javascript and our integer set, we can guarantee the stability of our type and the correctness of our verification.

Although this function is sufficient for verifying whether a value is an integer, we are actually duplicating our efforts. Moreover, it lacks a certain expressiveness which we might like to see. Let’s use our original isNumber function to say a little more about the meaning of our int type.

This new function performs the same check as the original, but it reflects a deeper relationship between our number set, Njs, and our integer set, Intjs. In other words, what we can see expressed here is the typical inheritance property of the is-a relationship.

The Is-A Relationship of Types

As is true for objects in classical object oriented programming, types can also have an inheritance relationship where one type is a subtype of another. This is what we mean by is-a relationship. We can say an integer is a number, or a name is a string. Although an integer can be a type in its own right, we know the number type is the foundation type in Javascript for any numeric representation. This means, for any function which requires a number, an integer is an acceptable value.

Our isInt function demonstrates the is-a relationship by using the number set definition as the first requirement of our check for set inclusion. Let’s continue the chain and create a characteristic function to defining our natural number. Our natural number set will be a strict subset of our integer set.

Now we can see that a natural number is an integer which is a number. This, of course, is similar to OO subtyping with regard to relationship, but is compositional in nature. In fact we can actually describe this type relationship as a relationship of sets, like so:

Naturaljs ⊂ Intjs ⊂ Numberjs

With the repeated behavior of including a function call from the superset, we can start looking for a way to uniformly describe our sets and their relationships. Let’s create a new function, subtype, to help us create set relationships in order to streamline the process of defining type relationships.

Subtype allows us to define our types with functional composition and define our new characteristics with the assumption that we are already working from within a specific type. Let’s rewrite our isNatural check using subtype.

Now the body of our characteristic function is expressed with an implicit relation to the superset of natural numbers, integers. This kind of higher-order function use to express set relations is extremely powerful for defining and describing value types we can use in our development.

Wrapping Up

This was a somewhat dense tour of how we can construct types in Javascript, so don’t worry if it takes a little while to pull the pieces together. The important take-away is that we can construct our own types with meaningful names and clear relationships in order to better understand the way our programs work.

At the end of the day, we are human, so expecting us to actively deal in generalized abstractions such as strings and numbers may not be a reasonable request. Instead, we can reclaim the reins and define our own type language which speaks to future developers in the language of our intent. Go make types and make your programs better!

Comments Off on Types, Sets and Characteristics

Currying Matters: Clarifying Contracts

Function contracts are a tricky thing. Ultimately what they define is an API for your application, but they also define how you write your internal behaviors. This balancing act can either lead to clear, well written code, or it can quickly devolve into ball of tangled string.

Walking the clean code, clean API line can seem to be a daunting task. It’s common to hear people say this is precisely what Classical OOD is built for. By maintaining state, methods can accept partial requirements and allowing the developer to build their behavior in time. I argue this kind of state management leads to extra cognitive load as the developer is required to keep track of the managed state. By currying and clearly exposed intent, incremental behavior building becomes a trivial task done in a reliable set of steps. It also leads to better program design and behavior determinism, making testing much easier to reason about.

A Small Example

Let’s have a look at a slice function as an example. It’s common to want to call slice on arguments objects and arrays alike. This means we have to vary our behavior for each different behavior. Instead of showing example of different usages, I’m going to jump to a general slice implementation similar to what was written in JFP v2.x.

This function makes use of a convenience function which we will continue to use throughout this post. Here is the implementation of pickEnd.

Let’s have a look at how we might accomplish a few simple tasks using our original slice function. We will create a function which will slice an arguments object or copy an array, a function which will drop the first three elements in an array and, finally, a function which will capture the elements from an array from indices 1 to 3.

As we can see, using our slice function forces us to either bind arguments, or actually wrap the entire behavior in a function. This kind of inconsistency makes our slice implementation difficult to use. There must be a better way!

Currying The Slice

The application inconsistencies in our new code leads me to believe we need a better solution. When dealing with a single function API, currying can, often, be illuminating regarding argument order and function implementation. At the very least we might land on a first uniform, stable application. Let’s have a look at what currying is and how we can apply it to our existing function.

Formal currying is defined as converting a function of multiple arguments to a series of on-argument functions. This means currying a function of 3 elements would go a little like this:

If we apply this formal definition to our function, it will produce a new series of functions which are called in order. This means each function progressively accumulates information about execution state without needing any external management system or object. Let’s take a look at a formal currying of slice.

If we use this new definition of slice, we will need to revise the implementation of our functions. Let’s dig in and see how currying makes application more uniform.

Although we have to wrap each new function in an anonymous wrapper, we now have complete uniformity in how we apply slice. With this uniformity, we can now, safely, reorganize code and guarantee code depending on our API won’t break.

Three Arg Monte

Since each of our derivative functions only take an array as an argument, we can fiddle with the inner workings so long as we don’t alter the output. Suppose we swap the order of the output functions, capturing values at different stages of execution. It is, in fact, no different than if we had reordered the parameter list in the original function, but without the pesky .bind() bit.

Let’s take our curried function and move our end parameter up the chain, next to the start parameter. This means our function series will always take a start and end value, which makes our values parameter the last argument. Let’s see the resulting reorganization.

With this new parameter order, we actually move the values parameter to the correct position; in other words, we can apply all of our indices first and take the values argument last, leaving us in a position which is correct for creating a variety of novel behaviors directly.

Our application of slice has remained uniform, while allowing us to exclude the anonymous function wrapper for all three applications. This is definitely closer to what we really meant to say at the beginning. If only we could get rid of that required second call.

Collapsing The Calls

Now that we have found a parameter order which serves us the best, let’s get rid of the extra function call. It is useful for takeFrom1to3, but it actually makes the application of slice for argumentsToArray and dropFirstThree unnecessarily complicated since we call a function with no argument. We want to eliminate confusion where possible.

Since curried functions can be expanded from multiple argument functions, what’s to stop us from reversing the process? Moreover, it is reasonable to collapse only the parameters we want at a given level. Let’s reverse the currying process for start and end and see what we get.

Slice has been collapsed back into a function which captures our indices early and applies them, lazily, to the final argument as we need execution to complete. This means we can actually get the uniformity we saw in earlier reorganizations, with the API sanity of a well-defined function, which happens to optionally take an extra argument after a start index. This is probably best viewed in an example.

Throughout the process, all three of our derivative functions have only ever taken a values argument, but the application of our deeper=level function has brought us to a point where the contract is most sensible for flexible application and reuse. Better yet, each of the slice applications expresses the intent more closely since only the indices we intend to use are used at application time.

API Clarity, At Last

Someone said, recently, on Twitter that what most people call currying is actually partial application. As it turns out this is only partially true. The line between currying and partial application is so blurred, I am inclined to argue that partial application is merely a special case of the more general form of function currying.

Moreover, currying is not a one-way street. Instead, it is a tool to help us identify better ways to express our programs through expanding and collapsing arguments. By better understanding how currying works, we can actually experiment with different configurations of our functions, ideally, without overhauling contracts, types and the like.

When used with intent and care, currying enables us to create functions which have sane, meaningful and expressive contracts while also providing the flexibility to fluidly apply a general-purpose function in a variety of different situations. In other words, if your function contract stinks, maybe it’s time to apply a little currying and make your code awesome!

Comments Off on Currying Matters: Clarifying Contracts

Enforcing Endpoints: Types and Signet

What a ride! I spent the last month preparing a talk for and presenting at Lambdaconf. If you haven’t been, you should. Of the conferences and coding-related events I have been to, this was probably the coolest, toughest, mind-bendiest one. It was awesome. I learned a lot about myself while I was there and a lot about the world beyond the horizon of what we consider “conventional production development.” More than that, it’s all coming to a developer shop near you sooner than you think.

You should go.

I have been talking about types in Javascript lately and this post continues the tradition. As I have been working on, and with, Signet, it becomes more and more obvious why types and signatures are fantastic in simple, raw Javascript code.

There is a lot of discussion about languages which compile to Javascript which support types. This includes Elm, TypeScript and PureScript, though there are more out there. Although I feel these languages may bring something interesting to the table, I feel they are largely akin to writing a language which compiles to C. If there is a flaw in the underlying language, compiling to the flawed language without actually addressing the problem is a band-aid, not a fix. We actually need real types in real Javascript.

I am not a die-hard type convert who wants everything to be typed to a ridiculous degree. Instead, I actually believe that blended dynamic and static typing can lead to an amazing, joyful programming experience. Imagine a world where you can bolt down the contract on things the world touches while leaving the internals to move fluidly through refactorings without having to worry about whether you’re violating a contract.

Programming in a Dynamic World

Let’s imagine you have a bit of code which takes a single purchase record and computes the final total for that record including tax. The code might look a little like what I have outlined below:

We’re not going to dive into why some of the functions are curried, let’s just accept that’s the way they are for this post.

Everything in this code has a clear name and, ultimately, speaks to the intent of the behavior. I’ll assume you are in an agile shop where your code is not thoroughly documented. Instead, you are relying on tribal knowledge to ensure people understand what this code does and how to interact with it.

The likelihood is someone is going to do it wrong.

This brings us to the way Javascript behaves. Javascript will, with all the best intent in mind, try to do the “right” thing. This means, passing numbers instead of objects, strings instead of numbers and NaN could all result in a running, though wholly incorrect program.

The internals of this small module might not need to be protected since anyone working in the file will be compelled to read the code and make sense of the words on the screen, but people who have never seen this code, and perhaps never will, still need to understand what correctness means. Do they know the functions are curried? No. Do they know the names of the variables? Probably not.

The fluid awesomeness of Javascript’s dynamic nature just bit us. Hard.

If You Liked It You Should’a Put A Type On It

One of the greatest failings of assuming clear names will make things manageable is that the names are rarely if ever seen outside of code they are used in. Some editors like WebStorm and Visual Studio Code will pick up the names within modules given the programmer is working with node imports and everything is properly exported, named and referenced.

Even TypeScript can’t save us from this kind of problem since the types are only supported at transpile time, so type erasure eats our one standing bastion of truth. What if we added a little signature and type help to tell others what we are expecting and what they can expect in return?

This is where Signet comes in. By using a modified Hindley-Milner type notation we can actually read what the API does and how we can interact with it. On top of that, we get real, fast type checking at runtime, which means type erasure is a thing of the past. Let’s have a look at our API definition with type enforcement.

The signature annotation not only tells us the kinds of values our function expects, it actually tells us that after the first execution we can expect a function back again. This means we can gain a tremendous amount of insight about our function without knowing anything about the internal workings of the function. Instead of having a true black box, we now have a black box with instructions on the side telling us how to use the thing. We don’t know how it is implemented, but we know it works the same way every time.

With this new enforcement, we get the following behavior:

Closing up Shop

In the end, the challenge in any programming project is not about whether or not you can write simply maintainable code, or whether you should use types or not. Really, it is about making sure you are clearly communicating with the people who rely on your code to do what it says on the label. This means, within the code itself, it should be clear, obvious and intentional. From the outside, any code which is accessible to others, including your future self, should declare what it does, and we should make use of every tool we can to simplify the process of gaining an understanding of what to expect.

By signing and enforcing your API, you get all the benefits of a type checker, plus signature metadata which means you don’t have to go rifling through code that is not immediately related to the task at hand. Meanwhile, under the covers, we can rely on patterns, good naming and clean code to ensure our code continues to deliver value and convey meaning. Now, go add some types to your code and make life better for your team!

Static Methods on Javascript Objects

I’m a big proponent of unit testing. This means that any code I can test, I do. When I work in the browser, however, it becomes more challenging to effectively unit test all of the code I write without spinning up an instance of PhantomJS. On top of that, most of the code I write in the browser, now, uses Angular as the underlying framework, which means my requirements are even more restricted since the go-to testing environment for Angular is Karma, which uses PhantomJS to satisfy Angular’s dependency on a live DOM.

When we consider testing requirements along with the desire to share code between Node and client-side Javascript, it becomes critically important to decouple our core functionality from the framework and environment it runs within. Although some projects can benefit from Browserify and Webpack, it is equally common for developers to fight against the build step which happens before running everything in the browser.

I have spent a fair amount of time off and on trying to find the best solution for each of these problems, which would solve all of them together. Ultimately, the solution came to me while working with Scala. In Scala, it is possible to define a class and an associated object. The object exposes functions as static methods on a namespace, while the class acts as an instantiable object which can be used in Classical OO applications.

A Basic Object

This inspired my thinking and I started looking at ways I could drop this same philosophy into Javascript. Ultimately, I landed on the concept of static functions on an object. In order to get some perspective on where this train of thought will take us, let’s take a look at a simple controller object like we might create in Angular.

This controller is actually pretty typical. There is a little bit of functionality which goes through and modifies the controller state. In order to properly test this behavior, we have to modify the controller state, then run each method and test that the mutation was correct. In a world where good functional practices are possible, this seems unnecessarily fiddly.

Moving to Static

If we rewrite this controller just a little bit, we can start separating behaviors and decouple the computational bits from the state mutation. This means the bulk of the work can be bundled up inside a pure function which is easy to test and think about. Once that is complete, the mutation behavior becomes trivial to test and reason about because it is merely setting a variable.

This change is important because we are actually modifying the base object which introduces functions which are not part of the instantiable object. Due to this, we can actually start moving the functionality out of the primary object scope altogether and, instead, only reveal the parts of our code which we really want to expose for use.

Full Extraction and Namespacing

Once we have extracted the base functionality, we can actually move all of our logic into a factory function. This will allow us to close over utility functions and reveal just the resulting composite functions which can be attached to our object just in time.

We can actually call our factory function within our tests to ensure the logic is correct, meanwhile, nothing is exposed to the outside world accidentally. This means we can attach these functions to the controller, if desired, just before we use them in our prototypal functions.

By attaching the functions as static methods, we give them a unique namespace, perform safe data hiding and ensure that our controller functions can refer to them without needing to be bound to a local context. This actually frees us quite a bit since much of the complexity related to Classical OO in Javascript is related to context switching depending on whether a function is called within the object scope or not.

I created a small utility to perform a no-frills merge of properties onto an object. This is only for illustration and would probably be best done with a reliable library like lodash or JFP. Let’s take a look at attaching our functions to our object for namespacing purposes.

We can see here the attachment of our functions is exclusively for the purpose of namespacing, much the same way we might see this in Scala or other functional language. Now that our functions are separated and declared within a factory function, we can actually work toward our second goal.

Externalizing Our Code

By separating our functionality, we can actually lift the entire factory function into a conditionally exported node module. On top of that, we get extra security because our factory function closes over our functions, making them completely inaccessible to tampering. This means, once our app is loaded in a browser, we get the same kind of separation from the world we normally see from an IIFE.

Moreover, because our code can be conditionally exported, we can require our behaviors directly and test them outside of the browser context. This means our tests will run faster and we don’t need to rely on as many, potentially flaky, integration tests. Here’s our final behavior code.

Summary

In the face of a new world for Javascript, it is important to capture every advantage we can in order to make our code clean, efficient and stable. By splitting our behaviors out of the strict confines of a framework structure and pulling them into a file for easy testing, we simplify the testing story and make it easier to share behavior between the browser and the server.

We can use simple patterns to build well defined, pure functions which give us a clear way to write and share code, while keeping it safe from attackers and stable for our users. The next time you find yourself working on a full-stack Javascript application, how are you going to split your app?

Comments Off on Static Methods on Javascript Objects

The Shodan Programmer (Reprise)

Quite some time ago, Michael O. Church wrote a blog post about the Shodan Programmer (beginning degree programmer, or journey beginning programmer). In this post he detailed a gradient system for identifying programmers with regard to skill, experience and knowledge. Two or three weeks ago, I discovered his post was either removed or his site had been deleted. I’m not entirely sure what led to his Shodan post going MIA, but it was an important idea in the greater discussion of progressing skill and ability.

The last remaining reference to his Dan idea is on a Quora post about the top 1% of programmers. In this post, the person posing the question was trying to find out how some of the greatest developers think and work in order to identify common habits of skilled and high-performing programmers.

With all of this in mind, I decided it is important to provide a new voice to the discussion about the Shodan Programmer. I believe that Church’s metaphor for describing programmer skill and ability holds up quite well against scrutiny. Ultimately, the idea is, programmers come in three broad-scope forms and the line is blurred when digging in and identifying when someone has moved from one part of the scale to another.

Where I currently work, we have three conceptual roles in which a developer falls: learner, contributor and mentor. Although this is, effectively, more closely related to the concept of apprentice, journeyman and master, it does line up, in part, with the greater idea Church presents in his Shodan Programmer post.

The Dan scale goes from 0.0 to 3.0 and, it could be said, this scale is logarithmic. The closer you get to the highest point, the harder it is to actually move the needle and the closer to 0 you are, the more likely you are to see large amounts of measurable improvement. This means it becomes increasingly more difficult to identify the gradation between two programmers with high proficiency.

Let’s have a glance at the three levels of the Dan.

Level 1 programmers, or Adders, are programmers who typically perform the bulk of the programming work in a software shop, solving common problems and interacting with systems. These programmers, given enough time, could eventually solve most problems which are necessary

Level 2 programmers, or Multipliers, are programmers who are capable, not only, of solving a problem, but are versed in higher-level ideas like architecture or library development and maintenance. Multipliers provide means to solve more general problems in order to reduce the amount of time spent solving the same problem over and over.

Level 3 programmers, or Global Multipliers, are programmers who tend to think beyond the scope of the immediate problem and look to solve large-scale problems. Although level 3 programmers can perform the tasks of level 1 and 2 programmers, they tend to take research positions and work on conceptual or innovative new technologies which proliferate through the entire community over time.

Level 1 Programmers

Level 1 programmers are what people would typically think of as entry- and mid-level programmers. These people are more focused on expanding their knowledge either through a learning program or day to day development projects which push their boundaries. Even programmers who have barely written their first Hello World program fall into Level 1, though they are usually not ready for production development for some time yet.

Church writes that a level 1 programmer is typically found on the scale between 0.0 and 1.4. If we were to consider the least experienced developer being hired as a junior or associate developer, we would likely be looking at developers who are at ~0.8 on the scale. Any programmer falling above 1.4 is starting to move into the realm of a Level 2 programmer.

We can see, of course, that this scale leaves a rather wide division between Level 1 and Level 2 since Level 2 actually begins well before a programmer actually reaches the 2.0 mark. It’s highly likely that someone who is working at a 1.2 level is probably starting to move into a mid-level programmer position and they are able to start looking at larger, more complex problems, though they are unlikely to be prepared to do architectural analysis

Church states that many programmers don’t progress beyond 1.2 because they stop actively investing in their own knowledge and education. It is common for someone to become comfortable with the technology stack and problem space they know and settle in.

Level 2

As you might imagine, a programmer who is at 1.5 is lumped into a Level 2 programmer. This does not mean that everyone who has reached level 1.5 is prepared to take on all tasks a Level 2.0 programmer would be able to accomplish, but they are starting to learn methods and techniques for tackling more challenging problems.

Level 2 programmers fall between 1.5 and 2.4 on the scale and perform a variety of tasks which might be considered too difficult, or too obscure for a Level 1 programmer. This does not imply any sort of superiority, however. More often reaching Level 2 is a product of independent learning, and industry experience. Level 2 programmers, typically, tap into knowledge which comes exclusively through time.

Church states that Level 2+ programmers can be identified through a variety of outlets such as library development or maintenance, speaking at conferences and mentorship. Due to the nature of their output, Level 2 programmers tend to multiply the efforts of a team rather than simply adding to it. This is where we can really see the difference between the Level 1 and Level 2 programmers.

Simply stated, by bringing Level 1 programmers onto a team the team is likely to benefit in an additive way. It is not uncommon to have a development team made up, exclusively, of Level 1 programmers, who produce working software. Typically, by introducing Level 2 programmers, the code quality will increase and the overall team will learn new skills and become a more effective team. This kind of improvement is greater than an additive effect, giving Level 2 programmers the Multiplier name.

The important aspect of a Multiplier is they provide large scale benefit to a company and are often as influential to an organization as a manager or executive. High-performing Multipliers not only raise the skill and ability of the people around them, but they steer projects clear of known pitfalls or dangers and empower the programmers they work with to take the software they touch to greater vistas.

Level 3

Church calls Level 3 programmers Global Multipliers, but it might be easier to envision them as theorists and researchers. These programmers are at 2.5 and above in the Dan gradient and it is highly unlikely anyone will actually reach 3.0, given the logarithmic nature of the scale.

Typically, Level 3 programmers work on bleeding edge projects and provide the technical and theoretical vision for the result. Level 3 developers are often found working in the R&D departments of large companies like Google, Microsoft or Apple or as high-paid, uniquely skilled contractors and trainers.

Level 3 programmers often have a deep understanding of more than just software development. They typically understand the deep underpinnings of computer science and mathematics. An academic equivalent would be a post-doctorate computer scientist leading research on a funded long-term project.

As with the gap between Level 1 and Level 2 programmers, a Level 3 programmer grows to their position through constant research, development and experience. Both Level 2 and Level 3 programmers have learned through a long process of failure and success. There is no simple path to reaching Level 3 and many programmers may never reach Level 3 simply because they lack the desire to put forth the tremendous amount of effort needed to increase their place on the scale by one or two tenths of a point.

Level Analysis

The way Church originally designed this scale, the intent was to identify appropriate skill level for people working in the industry and understand how people might attack a particular problem. Anyone who is at the whole number increments, e.g. 1.0 or 2.0, it is likely they would be able to solve 95% of the problems which could be identified at that skill level.

In other words, someone who is identified at a level of 2.0 would be able to successfully work on and solve 95% of Level 2 type problems. In much the same way, they are likely only going to be able to solve about 5% of Level 3 problems. This works the same way for someone at a level of 1.0, who would be able to solve 95% of Level 1 problems, but only 5% of Level 2 problems.

This means that for each point closer to the next level, a programmer would be able to solve a greater number of problems which would be distinct for that level. This kind of ability growth leads directly to the logarithmic nature of the graph.

Where this level designation comes in handy in day to day work is understanding the level of difficulty for a specific problem. If something is a straightforward coding problem which can be solved through a brute force approach, the problem is likely a level ~1.0 problem. On the other hand, if the problem is largely architectural or generic in nature it is probably more of a level ~2.0 problem.

By understanding where a developer currently falls on the scale will provide insight into the likelihood they will succeed at solving a problem on their own. In other words, if a developer is performing at level ~1.2, they will probably find a problem at level ~2.1 frustrating or inscrutable. On the other hand, they will also, likely, find a level ~0.3 problem trivial or boring.

This gives us a heuristic for maintaining developer engagement. Church claims that developers seeking a challenge perform best at about 65-75% above their skill level. This means we could expect a developer to exhibit moderate growth with a healthy mixture of problems which they consider “simple” for confidence, or 50% below their level, problems at +/-10% of their level and problems which are up to
50% above their level.

What it Means

Ultimately, this scale is not an indictment of anyone’s skill or ability regardless of where they are in their career. Regardless of whether you are just starting out, or you are a multi-decade veteran of the software industry, your place in the Dan is uniquely your own. Some people enjoy the act of writing code and will happily continue forward on that path, while others have ambitions of experience beyond where they are today. The choice is personal and it’s not one I would be comfortable guiding in any way.

Ideally, Church’s Dan should provide insight into the road a programmer could walk to achieve their desires and set a course for their career. Level 1.0 or 1.1 could realistically be reached in a couple of years and, perhaps, a year or so for a particularly dedicated developer. Church states that moving up the scale at 0.1 points per year after the first level is likely an aggressive schedule for many programmers. This means reaching level 2.0 will likely take a dedicated programmer 10 or 11 years on average, but might be achieved in about 8 for someone who is especially active in their research and experience.

I would suggest that the closer a programmer gets to 2.0, the slower the progress is going to feel simply because it takes more effort to cover the ground necessary for each tenth of a point. This is especially true since computer science is a field which is continually expanding and knowledge of topics continues to deepen year over year.

After reaching level 2.0, it could, realistically, take a lifetime to reach 2.5 or above. This is completely dependent upon the programmer and what their desires are. This does not necessarily mean reaching for the pinnacle is not a worthy goal outright. Instead what this means is each person will have to decide on their own whether they want to continue to climb, and what it will mean for their career.

In the end, this scale is simply a means for every person to understand where they currently are in their career, and provide a way to assess problems which will crop up while working on a particular project. In much the same way, revisiting this idea and the scale that comes with it has helped me to understand how to, both, pick appropriate level problems for people I work with as well as understand problems I have yet to face for myself.

In the end, I hope this has helped others to get a taste of the scale Church presented and, perhaps, draw a clearer line from where they are now to where they want to be. Everyone walks the path, the question is where does the journey ultimately lead?

Comments Off on The Shodan Programmer (Reprise)
Similar posts in General Blogging

Intent: Why Types Are Important

A common complaint from both the Javascript religious and the newcomers alike is Javascript is tremendously difficult to debug when things go sideways. When a null or undefined reference is passed, the stack trace can be illuminating or it can be completely obscure. Couple this with the growing popularity to use anonymous functions assigned to variables in lieu of named functions and you have a recipe for tremendous difficulty.

In modern compiled languages like C# and Java or F# and Scala, there is an enforced, static type system in place which ensures values which would cause a malfunction are disallowed from function calls. This does not guarantee program correctness, but it does help eliminate strange errors.

Of course, the really important thing which comes from static typing is less about the compile-time checking as it is the integration of typed thinking into the entire development process. While developers working in statically typed languages are thinking about the logic for their programs, they are also considering the data types they are using to arrive at their results.

Revealing Intent

When a programming language provides type annotations, it means the programmer can declare what they intend the program to do up front. Most statically typed languages typically have an editor (or two) which provide insight into what the annotations say elsewhere in the codebase, possibly quite far from where the programmer is currently looking.

What these editors are really providing is a look into the intent of the work which was done before. I refer to this kind of behavior as revealing intent. By revealing intent to the programmer, they can make choices which simplify the work of understanding other objects, functions and behaviors.

Javascript, for better or worse, does not allow for revealing intent other than variable names. This means that either each variable name must contain information about its type so people can opt to conform to the expected types or, alternatively, misbehave and intentionally break the function being called. I am a noted fan of dynamic languages and like my functions free-flowing, but sometimes I long for a good, strong contract.

Let’s pick a simple function written in Javascript and see what our baseline is.

Our function could add two numbers, but it could also be called upon to do other things the name does not specifically call out. AddJS could concatenate strings, coerce numbers to strings or act upon functions, objects and many other data types. Clearly this is not what we intended.

Microsoft designed a language called TypeScript which transpiles to Javascript and includes features from ES Next as well as a quasi-static type system. The type system in TypeScript is a step in the right direction when types are used, but there are still some problems. Let’s have a look at our function rewritten in TypeScript.

Our new add function declares it takes two numbers and returns a number. This is really handy when we are exposing a function as an API to the rest of the world because other programmers can then capture this type information as they program and use it to make their calls conform to the expectation declared in the type contract…

Unless they aren’t using Typescript in the rest of their application.

Typescript really only solves the problem if someone has bought into the entire ecosystem and uses modules which exclusively have TypeScript annotations attached or a TypeScript Definition file. Atop all of this anyone who wants to access these annotations will need to use an editor which supports that kind of behavior.

A Type By Any Other Name…

As functional programming continues to gain traction, patterns like function currying become more common in codebases. This means we now have functions which could return other functions (higher-order functions) which run 2 or more layers deep. This kind of behavior can be demonstrated by a small rewrite of our add function.

With this setup in vanilla Javascript, we have really challenged the next programmer to try and decode our intent if they aren’t familiar with a currying pattern. Due to the lack of types and intent declaration in Javascript, this function, for as simple as it is, tells us almost nothing about intent since even the input variables are separated across different functions and the result is the product of a closure.

If we were working in Scala we would get intent and behavior bundled in, possibly, too terse a form. Nonetheless, the full intent of our behavior is described by the following line of code.

This function definition actually declares not only data types for the function, but how they interact. We could almost say add moves out of the range of function definition and into a type definition on its own. That is, however, a little more esoteric than we need to be.

Of course, moving back to TypeScript, we can see where data types, function definitions and intent start to fall apart. Although data types are declared and displayed, it is difficult to write a curried function in a way that is both clear and declarative of intent. Let’s have a look at our curriedAdd function in TypeScript.

That’s kind of like a punch to the eyeball, isn’t it?

Tying Intent and Implementation

At the end of the day, the challenge we keep coming up against is the fact that our intent is either declared, vaguely, in code and lost before execution, or it is not declared at all. Really, though, data types are not intent. This is one of the biggest problems we have.

Although programming deals in data and behavior, the problem we have introduced is we have become obsessed with the data types and we have forgotten that they are only meaningful within the context of behavior.

A couple of weeks ago, we looked at a way to add a little metadata to our function in order to communicate information to programmers who use our API in the future. I also introduced a small library called Signet, which helps to simplify the process of attaching metadata so we don’t have to litter our code with a bunch of Object.append calls.

By using the language we introduced in Typed Thinking, we can actually get a full declaration around our function and add meaning and context to our API in general. Let’s try applying our full type, declaring intent, to our vanilla JS implementation of curriedAdd.

This definition helps us to fully understand what curriedAdd will do. When we get back our final function, we can query the signature from anywhere in our code, including execution time, and get a full report back on what our function will do. Let’s take a look.

This is a simple riff on the previous post since we already knew this was possible. Where our simple type language becomes useful is when we start working with curriedAdd. Instead of getting back an untyped function, which gives us no more information than we ever had before, we have a fully parsed AST which comes along for the ride with our function. This means we will actually get all of our other types for free all the way through our entire execution path. Let’s have a look at what happens when we call curriedAdd with a single value and check the signature.

This means our initial type declaration actually allows us to understand the return types without any further declaration anywhere else!

Our enforced type declaration has given us a way to communicate our intent to anyone interacting with our code whether we are available to answer questions or not. This type assignment reveals intent and helps to make library APIs and code in other files easier to work with.

On top of the ability to clearly identify intent and keeping our APIs static and safe, we still get to keep the dynamic nature of Javascript and all of the convenience that comes with it anywhere we are using local functions. This blended static/dynamic coding allows us to quickly and easily iterate on implementation details within a module or namespace while keeping the actual interface well-defined for the external user!

Summary

Languages and the way they manage types can be a really divisive topic, but with the flexibility built into Javascript, we can actually manage types on a case by case basis and surgically insert requirements without having to tie our hands elsewhere in our code.

Although TypeScript is a popular solution for trying to get a handle on the declaration of intent throughout our codebase, it starts to fray at the edges with advanced techniques, making it unsuitable for the move toward a more functional style of programming.

In the end, enforcing a type on our API endpoints with a strong, lightweight library like Signet gives us the right blend of enforced static typing where we need it and a fully dynamic environment when we want it. This seems like the only sane direction to go when working in a language as rich and flexible as Javascript. Go declare your intent and make people awesome.

Comments Off on Intent: Why Types Are Important

Unit Testing Express Routing

If you are unit testing your code, and you should be, then it is likely you have encountered certain patterns which make testing more difficult. One of the patterns which pops up often is centered around Express.js routes. Although the router has a nice, simple API to code against, the actual testing of the route action code can be a little challenging if you aren’t used to using tools such as mocks, fakes and stubs.

Today we are going to explore using the Mockery library and an express router fake module to simplify the process of reaching into our modules and getting ahold of the route actions we provide to express for the sake of testing and ensuring program correctness.

The Libraries

The post today will make use of Mocha, Mockery and Express Route Fake. The first two you may have heard of, the last you likely have not. Let’s walk the list and get a handle on what each of these tools does for us at a high level.

Mocha

If you have done any TDD or unit testing in Javascript and especially in Node, you have likely already encountered Mocha. Mocha is a popular BDD tool for testing Javascript. We will have examples of what test code in Mocha looks like later.

Mockery

Mockery is a tool for manipulating packages and modules which are required within script files for Node. Although Mockery is quite useful for breaking tight coupling, it is not as well known as Mocha. Unit testing scripts which are tightly coupled through require statements is challenging since there is no clean way to inject a dependency into a dependency chain without a third party tool. Mockery is key to getting good tests around Express route actions as we will see.

Express Route Fake

Express Route Fake is a module I wrote to emulate behavior we use at Hunter to gain access to our route actions as we get tests written around our code. The core idea of Express Route Fake is to substitute the fake module in for Express in order to capture references to the actions which are assigned to different routes. We will explore this shortly.

Registering Replacements with Mockery

I am assuming you are already familiar with a testing framework, so I am not going to cover the basics of using Mocha. Instead we are going to start off looking at how to register a faked module with Mockery so we can break a dependency in Node.

Mockery actually manipulates the Node module cache and updates it with code of our choosing. This gives us the ability, at test time, to dig in and create a fake chunk of code which we control so we can ensure our tests actually send and receive the right output without doing dangerous things like interacting with a network connection or a database. We want the scope of our unit tests to be as tight as is reasonable so we can ensure the code under test actually performs the correct action every time.

This kind of guarantee around tests is called determinism. Deterministic tests are tests which, when provided a single input, always return the same output. Ideally any interactions which would break the determinism of our functionality should be stripped away and replaced with code which always does the same thing. This gives us guarantees and makes it easier to identify and test a variety of different cases. Let’s have a look at an example of breaking a dependency with Mockery and replacing the code with something else.

The beforeEach block sets up a fake MySQL module with a query method which immediately calls a passed callback. Mocking MySQL does two things for us. First it removes the asynchronous behavior which comes from interacting with a database, ensuring all of our tests run inside the event loop. The second thing this does for us is it allows us to provide a guarantee that the results passed back from our MySQL fake are always the same. This means we don’t have to set up and tear down an actual database instance. We can simply test the code we care about and assume the database library does what it is supposed to.

Important items to note about the code in the beforeEach and afterEach blocks: Mockery takes a certain amount of work to get working. The enable call in beforeEach starts Mockery working in memory and tells it not to post warning messages every time it does something. It is safe to assume, if you see the results you want, that Mockery is working. The code in afterEach returns the cache back to its original state, leaving everything clean for the following test.

Faking Router For Great Good

Now that we have looked a little bit at how Mockery works, we are ready to start digging into what we really care about. Let’s start testing our Express route actions. The first thing we should look at is a little bit of example Express routing code. Below is a simple route example which just receives a request and then responds with 200 and a little message. It’s not exciting code, but we can actually test it.

We can see a few things here which will be really important to get the tests right. First, Router is a factory function. This means anything that is going to stand in for express will have to implement this correctly. The next thing we know is, the router object which is returned has methods on it like ‘get.’ We will want our fake object to replicate this as well. Now is probably a good time to take a look at the source code for Express Route Fake.

Express Route Fake is a small module which packs a pretty massive punch. Everything is set up for us to quickly capture and test our route actions. The very first thing we have is a cache object which will store key/value pairs so we can request whichever function we want to test easily.

After the cache object we have a simple function which captures the route method, the route path and the route action. This function is the real workhorse of the entire module. Every route call will go through this one function and be stored in our cache. It is critical to understand that all of the methods, paths and actions will be captured and related so we can test them later.

Finally we have the Router factory fake, getRouteAction and reset functions. Reset is exactly what one might expect, it resets the cache to empty so the entire process can be repeated without starting with a dirty object. getRouteAction performs two critical activities. First, it verifies the route exists and throws an error if it doesn’t. Secondly, it passes back the route action so we can test the function outside of the express framework.

A side note on the getRouteAction error behavior; it is important and useful to get clear errors from our fake in this case. Over time my team has run into confusing situations because our implementation was home-grown and does not throw useful errors. This means we get an error stating “undefined is not a function” which does not really tell us what is wrong. By getting an error which informs you the route doesn’t exist, you can immediately verify whether the route is being created correctly and not need to troubleshoot your tests.

Putting the Setup Together

Now that we have the tools and have taken a look at them, let’s start constructing what our tests would look like. We know Mockery is going to substitute in our fake module and we also know that Express Route Fake will capture the actions. All we really need to do is a little setup to get things rolling.

In our setup we have a little bit of extra setup. Since Node and Express interact with the http module through request and response objects (typically called req and res respectively), we will need to create objects we can pass through and use as well. Considering the calls we are making on res, I just included the bare minimum functionality to actually test our route action: status, send and end.

Please note we are actually requiring the module under test AFTER we perform our Mockery setup. It’s really important to do this, otherwise Node will provide the actual Express module and our fake code won’t be used.

Now that we have our code set up and ready to go, let’s take a look at what our tests look like.

We can see that actually testing the actions, now, has become three simple lines of Javascript. What is happening in each of these tests is, our module is registering actions against routes, which are stored by our Express Route Fake module. Once the test starts, we simply ask for the function and execute it as if it were called by Express because of an HTTP request. We pass in our fake objects and capture the result of our action behavior. This allows us to see directly inside of our method and test the interesting parts, throwing away the stuff that would be, otherwise, obscured by frameworks, libraries and Node itself.

A second, important item to note is that we get extra guarantees around our route paths. If someone were to come along and change the path in our module, but not update the tests, or vice versa, we would get immediate feedback since getRouteAction would throw an error telling us the path does not exist. That’s a whole lot of security for a little bit of up-front work!

Summing Up

Today, wee looked at how to use just a couple of modules to insert a fake for Express and get better tests around our code. By using Mockery and Express Route Fake, you can capture route actions and get them under test. Moreover, you can do this while only writing code that is specific to the tests you are writing.

As you write more tests, it might become useful to create a factory for creating custom request and response objects which would simplify the test code even more. Of course, with all of this abstraction it does become more challenging to see what is happening under the covers. Ultimately, this kind of tradeoff can be useful in situations like this where repeated code is more of a liability than a help.

The next time you sit down to create new functionality and wire it into an Express route, consider starting off with Mockery and Express Route Fake. They will simplify the tests you need to write and limit the amount of code you have to change in order to get tests in place. Happy coding!

Comments Off on Unit Testing Express Routing

Typed Thinking in Javascript

Javascript is a dynamically typed language. I suspect this is not news to anyone reading this. The reason this is important, however, is I have heard people say Javascript is untyped. This statement is most definitely false. Javascript has and supports types, it simply does not actively expose this to the world at large.

Javascript is in good company when it comes to dynamically typed languages. Python and Ruby are also popular languages which are dynamically typed. Other venerable languages which are dynamically typed include Clojure, Elixir, Io and Racket. People coming from statically typed languages often say that Javascript’s dynamic typing is a hindrance to good programming. I disagree. Bad programming is a hindrance to good programming. I feel programmers coming from the languages listed above would probably agree.

What’s the Difference?

Several popular languages today, including C#, Java and C++, are statically typed. This means the programmer declares the values they plan on using to accomplish a task when they define a method. There are distinct benefits to this kind of programming, specifically, the compiler can quickly determine whether a method call is valid. This kind of validation is useful and can prove a good tool for programmers, no doubt.

As you can see above, everything is explicitly annotated with a type definition. This kind of annotation is effectively a note to anyone who reads this code, including the compiler, et al, that this function behaves this way. Unfortunately, this convenience comes with a price. Suppose you wanted an add function for any sort of number including mixed arguments…

Modern improvements on type values has helped improve this problem (don’t shoot me, Java people), but it becomes obvious rather quickly that having restricted type flexibility means there is a lot more work which must be done to accomplish a seemingly simple task. We have to make a trade to get this compile-time help from the language.

Dynamic typing, on the other hand, does not have this restriction. In Javascript (or Python, Clojure, etc.) no type annotation is needed. This means the language will perform what is called type inference to do the right thing. Languages like Python or Clojure are less forgiving if types don’t line up correctly. If, for instance, you attempted to add a number and an array in either of these languages, an error would occur and everything would go downhill from there.

Javascript works a little harder to do the right thing; perhaps a little too hard. In a strange twist of fate I, once, attempted to demonstrate that Javascript would throw an error when trying to add a string and a function. Instead I got a string containing the original string, and the source code for the function. Suffice to say, this is not what I expected.

Nevertheless, this kind of type management is both the weakness and the strength of a dynamically typed language. Rather than having to spend time really thinking about strings, ints, doubles, bools and so on, you can spend more time thinking about the way your program works…

Until it doesn’t.

Correctness and Types in a Dynamic World

One of the most important things to consider in Javascript is intent. Although the kinds of strange things can be accomplished by applying common actions to unexpected values can be entertaining, it is not particularly helpful when attempting to write a correct program.

Correctness in programming is when a program performs the expected action and, within the domain of acceptable values, returns the correct output. In other words, an adder would be incorrect if it always returned 9, regardless of the input; an adder which always returned a valid sum would be considered correct.

By considering correctness, we must consider input and output types. Let’s keep using our add function because it’s easy to understand. Above, when we discussed types annotations, we looked at an add function in Java. We said that the input values a and b were both integers and the output is an integer. This forces the idea of correctness upon our function which, actually, could be defined as correct in a broader sense. What if, instead of declaring all of the different types and overloading the function again and again, we made up a new type. Let’s call this type Addable. Suppose we had an addable type in Java and could rewrite our function accordingly:

We can actually define a notation which will help us to understand the correct input/output values of our function. We can say add has a function signature which looks like this: Addable, Addable => Addable. In other words, our function takes two Addable values and returns a new, Addable, value. All of this is true and we could test this function via various methods to prove the specific addition behavior is correct.

This new Addable type is effectively what we get in Javascript with the type “number.” We know that any number can be added to any number, so whether one number is an integer and another is a floating point value, we know they can still be added together. This means we can actually go so far as to eliminate the type annotations altogether and simply write our function as follows:

Of course, the problem we face here is there is no annotation to tell the next programmer what types a and b should be. Moreover, Javascript is quite forgiving and will allow a programmer to pass anything in which might be usable with a “+” operator. There are solutions to each of these, though we will only look at solutions for telling the next programmer what we intended.

Ad Hoc Properties to the Rescue

Under the hood, Javascript shares some really interesting characteristics with Smalltalk. Specifically, everything in Javascript, when managed within the runtime, is an object. This means we can do all kinds of neat things with functions, like assign properties.

What this means is we can actually do something real about making our programming intentions more clear. What if we took our add function and assigned an ad hoc property to the Function object instance called “signature?” By creating a property which declared what the function should do we get two benefits. First, anyone reading the source can immediately see what we meant to do and, second, we can actually create an artifact in our code which can be called upon elsewhere to get immediate feedback on what our behavior should look like. Here’s an example:

Now, looking at our code we can see what add does. It takes two numbers and returns a number. We can use this same property to our advantage elsewhere in our code. If we were planning to use add and wanted to see what the expected input and output are, we can simply output the signature. Here’s how we could do that:

Now we know! Better yet, if add was somewhere deep in a third-party library, we wouldn’t have to dig through third-party code to understand what the contract for add might be.

Thinking Types

The really important idea here is, even if they aren’t expressed in code, types live within everything we do in Javascript. As we develop software, it becomes really easy to simply not think about what a function signature looks like and call it with whatever we have, hoping it does what we expect.

Programming this way is dangerous and can lead to bugs which are hard to triage and fix. Instead of using the spray and pray approach, it is helpful to understand, more fully, what you intend to do and work with the types which are intended in a functions activity.

What this means to the dynamic programmer is, we have to be more vigilant, more cautious and more prepared while solving a problem than someone working with a statically typed, explicitly annotated language.

There are two ideas we must always keep in mind when programming, the goal of a correct program and what we must do to get there. The first idea is related to the company goal related to whatever problem we are actually trying to solve. The second idea encompasses types and actions almost exclusively.

Summary

Regardless of the typing mechanism for the chosen language with which we solve a problem, types are part of the solution. Javascript does not express the value and function types explicitly in the source code, but the types we use are equally important to anything used in a statically typed language.

We can solve the problem of expressing our function signature through using comments or adding a property which can be read and understood by other programmers. This will help alleviate the challenges which arise from misunderstanding source code.

Finally, as we work we must always be aware of the types we are interacting with and how they lead to the solution for whichever problem we are solving at the time. Instead of throwing things at the wall and seeing what sticks, let’s work carefully and with intent to write correct, valid programs.

P.S. If you don’t want to remember all of the metadata stuff you have to do, check out signet.

Objects Are Still Shared State

Dear programmers coming from Classical Object Oriented programming, please stop thinking that encapsulation of variables eliminates the “globalness” of your variable. It’s a hard truth, but you had to hear it from someone; you have a problem. Consider this an intervention.

I had a conversation a couple months ago where I looked at some code a senior developer had written and asked, “why are you using a global variable?” The response I got was “it’s the exposing module pattern, so it’s local and encapsulated. It’s not global.” The variable was a cache object exposed outside of the module; and it was global anyway.

When I say global, it is not about whether the entire program, or the entire world, can access your value, it’s about how your variable gets managed and modified. Really, the problematic aspect of a global variable comes from the fact that global variables, in many popular languages, represent shared, mutable state.

Consider a world where every variable is actually immutable, i.e. once you create a variable, you can’t change the value. In this particular case, a global variable is really nothing more than a globally readable value. You can’t write to it, so you can’t impact the rest of the running program. Is that global variable actually a problem? Decidedly less so, that’s for sure.

Mutating Object State

Let’s take a look at a very simple, though rather common, example of the way variables are often managed inside objects.

There are two things wrong with this if value is actually important to the internal state of the object. First, since Javascript does not support private variables (explicitly, but we’ll come back to that), then this suffers from the Indecent Exposure code smell. Essentially, anyone in the world can directly access and modify the internal state of this object. That’s bad news.

The second issue with this object is the getter actually modifies the internal value of our object and returns a representation of the previous object state. Effectively, our getter is modifying the internal state of the object and lying to us about it.

Before you proclaim “I never do that! How very dare you,” keep in mind that this pattern shows up all the time. Popular frameworks like Angular and Ember actually encourage this kind of thing through the controller pattern. This is a sneaky trap that is hard to avoid.

Although we can’t quickly resolve the code smell, let’s take a look at a remedy for the lie that is our “get” method name.

Now we understand and declare what the method does. For some people this is enough and we need to go no further. I, on the other hand, feel this is still rather suspect and would prefer to see a cleaner, more elegant construction.

Separate The Activity

The issue I draw with our updated object is, we have one method which does all the things. This is a really bad idea since it really doesn’t protect the programmer from a micro-god function. (Hey, You can have micro-frameworks and micro-services.) Effectively we have fixed the naming problem, but we haven’t actually resolved the smelly code which lives within our method.

Typically I prefer a single function which will return the current state of affairs and other function, if you MUST, which modifies the internal state. This kind of separation of concerns actually helps to keep object state sane and useful. If not for the exposed internal value of the object, we would be on our way to saner code.

We can see this code actually separates the functionality and has the lovely side effect of making the code more readable. If I were working in a project using an MVC paradigm, I would call this good and move on. We have separated the behaviors and tried to keep everything clean, tidy and meaningful. Our view would be able to access the values it needs and we keep our state management safe from accidental update.

Turn Up The Encapsulation

From here we can start looking at working on our fine detail. Up to now, we have accepted that our internal values are exposed and available for the world to manipulate, AKA Indecent Exposure. It’s time to fix that little bit of nastiness and make our object water- and tamper-proof.

The only way to actually protect a variable from external access in Javascript is through closures. Since functions are objects and objects are built atop function constructors, we can perform a little scope management surgery and make our object really safe and secure. Let’s take a look and see what we can do to lock things down.

This code does a little fiddling around with scope by partially applying the object’s internal state to our get and set functions. This protects our variable from being accessed by the outside world, but allows our get and update methods to access our value freely. When your data must be locked away, this will get you there.

Our Code Goes to 11

In order to finish up this journey, it seemed only right to create a completely pure, immutable object just to see where it would lead us. If we were to really go all the way, we would need to do a little more work to ensure everything still worked as we would expect.

We know the variable “value” maintains a count for some reason, so it will be important to ensure value is always an integer. We also want to make sure the get method always gives the current count. Finally, update should do just that: update the count value. What does it mean to make an update if everything is immutable? Let’s have a look and find out.

This is just chock full pure functions and added behavior. With all of that added behavior, we get something magical. Instead of having an object which is mutable and, ultimately, somewhat unpredictable and hard to test, we end up with an object which has the following properties:

  • Immutable
  • Contains pure methods
  • Has a single, pure, static method
  • Is compositionally built
  • Updates through new object construction

This whole object construction could lead us down many discussions which would get into types, values, mutability, function composition and more. For now, it will suffice to say, this kind of development creates the ideal situation for developing safely and really turns our code up to 11.

The numbers all go to 11.

Summing Up

Although we got a little spacey at the end, the important thing to take away from this whole thing is, any time an object is built and modifies its own state through method calls, the methods are actually relying on shared, mutable state.

Shared mutable state in an object really is just a micro-global and should be viewed as such. This means, any value which can be accessed and modified should be considered unsafe and untrustworthy. Untrustworthy data should never be viewed as the source of truth.

From here forward, if you start to add a variable to an object or module, ask yourself, does this really need to be global, or can I localize it? Perhaps you will find a better way to keep your code clean and easy to reason about.

Comments Off on Objects Are Still Shared State