Why the feedback-loop is crucial for product success

Posted Sep 29, 2019

All development and changes to a product comes associated with risk. The risk of building the wrong thing, the risk of building features that does not speak to the users, the risk of introducing bugs. The list goes on and on!

Even worse is that the risk increases over time. The longer the work, the bigger the risks becomes - Unless you have good and effective routines for continuous feedback. Without feedback-loops you will continuously build your product on assumptions that leads to new assumptions. This leads to an ever-increasing risk of failure.

By working strategically with feedback-loops you can decrease the risk of failure dramatically while at the same time increase product quality and user-satisfaction. This is why feedback-loops has become such a crucial part of product development in today’s popular agile methodologies and principles such as Scrum, Kanban and Lean.

If you have an iterative process around receiving and reviewing valuable, insightful feedback you will directly decrease the risk by validating or invalidating your assumptions.

Feedback-loop risk reduction

First, we need to understand which feedback-loops that comes to play during our work. A simple example could be the feedback you get when writing code in an editor. As soon as you stop typing, the editor will let you know if you misspelled a variable or function name. Another feedback-loop could also start from the point you have built a new version of your product until the time when users are able to try the new features out and give you opinions on how well its suites their needs.

Depending on what type of feedback you are searching for you can expect differences in its quality. Some feedback may be definite, other might be harder to analyze and understand. If we have good quality, we can expect a greater risk reduction than if the feedback is more uncertain. E.g. Have you successfully identified a representative segment of users to provide feedback? Are the tools you are using reliable and accurate? This is why you see an increased risk over time even though you get feedback in the illustrated chart. If the quality of the feedback is very good you don’t necessarily need to see that increase over time.

When you have a clear understanding of which feedback-loops that comes into play you can start to roughly list how long each feedback-loop cycle is. For example; misspelled variable names in code will give you feedback in a second. End-user feedback will have a longer feedback-loop cycle. Hopefully no less than every sprint. With feedback-loops and their cycle time clearly listed and visualized you will bring awareness of the loops and possibly their weaknesses.

Imagine what it would be like if you did not get immediate corrections of misspelled variable and function names! Most probably you would continue until compilation and by then it could possibly be a little bit harder and more cumbersome to understand and correct the issue which consumes valuable time. You will be surprised how often this holds true for other types of less trivial productive feedback-loops!

The longer the feedback-loop the bigger the risk. A good practice is to always strive to shorten the feedback-loop cycle to become as short as possible or as short as convenient for minimizing the risks associated with the change.

To spot weaknesses in an area of your product development it could be an eye-opener to also categorize your identified feedback-loops. Some of them might relate closer to engineering practices that will help you increase the quality of the product while other relates more to processes, progress, team building and well-being, insights in market demand etc.

Here are a few examples of some of the feedback loops that comes into play when developing a software product, and you can probably see room for improvement when looking at this chart.

Feedback-loops

What feedback-loops could you improve and shorten in your work? Would shorten those loops lead to a better product delivered by your organization? Hope you found this interesting and inspiring!

Potentially releasable product?

Posted Jan 16, 2019

What is a “potentially releasable product increment”, really? Last year I worked as Scrum Master in a team that delivered software for multiple target platforms. One of the products was a mobile application. The mobile application was target for multiple markets and regions and needed multi-lingual support. One of the features in the application was to switch between different languages inside of the application (the app runs on a device available to a range of people with possibly different primary native language).

Some changes had been introduced to the texts in the application. We needed to send parts of the texts to the translation agency for retranslation. Unfortunately, the Chinese translations were not returned before the end of the sprint and didn’t make it to the sprint release. As a consequence, the missing texts disappeared when Chinese language was selected in the application. We were aware of this and told all our stakeholders about it during the sprint review. One of the stakeholders then asked: “Is this really a potentially releasable product increment?”

At that point it got me thinking; Maybe it isn’t?

Maybe we can find the answer to this in the core of Scrum? Scrum is built on empirical process control. The core of empirical process control is transparency, inspection and adaption. If we actively work on these things it will enable us to gain knowledge from experience and to make decisions on what is already known.

One of the purposes of Scrum is to foster short feedback loops and one of the main benefits of having a potentially releasable product increment each sprint is to enable inspection and adaption. Without it we can’t get proper feedback from our stakeholders.

In the Scrum Guide we can read that:

At the end of a Sprint, the new Increment must be “Done,” which means it must be in useable condition and meet the Scrum Team’s definition of “Done”

and…

The increment must be in useable condition regardless of whether the Product Owner decides to release it.

