Streamlining Development Through Functional User Stories

Sam Bobo
8 min readMay 17, 2019

--

I recall sitting in my introduction to computer science class at university and watching my professor standing at the chalkboard (with chalk all over his pants, typical of the CS department) teaching a lecture on writing functions in Java. During the lecture, we learned about defining a function by its return type (int, double, string, void, etc), modifiers (public, private), method name, parameters, and body. After mastering beginner-level functions, we proceeded to learn about functions as one practice in Functional Decomposition, where we are:

“tak[ing] a large-scale problem statement and decompose[ing] it into high-level functions,”

— Clean Architecture, Robert Martin

which increases maintainability, readability, and refactorability of the code being written.

Fast-forward to 2019: Our team was working with a large financial company and tasked with engineering a financial calculator. Combining my mathematics degree and technological background, I hypothesized that dividing the engine into separate functions, according to the functional programming paradigm, would serve as the optimal method of (a) writing technical user stories and (b) conveying the product requirements to the development team. After testing my hypothesis and gaining feedback from the engineers, I discovered that writing functional user stories can be a factor leading to the team’s ultimate success due to their methodical pattern, small implementation size, and easy learning for new Product Managers.

Through this blog, you will learn about about functional user stories and the benefits of their application.

ANATOMY OF USER STORIES IN FUNCTIONAL DECOMPOSITION

Let’s start with an example: writing a function for computing the dot product of two arrays. In mathematics, the dot product is defined as:

Summarizing, the dot product is a function that multiplies elements from array A with those from array B, element-wise, and adds the results together to produce a single (scalar) number. Writing this in javascript:

For simplicity and brevity in illustrating this concept, the code for throwing an error if the two arrays are not equal in length (equality in size is a requirement to perform this operation) was not written.

So, working backwards, how would a Product Manager write a user story for computing the dot product of two arrays? The user story is trivial and can follow the below pattern:

As the {program}, I should be able to compute {function} of/using {input parameters} so that {valuable use case}.

In the case of our dot notation function:

As the example program, I should be able to compute the dot notation of two arrays so that a data scientist can build more complex computational models.

Next comes the acceptance criteria, written in the form of a Gherkin statement. Since the story describes a function, it’s best to think about the parts required to build a function: inputs, computation, outputs. As a general pattern, the Gherkin statement for a function should look like:

GIVEN: {parameter 1} is provided to the {program} as an input from {source}

AND: {parameter 2} is provided to the {program} as an input from {source}

AND: {parameter N} is provided to the {program} as an input

WHEN: The {program} runs the {function} defined below

THEN: The {program} should return {return value or object}

{Function}

{Function definition}

Returning to our dot notation function:

GIVEN: Two arrays of length greater than zero are provided as an input

AND: Both arrays are equal in length

WHEN: The program applies the Calculate Dot Product function defined below

THEN: The program should return the dot product as a scalar number

Calculate Dot Product

dotProduct = SUM{i = 1 to n} (A[i] * B[i])

UNIT TESTING

For teams practicing Test Driven Development (TDD) or writing unit tests as a development practice, functional user stories have their benefits in simplifying the creation of unit tests through a repeatable pattern. Take, for example, a unit test for the dotProduct function used as an example above. Our test could look like:

This pattern looks familiar! The parameter variables arrayA and arrayB we define on lines 2 and 3 are the precondition to our function, the actual invocation of the dotProduct method on line 4 is our action, and the check on line 5 is our result, which correlates directly to the structure of our Gherkin statement. This test would serve as one of many as the engineering team ensures that edge cases and a variety of scenarios are tested for complete coverage. Abstracting this example out to a repeatable pattern, we get (written in pseudo code):

Now that we have reviewed the pattern, both a theoretical and practical example of the associated user stories, as well as a unit test case, let’s talk about the integration aspect.

INTEGRATION

If a program is broken down into a series of functions or sub-functions, how do the pieces come together? The answer is integration! Integration is the step where the constructed functions get strung together sequentially to form the end-to-end calculation and arrive at our desired value; this is achieved by passing the returned value from one function into the input of another. Check out the pseudo code below:

The user story follows the same repeatable pattern utilized on the smaller individual functions. However, this time, will act similarly to an epic-level story:

As the {program}, I should be able to compute {function} of/using {input parameters} so that {valuable use case}.

GIVEN: {parameter list} is provided to the program as an input

WHEN: The program runs the {end-to-end calculation} described below

THEN: The program should return {value(s)}

End-to-End Calculation

  1. Calculation1
  2. Calculation2
  3. CalculationN

In physics, the dot product operator is highly prevalent when performing vector mathematics. One such example is calculating Power, defined as the dot product of force and velocity. If we wanted to write a program to calculate Power using functional programming paradigms, our user story would look like:

As the prediction engine, I should be able to compute the power of a system provided its mass, time, and displacement so that I can optimize plant efficiencies.

GIVEN: A system’s mass is provided to the prediction engine as a direct input

AND: A systems motor displacement is provided to the prediction engine as input from the sensors

AND: The total elapsed time is provided to the prediction engine as input from the monitoring service

WHEN: The prediction engine computes the total Power emitted described in the process below

THEN: The prediction engine should return Total Power

Power Calculation

  1. Calculate Velocity
  2. Calculate Acceleration
  3. Calculate Force
  4. Calculate Power

Power = dotProd(force, velocity)

Since each function was built independently and defined prior outputs as input parameters, the remaining work simply involves actually passing in these values in order.

BEST PRACTICES

Below are some best practices to consider when writing functional user stories:

Reference other functions in “Technical Notes”: User stories, in theory, should be written as independent requirements with the ability to be picked up from the engineering team at any point (with prioritization from the Product Manager). Since functions may rely on the outputs of other functions described in different user stories, make sure to reference the story in the “Technical Notes” so that the engineering team can have a quick and easy reference.

Note the use of outputs in the Gherkin Statement: Often, the outputs of your functions will be used in a multitude of scenarios. For example, the output could be used in a subsequent calculation or a value returned by the program. Make sure to note those in the Gherkin statement of your user story so that the engineers can plan accordingly.

Now that our program is complete, let’s explore the major benefit of functional user stories: simplifying implementation and complexity.

SIMPLIFIES IMPLEMENTATION AND COMPLEXITY

In the AgileXP development paradigm, there is an Iteration Planning Meeting (IPM) prior to each iteration’s start where all those involved discuss the complexity in implementation of prioritized user stories. A story’s complexity is represented in the form of “story points” assigned by engineers during the IPM, and can be defined differently based on the team. One method of defining the complexity represented in story points is by utilizing the Fibonacci sequence (1, 2, 3, 5, 7, …), a method that states that larger user stories increase drastically in complexity. Developers typically utilize a practice called “Planning Poker” to assign story points, whereby each member on the engineering team independently selects a point value, and then all reveal their predictions simultaneously. Divergent values are discussed by the engineering team and then converge on an agreed upon estimation for the story.

When applying functional user stories to my Product Management practice, I discovered that the technical stories I wrote almost always resulted in a 1-point complexity estimation (i.e.: could be completed in less than a day). Recall from above that our functional user stories provided a pattern to collaborate with the engineering team on the function name, parameters, calculation, and expected result returned that also aids them in writing code in the Functional Programming paradigm. With that information, implementation is extremely straightforward and the bulk of the effort required is building the unit tests to accompany the function being built (and those have a pattern too!). For our integration stories, given that those are larger in nature and oftentimes detect bugs in the code, the engineering team would likely point the story a 2.

CONCLUSION

Functional user stories proved to be a successful method of breaking down the overall program being built by the development team, but also served as a fantastic teaching method for training new Product Managers on writing technical user stories. During your next project, I encourage you to apply the functional user story pattern for yourself and comment below on the results you find.

Sam is passionate about empowering people to innovate, understand, and transform the world utilizing ground-breaking technology. Over the course of his career, he has consulted CEOs and CTOs from product design through implementation to revenue maximization. He seamlessly melds business acumen, technological know-how, and creative vision to identify, prioritize, and resolve his client’s most daunting problems to ensure their competitive edge in the marketplace. At TribalScale, Sam teaches Product Management to clients via one-to-one mentorship in the Transformation practice.

--

--

Sam Bobo

Sam is passionate about empowering people to innovate, understand, and transform the world utilizing ground-breaking technology.