The take away from this is that as long as the translated texts were not a part of the team’s Definition of Done the increment can be seen as potentially releasable. The increment enables inspection which will generate valuable feedback on the increment. The product owner may very well decide not to publicly release the increment, but what can possibly be better than fast feedback from people actually using and evaluating the product?

One way to meet the expectations of the stakeholders forward would be to alter the teams Definition of Done with a point stating that all texts should have a proper translation for all supported languages. This would result in an increment where no texts are changed before all translations are delivered from the translation agency.

Be aware of your enumerated types

Posted Oct 18, 2015

When you are working with Apples Foundation framework you have probably stumbled across NS_ENUM and NS_OPTIONS (since iOS 6 and OS X Mountain Lion). Both NS_ENUM and NS_OPTIONS are marcros that use the C enum under the hood, and if you have used C enums before you will probably understand these macros, kind of, right away.

So why do we need these macros? NS_ENUM and NS_OPTIONS makes it easy for developers to specify the underlying type and size of your enumeration. This is handy since we, developers for Apple plattforms, may need to compile our applications to run on both 32-bit and 64-bits processor architectures. So by defining the type of the enumeration to be NSInteger or NSUInteger, the compiler can decide what the most appropriate size depending processor architecture.

In this post I am going to take a little deeper look at NS_OPTIONS and give a solution to a misstake I often see in the community when using the macro.

NS_OPTIONS

If you are used to C enum, you may also be aware of that enum can be used as bitmasks. This is exactly the use case of NS_OPTIONS. The macro tells the compiler that the values can be combined with bitmask operators, | for bitwise or and & for bitwise and.

Here is an example from UIView.h in UIKit. This is the definition of UIViewAnimationOptions.

typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions) {
    UIViewAnimationOptionLayoutSubviews            = 1 <<  0,
    UIViewAnimationOptionAllowUserInteraction      = 1 <<  1,
    UIViewAnimationOptionBeginFromCurrentState     = 1 <<  2,
    UIViewAnimationOptionRepeat                    = 1 <<  3,
    UIViewAnimationOptionAutoreverse               = 1 <<  4,
    UIViewAnimationOptionOverrideInheritedDuration = 1 <<  5,
    UIViewAnimationOptionOverrideInheritedCurve    = 1 <<  6,
    UIViewAnimationOptionAllowAnimatedContent      = 1 <<  7,
    UIViewAnimationOptionShowHideTransitionViews   = 1 <<  8,
    UIViewAnimationOptionOverrideInheritedOptions  = 1 <<  9,
    
    UIViewAnimationOptionCurveEaseInOut            = 0 << 16,
    UIViewAnimationOptionCurveEaseIn               = 1 << 16,
    UIViewAnimationOptionCurveEaseOut              = 2 << 16,
    UIViewAnimationOptionCurveLinear               = 3 << 16,
    
    UIViewAnimationOptionTransitionNone            = 0 << 20,
    UIViewAnimationOptionTransitionFlipFromLeft    = 1 << 20,
    UIViewAnimationOptionTransitionFlipFromRight   = 2 << 20,
    UIViewAnimationOptionTransitionCurlUp          = 3 << 20,
    UIViewAnimationOptionTransitionCurlDown        = 4 << 20,
    UIViewAnimationOptionTransitionCrossDissolve   = 5 << 20,
    UIViewAnimationOptionTransitionFlipFromTop     = 6 << 20,
    UIViewAnimationOptionTransitionFlipFromBottom  = 7 << 20,
} NS_ENUM_AVAILABLE_IOS(4_0);

In this definition the shift operator is used to define the values of the constants in the enumeration. For example 1 « 4. What this does is that it takes the bits for decimal 1, and scoot them to the left by four steps. 0 0 0 0 1 will then become 1 0 0 0 0. The value for UIViewAnimationOptionAutoreverse will therefore resolve to decimal 16.

By this definition, all options from UIViewAnimationOptionLayoutSubviews to UIViewAnimationOptionOverrideInheritedOptions can be combined together in any combination. Since these options are using decimal 1 with different shifting. Options can combined by using bitwise or |.

UIViewAnimationOptions options = UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse;
// options = 1 0 0 0 | 1 0 0 0 0 = 1 1 0 0 0 = 24

We can also check if an option is set in the bitmask by using the bitwise and &.

UIViewAnimationOptions options = UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse;
BOOL const shouldRepeat = (options & UIViewAnimationOptionRepeat);
// 1 1 0 0 0 & 1 0 0 0 = 0 1 0 0 0 = 8
// shouldRepeat = YES

The problem

The previous example of checking a bitmask might be a sufficient solution in cases where every option is represented by one bit. If the bitmask should change, this solution may become broken depending on the change!

This is even more obvious when we look at both the options for the animation curve and the animation transition. As you can see in the definition of these options, the shifting is different from the first options. Instead of shifting the value 1 by different steps, different values are shifted with the same amount of steps. These options will therefore end up using the same bits in the resulting bitmask. When this is the case, all bits in the mask that is dedicated to this option needs to be considered when determining if an option is present in a bitmask or not.

Lets look at an example where the check for an option done in the previous example is an insufficient solution.

UIViewAnimationOptions options = UIViewAnimationOptionCurveLinear;
// shifting value 3 (binary 11) 16 steps
// options = 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 = 196608

UIViewAnimationOptions easeInOption = UIViewAnimationOptionCurveEaseIn;
// shifting value 1 (binary 1) 16 steps
// options = 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 = 65536

BOOL const curveIsEaseIn = (options & easeInOption);
// curveIsEaseIn = 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 & 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 = 65536
// curveIsEaseIn = YES

As you can see, when checking options against a bitmask like this can lead to an incorrect result. In my example the check says that the options contains ease in, which is not what I defined… It’s enough for the options to have one bit in common in order for the result to turn into something other than 0 (false). So what would be a more sufficient way of checking if the animation curve is of type “ease in”?

A sufficient check requires that you know how the enumerated type is defined. So whenever I want to define these kinds of options I also create a corresponding function to check for a value in an option mask. This is great since if the enumerated type needs to be changed later on, there is just one place to change the values, instead of everywhere in the app. It also makes the check a lot more readable.

Here is an example of a function that I would have added to check for an animation curve if I had options simillar to the UIViewAnimationOptions.

static inline BOOL UIViewAnimationOptionsHasAnimationCurve(UIViewAnimationOptions options, UIViewAnimationOptions curve) {
    // Shift the options back 16 steps.
    // Then mask out other bits that are not used for the curve options.
    options = (options >> 16) & 3;
    // The same principle on the curve passed to the function
    curve = (curve >> 16) & 3;
    // Options and curve should now resolve to the same value if the curve is in the options mask
    return options == curve;
}

UIViewAnimationOptions options = UIViewAnimationOptionCurveLinear;
BOOL hasEaseInAnimationCurve = UIViewAnimationOptionsHasAnimationCurve(options, UIViewAnimationOptionCurveEaseIn);
// hasEaseInAnimationCurve = NO

The decimal value 3 is used in the example above since it’s binary representation is 11. Meaning that the two bits used for the animation curve will be kept, but other bits will be and-ed out by zeros.

As a practice for you, I leave the function for checking for a specific transition out. I hope you found this article interesting and that you gained some new insights. Happy coding!

Map, Filter, Flatmap and Reduce in Swift

Posted Aug 15, 2015

Last year at WWDC, Apple released their new programming language, Swift. The development of the language has progressed real quick since the release, and by now Swift 2 is in Beta and available to developers through Apples Developer Portal. The release has been a great success and Swift has become one of the most beloved programming languages out there! As a twist, the language is also expected to be released as open-source this fall.

While the language makes it easier for developers to write code with greater expressiveness, readability, security and performance - It also marks a bigger interest in alternative programming paradigms. While Apples old programming language, Objective-C, is a C-based, object-oriented programming language - Swift could be categorized as a multi-paradigm language. The language is still strongly object-oriented, but Apple has also added support to use Swift in a more functional fashion. This is done by adapting some of the most well-known functional concepts and encurage the use of immutable objects.

Functional approaches has some great benefits over the object-oriented once; especially when it comes to concurrency and thread-safety. They also tends to be simpler to put under test since all functions are fully centered around input and output data of the function, and does not depend on global states or cause any side-effects.

I want to start by making a run-through on some of the higher-order functions, with their origins in functional programming languages, that has been added to Swift. These are; Map, Filter, Flatmap and Reduce. In Swift 2.0 these methods has been moved from a global scope into the CollectionType protocol.

Map

func map<T>(@noescape _ transform: (Self.Generator.Element) -> T) -> [T]

This is the function definition of the map function in Swift. At a first glimpse this might look a bit scary, but lets break it down! func map declares the function map. The <T> part tells Swift that the type T is a placeholder for a class. This is known as a generic declaration. Declarations like this will stop the compiler from trying to look up the type T later in the declaration.

@noescape is an attribute in Swift that are used to communicate to the user of the function that the argument will not outlive the lifetime of the call. If the function dispatches to a different thread, an argument may be captured so that it exist at a later time when its needed. The @noescape attribute is a sign that this will not happen for this function.

The _ means that the external parameter name is not needed when calling the function. transform is the name of the parameter.

The type of the parameter is declared as (Self.Generator.Element) -> T. This is a closure that takes an argument of type Self.Generator.Element and returns an instance of type T. I will not explore SequenceType, GeneratorType etc. any further in this post, but for sake of clarity you can look at the Self.Generator.Element type as the same type of object as the type contained in the collection.

And finally -> [T] declares the return type of map. An array of T’s.

What map does is that it takes the given closure and call that on every element in the collection. As we can understand by the function declaration, the result of the map function is an array of the same type as the return type of the closure. So the result will be a new array but with elements that are the result of calling the closure on the elements in the origin array. Note that Self.Generator.Type is the type of the argument to the closure, but T is the return type. This means that the new array don’t necessarily need to contain objects of the same type as the origin array.

Here is an example on how it can be used in Swift.

let devices = ["Phone", "Pad", "Mac"]
var prefixedDevices: [String] = devices.map {
    (let device) -> String in
    return "i" + device
}
// prefixedDevices = ["iPhone", "iPad", "iMac"]

// Or similar...
prefixedDevices = devices.map { "i" + $0 }
// prefixedDevices = ["iPhone", "iPad", "iMac"]

For illustrating purposes here is how to achieve the same thing in Objective-C.

NSArray *devices = @[@"Phone", @"Pad", @"Mac"];
NSMutableArray *transformedDevices = [NSMutableArray arrayWithCapacity:[devices count]];
for (NSString *device in devices) {
    NSString *transformedDevice = [@"i" stringByAppendingString:device];
    [transformedDevices addObject:transformedDevice];
}
NSArray *prefixedDevices = [transformedDevices copy];
// prefixedDevices = @["iPhone", "iPad", "iMac"]

Filter

public func filter(@noescape includeElement: (Self.Generator.Element) -> Bool) -> [Self.Generator.Element]

Filter is a bit different from map in its declaration. The type of the includeElement parameter is a closure that takes a Self.Generator.Element and returns a boolean value. The return type of filter is also an array of the same type as the argument to the closure; Self.Generator.Element. What this means is that the resulting array will be an array with objects of the same type as the origin array.

The filter function calls the closure on every element, and if the closure returns True, then the element will be included in the new array.

let devices: [String] = ["iPhone", "Samsung Galaxy", "iPad"]
var filteredDevices = devices.filter {
    (let device) -> Bool in
    return device[device.startIndex] == "i"
}
// filteredDevices = ["iPhone", "iPad"]

// Or similiar...
filteredDevices = devices.filter { $0[$0.startIndex] == "i" }
// filteredDevices = ["iPhone", "iPad"]

And again - Here is the same thing done in Objective-C.

NSArray *devices = @[ @"iPhone", @"Samsung Galaxy", @"iPad" ];
NSMutableArray *mutableFilteredDevices = [NSMutableArray arrayWithCapacity:[devices count]];
for (NSString *device in devices) {
    NSString *firstLetter = [device substringToIndex:1];
    if ([firstLetter isEqualToString:@"i"]) {
        [mutableFilteredDevices addObject:device];
    }
}
NSArray *filteredDevices = [mutableFilteredDevices copy];
// filteredDevices = @["iPhone", "iPad"]

Flatmap

public func flatMap<S : SequenceType>(@noescape transform: (Self.Generator.Element) -> S) -> [S.Generator.Element]

Now, flatMap can be a bit harder to wrap your head around at first. Lets have a short break down of the declaration.

A generic declaration <S : SequenceType> is used for referring a type that conforms to the SequenceType protocol. The argument for parameter transform should be a closure that takes an element in the collection which the flatMap function is called on, and return an object conforming to SequenceType. The return type of the flatMap function is then declared to be an array with objects of the same type as the closure argument.

FlatMap is handy to use when you are working with multi-dimensional arrays. Just like the map function the transform closure gets an element in the collection as argument, but the flatMap closure is expected to return a type conforming to SequenceType (eg. Array). What flatMap then does is that it flattens all these returned sequences and return that as an array.

let shoppingBags = [["Banana", "Apple", "Orange"], ["Cornflakes"], ["Coffee", "Butter"]]
var shoppingBag = shoppingBags.flatMap {
    (let shoppingBag) -> [String] in
    return shoppingBag
}
// shoppingBag = [Banana, Apple, Orange, Cornflakes, Coffee, Butter]

// Or simillar...
shoppingBag = shoppingBags.flatMap { $0 }
// shoppingBag = [Banana, Apple, Orange, Cornflakes, Coffee, Butter]

So flatmap can help you remove a dimension in your array. You can of course do more things than just returning the array passed to the closure. I would say that flatmap is most powerful together with other higher-order functions. Here are some other use-cases.

let shoppingBags = [["Banana", "Apple", "Chocolate"], ["Cornflakes", "Chocolate"], ["Coffee", "Butter"]]
let numberOfItemsInBags = shoppingBags.flatMap { [$0.count] }
// numberOfItemsInBags = [3, 2, 2]

let healthierShoppingBag = shoppingBags.flatMap {
    return $0.filter {
        $0 != "Chocolate"
    }
}
// healtherShoppingBag =  [Banana, Apple, Cornflakes, Coffee, Butter]

let persons = [["id": 1, "age": 30], ["id": 2, "age": 24], ["id": 3, "age": 36]]
let agesPlusOne = persons.flatMap { $0["age"] }.map { $0 + 1 }
// agesPlusOne = [31, 25, 37]

Reduce

func reduce<T>(initial: T, @noescape combine: (T, Self.Generator.Element) -> T) -> T

At last! Lets take a closer look at the reduce function and its declaration. A generic declaration is specified, T. Reduce has two parameters. First initial, an object of type T. Then the combine parameter which takes a closure as argument. The closure in turn takes an object of type T and an element in the collection the reduce function is called on as arguments. The closure should return an object of the same type as the first parameter. The return value of the reduce function is of type T.

The problem the reduce function solves is that it combines all elements in the collection into one single value. While the closure is called on every element in the collection, the initial argument to the closure will be the returned value from the closure for the previous element. The first element in the collection will have the initial argument to the reduce function as the inital argument to the closure. The returned value of the reduce function is the same value as returned from the closure when called on the last element.

let ages = [10, 21, 24, 53]
var sumOfAges = ages.reduce(0) {
    (let initial, let element) -> Int in
    return initial + element
}
// sumOfAges = 108

// Since operators are functions we can do..
sumOfAges = ages.reduce(0, combine: +)
// sumOfAges = 108

Here is the same thing done in Objective-C.

NSArray *ages = @[@(10), @(21), @(24), @(53)];
NSNumber *sumOfAges = @(0);
for (NSNumber *age in ages) {
    sumOfAges = @([sumOfAges integerValue] + [age integerValue]);
}
// sumOfAges = 108

// Or using collection operators
sumOfAges = [ages valueForKeyPath:@"@sum.self"];
// sumOfAges = 108

Of course reduce is not limited to numbers. It can be used with any data type that you can combine into a single value inside the closure.

Conclusion

All these higher-order functions added to Swift can be really powerful, especially when chained with each other. I look forward into discover more of the functional programming concepts added to Swift, and getting used to use them effectively! I think that when you get into the mindset and get comfortable using these methods - You will probably change how you tackle those everyday programming tasks.

The origin of the Apple command-key symbol ⌘

Posted Aug 3, 2015

If you are a PC user you may have seen the Windows-button on your keyboard. But if you are a hardcore Mac user, as I am, you have probably seen and used the command-key [ ⌘ ] instead. But have you ever wondered what the symbol actually stand for?

Back in the old days - before I was even born. Apple computer keyboards had an Apple-key [  ] as well. The key was used in the same way as todays command-key. If you press and hold the key together with another key, you select an option in the menu of the current running application in OS X.

The key combination to use to select a menu option is indicated in the menu.

Command-key combinations

One afternoon, the developers where demonstrating the MacDraw application for Steve Jobs. As you can imagine, there was a whole bunch of apples before the command-key symbol was invented, and that made him really upset!

“There are too many Apples on the screen! It’s ridiculous! We’re taking the Apple logo in vain! We’ve got to stop doing that!”

But how do you find an icon meaning “Command”? That’s not an easy task. The bitmap artist at Apple, Susan Kare, was flipping through an international symbol dictionary searching for inspiration. And there it was! The looped square!

The looped square is well known symbol to us Swedes since we see it on our road signs daily. The sign is used to indicate an attraction or a cultural interest. And since 1983, it’s also used by Apple on their keyboards!

There has been a speculation around where the symbol actually origins from, and that it should be an aerial view of Borgholm Castle. However, the first discovery of the symbol goes back to 400-600 A.D… Centuries before the castle was even built.

For those of you who are interested in this story told by Andy Hertzfeld himself. You can read it here.