mobile it



Architectural missteps in view, presentation, and navigation missteps in view, presentation, and navigation<p>​​Every system and architecture tackles the test of time. It's an unfair battle, almost impossible to win. That doesn't mean we should surrender and hack unsustainable components without the ambition of longevity. We must develop them to deal with this challenge gracefully and try to defer the inevitable as long as possible.</p><p>Nothing lasts forever, though, especially in a fast-moving industry like mobile app development, and some missteps are bound to bubble up along the way. Let's define the most common and explain possible ways to avoid them.</p><h2>Overly logical view</h2><p>Let's start with an obvious one, an arch-enemy to any solid architecture<span style="color:#000000;"><span style="font-size:11pt;font-family:roboto, sans-serif;color:#0e101a;vertical-align:baseline;white-space:pre-wrap;">—</span></span>a view that does way too much.</p><p>The view is an excellent, self-describing name for a software component. Its purpose is <i>to view</i> what's happening inside the system in a user-comprehensive, preferably friendly way. It renders to the screen, listens for content updates, and delegates events to someone else to handle.<br></p><p>When there's a need for an extensive user-interface redesign, it's the view's role to step up, take all the heat, and keep all the vital bits of the application unchanged. It's a straightforward process, as no important presentation or business logic gets in the way.</p><p>That's an example from an optimal world where the view is a thin layer that does just the minimal job it should. Yet some programmers complicate the layer with additional logic, like persistence, state management, or navigation. Those should have their foundation elsewhere, and it's no surprise that dealing with all this extra complexity might prolong redesign estimates from a few days to a couple of months.</p><p>As system and platform designers, Google or Apple aren't leading by example either. On the contrary, they encourage programmers to place too much weight on their views' shoulders by providing them with components that require such an approach. One example for all: the FetchRequest property wrapper, defined in SwiftUI, fetches entities straight from the Core Data store. To quote usage from docs: "<i>Use a FetchRequest property wrapper to declare a FetchedResults property that provides a collection of Core Data managed objects to a SwiftUI view.</i>" Ironic slow clap for encouraging programmers to couple views with data storage.</p><p>There are plenty of wolves in sheep's clothing, so keep your guard up and remember<span style="color:#000000;"><span style="font-size:11pt;font-family:roboto, sans-serif;color:#0e101a;vertical-align:baseline;white-space:pre-wrap;">—</span></span>just because you can doesn't mean you should. Your view should preferably not do much. The thinner the view layer is, the better. UI tends to change quite often, and keeping the view layer lean is a good practice for making swift and safe changes.</p><h2>Almighty view models</h2><p>As part of the presentation layer, view models are responsible for formatting content for the view and handling its events. It should be a comprehensive component, a little helper for the view, listening for changes, and handling presentation logic that lightens the load for the view.</p><p>Usage varies per project, but typically, it observes an application's state, transforms it into user-presentable data, and notifies the view. Unlike views, they are independent of UI frameworks, which makes them easily testable. That's not just icing on the cake but a massive step towards robustness.</p><p>However, they are often misunderstood and create a cesspool for what didn't fit elsewhere. So it happens that they handle business logic, navigation, and all other bits that don't have an official place elsewhere. Some scoundrels even compose requests and deal with networking! That's wrong on many levels; it defies the separation of concerns and tries to fit multiple components into one. This misplaced logic is not reusable and complicates further development on top of that. Such view models span hundreds of lines and compel us to recall massive view controllers from the Objective-C era.</p><p>Overly bloated view models are often present in architectures designed by proponents of MVVM who, in naive pursuit of simplicity, argue that three-layered architectures should easily cover all needs. Simplicity is, without a doubt, one of the goals, but the multi-hundred-line view model is anything but simple.</p><p><b>MVVM is not an architecture.</b> It's a pattern describing how to structure the application’s presentation layer. It would be unwise to build a complete application around any pattern. Why should MVVM be an exception?</p><p>Should you find yourself struggling with where to put something in codebases where the MVVM pattern serves as an architecture of the whole system, you might be on the right track. Navigation, networking, business logic, and many others don't have a well-defined place in incomplete architectures. You can lift the burden from view models with proper <a href="/Blog/Pages/application-domain-modeling.aspx">domain modeling</a>, define a spot for all those other concepts, name them, and be one step closer to a clear and comprehensive design.</p><h2>Lost in navigation</h2><p>In the early days of mobile application development, we didn't emphasize navigation much. Widely adopted architectural patterns such as MVC or MVP didn't have a letter in their name designated just for navigation, so we solely used system components such as UINavigationController, Activity, and Fragment, respectively, Storyboard segues. But these are massive system frameworks mainly “designed” for UI presentation. Their basic use complicates the view and further couples with the interface builder (used for scene designing) in the worst case.</p><p>Fortunately, things have gotten a lot better in the last few years, and with architectural enlightenment have come plenty of new designs. Some have even had their opinion or designated components on how to handle navigation. That's how coordinators, wireframes, flow controllers, and so on came to be. However, extracting the navigation into its place has revealed issues hidden in plain sight, such as sharing data between the screens. Some architectures do address this, but it is often neglected or misunderstood, so state propagation becomes another navigation responsibility.</p><p>The state dramatically complicates the situation for everyone involved in navigation. It must be obtained from the call site and passed to the next scene, which decides where to store such an incoming state. And it doesn't just end there. Once you wish to return to the previous scene, you need to take the state back with you and decide whether or not to replace the last one. That doesn't sound very easy, even for small-scale apps; imagine making sense of this in an app with hundreds of screens.</p><p>When you take a step back, however, you will notice that it is not so much a question of navigation. The problem is in state propagation and its coupling with navigation.​ <a href="/Blog/Pages/swift-ui-and-architecture-state.aspx">Decoupling state to its place​</a> significantly improves usability, testability, and simplifies navigation. It also makes it clear as to who owns the state and where the source of truth is.</p><h2>Architecture-agnostic</h2><p>The post might seem to focus more on a separation of concerns than architecture, but those two go hand in hand. Once you realize the bloated multipurpose components are too hard to tolerate, you start to look for something more cultivated than three-word patterns dressed as architectures. More layers do not equal more complexity. They bring order, and clarity, and leave no place for presumptions (which lead to unwelcome pull-request surprises and heated discussions).</p><p>The resulting product is not the only and most important value we produce. By making the software genuinely soft, we can deliver continuously, with the same effort, and in the long run. That's an essential feature valued in any field by any business.</p> ​<br>#architecture;#view;#presentation;#navigation
Application domain modeling domain modeling<p>Software projects are about telling computers what people want to do. Programmers are the ones who speak the computer language, but ordinary people aren't predestined to think and communicate the way a computer does. They are usually good at telling what they want to achieve and what is the purpose. Then it's the programmer's task to translate the purpose into computer language.</p><p>This arrangement leads to an unintended limitation. When a person needs to tell something to a computer, they need a programmer. When people need information about computer behavior, they need to ask a programmer. Programmers are a bottleneck in this process.</p><p>But what if we can design the project so the code is understandable even for ordinary people?</p><h2>Enter the domain</h2><p>A domain is a part of every project that does the important things. The business logic resides there together with industry rules and policies. The domain must be articulated unambiguously for everyone.</p><p>The domain shouldn't be too technical. There should not be transactions, exceptions, wrappers, or gateways. Ordinary people do not understand these terms but need to understand the domain. Although programmers understand these technicalities, they are ambiguous, and two programmers may imagine a different mechanism under these terms.</p><p>The domain should be full of real-world objects. We should see purchase orders, money amounts, other people, or actual goods. These objects can be virtual, like card transactions, but need to be recognizable to everyone.</p><p>Kotlin exhorts for readable code. This is one of its main characteristics. And we can use it to model our domain.</p><p>The real-world objects are usually modeled as <span class="pre-inline">data class</span> with read-only properties. Any modification needs to be done by a generated <span class="pre-inline">copy()</span> function that prevents unintended state updates or inconsistencies.</p><p>Some objects or data items like Social Security Numbers are so simple that one may tend to represent them as a primitive type like <span class="pre-inline">String</span> or <span class="pre-inline">Int</span>. This is good for program efficiency, but a person may unintentionally swap it with some other information of the same primitive type and introduce a severe error. To overcome this, we may introduce a <span class="pre-inline">data class</span> to wrap the information and give it a unique type. This will work, but its overhead may consume an unacceptable amount of resources when used at a larger scale. Kotlin <span class="pre-inline">value class</span> is a great fit for such use cases. It assigns a unique type to a simple data item while still keeping its memory footprint small.</p><h2>Domain actions</h2><p>Domain objects are important, but they are useless unless we can take action with them. A purchase order is to be placed or canceled. A parcel with a new pair of shoes is to be shipped or claimed. And we need to model these actions as well.</p><p>The first thing is the name. <span class="pre-inline">Action</span> in programming is quite an overused, and generic term and it does not work well for us. Some teams name them <span class="pre-inline">Interactor</span> others use the term <span class="pre-inline">UseCase</span>, or <span class="pre-inline">Actor</span>. We will use the term <span class="pre-inline">UseCase</span> for the rest of this post.</p><p>A use case is defined as a single function with explicit input and output. Use cases have no state and can be called multiple times. Let's try to define them in Kotlin. </p><p>It would be nice if a <span class="pre-inline">UseCase</span> may have a single input and single output so we can define a base type for all use cases with inputs and outputs defined as generics. But in the real world there are actions that may have more inputs, so this is not feasible, is it?</p><pre><code class="kotlin hljs">class FindDriverUseCase { fun execute(position: Coordinates, destination: Coordinates) } </code></pre><p>This approach will work technically, but it does not tell the whole story for people unfamiliar to the context.</p><p>Introducing a specific type for use case input will actually help to understand the context and works as an extension point for further feature evolution.</p><pre><code class="kotlin hljs">class FindDriverUseCase { fun execute(input: PotentialRide) } </code></pre><p>Great, after using this approach for a while, you'll realize that some use cases have their input and output optional. That's fine, Kotlin has built-in nullability in the type system, doesn't it?</p><pre><code class="kotlin hljs">class FindStoresUseCase { fun execute(input: Country?): List<Store>? } </code></pre><p>The use case finds all our company stores. We may want to get a list of all of them or to filter them by a given <span class="pre-inline">Country</span>.</p><p>The definition of input as <span class="pre-inline">null</span> on the use-site is not very understandable in this case. Also, it is hard to guess what <span class="pre-inline">null</span> as returned result actually means. A little bit more modeling will fix this:</p><pre><code class="kotlin hljs">sealed interface For { object AllCountries: For data class SingleCountry(val country: Country): For } sealed interface StoresResult { object NotAvailable: StoresResult object OutOfSync: StoresResult data class Available(val stores: List<Store>): StoresResult } class FindStoresUseCase { fun execute(input: For): StoresResult } </code></pre><p>It seems to be a good idea to deny the value <span class="pre-inline">null</span> as use case input or output at all. Let's introduce a base type and force the generics to be based on <span class="pre-inline">Any</span> that effectively forbids <span class="pre-inline">null</span>: </p><pre><code class="kotlin hljs">interface UseCase<in Input: Any, out Output: Any> { fun execute(input: Input): Output } </code></pre><h2>Actions namespace</h2><p>Quite often, we have a few use cases working with similar objects:</p><p><span class="pre-inline">SubmitPurchaseOrderUseCase</span>, <span class="pre-inline">CancelPurchaseOrderUseCase</span>, …</p><p>These class types may quickly pollute the project's namespace and make it hard to navigate.</p><p>We should try to group them somehow under a shared namespace. Kotlin doesn't have support for namespaces (<a href="">yet</a>). We can supersede it by grouping the use cases under a single <span class="pre-inline">sealed interface</span> for this purpose. You can use <span class="pre-inline">sealed class</span> or <span class="pre-inline">object</span> as an alternative, but the memory footprint would be slightly bigger.</p><pre><code class="kotlin hljs">sealed interface PurchaseOrderUseCase { class Submit { … } class Cancel { … } } </code></pre><h2>Kotlin call site</h2><p>Now let's look at the call site:</p><pre><code class="kotlin hljs">val purchaseOrder = PurchaseOrder(...) val submitPurchaseOrderUseCase = PurchaseOrderUseCase.Submit() val result = submitPurchaseOrderUseCase.execute(purchaseOrder) </code></pre><p>We can polish it with a little trick called Invoke operator. When a Kotlin function named <span class="pre-inline">invoke()</span> is marked as <span class="pre-inline">operator</span>, its invocation may be replaced by the use of <span class="pre-inline">()</span> operator.</p><p>When applied to our base type</p><pre><code class="kotlin hljs">interface UseCase<in Input: Any, out Output: Any> { operator fun invoke(input: Input): Output } </code></pre><p>the call site can be simplified to</p><pre><code class="kotlin hljs">val purchaseOrder = PurchaseOrder(...) val submitPurchaseOrder = PurchaseOrderUseCase.Submit() val result = submitPurchaseOrder(purchaseOrder) </code></pre><p>Notice the use case instance name change, where the <span class="pre-inline">UseCase</span> suffix has been omitted, and its invocation now looks like a standard function call. If it is used in an obvious context, we may shorten the use case instance variable name even more and call it simply <span class="pre-inline">submit(purchaseOrder)</span>.</p><h2>Swift call site</h2><p>Until now, we were only calling our use cases from Kotlin code. On Kotlin Multiplatform projects, it is common to share the domain logic between all targeted platforms. Let's check how a use case may be used in another language. We will take the example of a mobile application implemented both for Android in Kotlin and iOS in Swift.</p><p>First, let's try to call it the same way we do in Kotlin.</p><pre><code class="kotlin hljs">val submitPurchaseOrder = PurchaseOrderUseCase.Submit() val result: SubmitResult = submitPurchaseOrder(purchaseOrder) </code></pre><p>This code has two major problems. The invocation operator is unavailable, and the result is not of type <span class="pre-inline">SubmitResult</span>. Let's start with the latter one.</p><h3>Swift generics</h3><p>Generics in swift are available only for <span class="pre-inline">class</span>, <span class="pre-inline">struct</span> and <span class="pre-inline">enum</span>. A very similar thing for <span class="pre-inline">interface</span> is called associated types, but its characteristic is incompatible with Kotlin generics.</p><p>This is why Kotlin Multiplatform has Swift generics support only for classes. To fix this in our project we need to define our base type as an <span class="pre-inline">abstract class</span> instead of an <span class="pre-inline">interface</span>. This is actually not an issue as its implementations are classes anyway:</p><pre><code class="kotlin hljs">abstract class UseCase<in Input: Any, out Output: Any> { abstract operator fun invoke(input: Input): Output } </code></pre><h3>Swift function invocation</h3><p>Now let's fix the former problem with use case invocation. Swift language doesn't have an invoke operator like Kotlin. Instead, it has methods with special names, and one of them is <span class="pre-inline">callAsFunction()</span> that can be called with the use of <span class="pre-inline">()</span> symbol.</p><p>We may introduce this function to our use case base type but that may be confusing for use from Kotlin common code or Android code.</p><p>To make it available for iOS code only, we will provide different implementations of use case base type for Android and iOS using Kotlin's <span class="pre-inline">expect</span>/<span class="pre-inline">actual</span> feature. Its implementation just delegates the call to our standard <span class="pre-inline">invoke()</span> function.</p><pre><code class="kotlin hljs">// Kotlin Common expect abstract class UseCase<in Input : Any, out Output : Any> constructor() { abstract operator fun invoke(input: Input): Output } // Kotlin Android actual abstract class UseCase<in Input : Any, out Output : Any> { actual abstract operator fun invoke(input: Input): Output } // Kotlin iOS actual abstract class UseCase<in Input : Any, out Output : Any> { actual abstract operator fun invoke(input: Input): Output fun callAsFunction(input: Input): Output = invoke(input) } </code></pre><h2>Living documentation</h2><p>The domain is a part of every project that actually does the important things. When modeled properly, it suits so-called living documentation. It is understandable for any reader; anytime a logic is changed, the documentation also changes. </p><p>Anytime you find a piece of domain code that is not understandable, let's take a moment and polish it. Your future will be grateful to you.</p><p><br></p><p>Pavel Švéda<br></p><p>Twitter: <a href="">@xsveda</a><br><br></p>​<br>#domain;#architecture;#kotlin;#swift;#multiplatform
Unexpected bad practices bad practices<p>​​​​Some programming practices are so familiar to us that we use them automatically without much thought. Sometimes these techniques become obsolete; sometimes they are applied in the wrong context. Addressing such poorly experienced habits is often met with revolt. Especially by those who use them and perceive the topic as useful, so let's do exactly that!</p><h2>Marks</h2><p>Programming IDEs often recognize specific types of comments to help navigate across the codebase. Xcode’s <i>FIXME</i> lets other developers know that a piece of code deserves more attention. <i>TODO</i> is helpful when something is, well, to be done. <i>MARK</i> differs from the previous cases; it serves a documentation purpose. The same feature in IntelliJ IDEA/Android Studio is called r​egion.</p><p>Marks divide the source code into multiple parts using headings. That can make the code appear broken into logical units. If you are a reader familiar with the former Objective-C era of iOS development,​ know that this is just an updated <i>#pragma mark</i> directive.</p><p>Typical usage is in files with a large number of lines. <i>Marks</i> create the illusion of clarity by breaking them into pieces that supposedly belong together.</p><p> <b>The usage of marks in such cases is a bad practice.</b> Developers often abuse them to justify a file being too big. One should not depend on Xcode to make the code comprehensive and readable. Small and well-decomposed classes are more straightforward to reason about and navigate without IDE features. Especially for pull request reviewers using the web interface where those features are absent.</p><h2>Extensions</h2><p>Modern programming languages such as Kotlin or Swift allow you to extend classes, interfaces/protocols, structs, or enums to provide an additional implementation. You can divide your code into multiple pieces using extensions to outline what belongs closer together. Another usage is to make a convenience extension around another type you might not even own to make its use more intuitive. The possibilities are almost limitless. This isn't always a good thing, but first, a peek into history. </p><p>Extensions existed way back in Objective-C as well. If you're not blessed with experience with programming in such a language and had to guess the name for extensions, you'd likely be surprised. It's Categories! Another surprise is that Extensions are a thing in Objective-C too, but serve different purposes. What's interesting is the difference between both languages. Categories in Objective-C forced the developer to come up with the name. That's why files named in style <i>Class+CategoryName.swift</i> are often used even for Swift extensions. And more importantly, to use Categories, you had to import them explicitly.</p><p> <b>Extensions in Swift are an unnamed piece of code.</b> Such code may be more complicated for the reader to grasp. If multiple extensions of the same type exist, adding a name to the code and wrapping it in a type might help readability immensely.</p><p> <b>Improper extension of widely used types causes namespace pollution.</b> It's critical, before creating extensions, to ask whether all instances of the type should have such an ability. Should all UIViews have access to a blinking method? Does one specific subclass of UIView make more sense?</p><p>Some developers use extensions to break down the implementation of multiple protocols: which might also be a warning sign. If a class implements many protocols, it may be time to consider splitting it into smaller classes.</p><p>For trolls out there: you can make your co-workers mad by extending <i>UIView</i> with <i>translatesAutoresizingMasksIntoConstraints</i> and watch them compare it with <i>translatesAutoresizingMaskIntoConstraints.</i></p><p>But don't.</p><h2>Comments</h2><p>The ability to write comments might lead undisciplined programmers to create code of poor quality. Unfortunately, it's easier to neglect to name a variable and describe what's going on in my head with a complicated but not-so-clear comment. Easy should not be our goal. Brevity and clarity should.</p><p> <b>Great comment for poorly written code is still a code smell.</b> Don't just take my word for it. Robert Martin states: "A comment is a failure to express yourself in code. If you fail, then write a comment; but try not to fail."</p><p>Another reason is as the code lives in the repository and is modified and refactored, its behavior might change, and its name can express it everywhere it is called. But its comment is rarely updated and may become more confusing than helpful.</p><p>Documentation comments serve their purpose very well when you're designing an API for others to use. Remember that the API needs to stand by itself, and clarity is the priority. Don't use the documentation comments as an excuse for a lousy design.</p><h2>Structure</h2><p>The structure of a project is one of the first things you see when you check out a codebase, and it should outline the app's purpose at first sight. However, it is not an exception that some projects have folder structures inspired by the layers of architecture, e.g., View, ViewModel, Model.</p><p> <b>Project ​struc​ture based on architecture layers is a bad practice.</b> It makes reusability effectively impossible. Navigating through such a structure is unnecessarily complicated and becomes harder to maintain as the scope increases. It doesn't scale. Folders inspired by the architecture might have their place, not just at the top level. It should not be the first thing you see.</p><p><img src="/Blog/PublishingImages/Articles/unexpected-bad-practices-01-01.png" data-themekey="#" alt="" />     </p><p>See for yourself, what structure tells you more about the application?</p><h2>Dependencies</h2><p>Open source offers many libraries to simplify life, from UI components through networking to dependency injection solutions. It can often save a great deal of time and effort. On the other hand, this carries various dangers and limitations; using third-party libraries requires discipline, order, and balance.</p><p> <b>Randomly scattered third-party dependencies significantly reduce robustness.</b> Shielding the core of the application and using the libraries from the outer parts of the architecture helps mitigate the risk. Abstraction eases the process of replacing one library with another.</p><p>It's OK to utilize 3rd party dependencies, but with caution. Ask yourselves: How much time will it save me? How much effort will it take to replace? Can I install enough defense mechanisms to protect the application? </p><p>The silver bullet to protect your app, though sometimes tricky or impractical, is to have the import of the dependency in only one place.</p><p>We've had the pleasure of taking over multiple apps that were impossible to maintain anymore due to this problem. Without abstraction, no longer supported (or closed sourced) libraries disintegrated the codebase. External dependencies should never hold your product hostage.</p><h2>Tests</h2><p>Test-driven development is a programmer's good manners, a discipline overflowing with benefits. Technical impacts are a blog post by itself, if not a series. Non-technical impacts such as easy onboarding of new team members and executable documentation that cannot become obsolete speak for themselves.</p><p>Yet they are often neglected. A complete absence of tests is the apparent first and most common violation, followed by writing tests after the production code, which mitigates all the benefits and introduces other obstacles.</p><p> <b>You must write unit tests first - before production code.</b> Testing first will prevent you from creating code that's too complex. It will guide you through building components of the right size. The big classes are challenging to test, and the tests will direct you to decompose them into smaller ones.</p><p>Tests written after production code are inherently lower quality and can even be misleading. Unless you write the production code as proof of the first failing test, it is impossible to say whether the tests assert what they declare. It is then questionable how well such tests protect the system under test.</p><p>If you write tests after implementation, you may find a component challenging to test, which is impossible with a test-first approach. You can't create untestable code!</p><h2>The devil's in the detail</h2><p>Even the mundane can be harmful if we do something too automatically and with less attention. Challenge the ordinary and seek bad practices that you wouldn't expect.</p> <br>#xcode;#swift;#kotlin;#productivity;#team-collaboration
Development rules for better productivity rules for better productivity<p>​Each project has its own rules for development. Most often, these rules describe development practices and work with a version control system (VCS) that outlines how to test and deploy the product, the structure, the architecture of the project, and the code style, but the rules can also include the basics of secure development and more.</p><p>These rules can be unwritten but are usually defined and recorded in a shared space where everyone has access to them. Yet more important is how these rules are applied and enforced in practice.</p><h2>Wise men know it best</h2><p>Some people believe that pair programming or code review is an appropriate platform for rules revision. Participants can agree on the application of the rules or change them based on context. When developers approach this conscientiously, the result can be a project that may not be consistent, but its individual parts will be in the best possible shape.</p><p>This approach may lead to better results for a short period of time at the start of a project, but its shortcomings will start to become apparent over time. Even experienced developers and technical leads are just people. They can occasionally get tired or simply overlook something. Thus, minor deviations from the agreed-upon rules pile up and begin to form so-called technical debt.</p><h2>Time trial</h2><p>The next aspect that reflects in time is the expansion of the project, and this is on two levels.</p><p>The first is the expansion of the product itself. As the product becomes successful, it receives new and more sophisticated features that begin to connect previously simpler and independent features. This is where the small deviations and inconsistencies that at first seemed good for the functionality start to show up. The problem is that now more of these functions need to be compatible with each other, but they are not ready for it.</p><p>This is not just a problem of incompatibility of features. Often, well-intentioned developers try to reuse existing components as much as possible to avoid code duplication. They forget the rule that we can reuse a component when we expect the same behavior but also have the same reasons to change. If this condition is not met, the Single Responsibility Principle is violated and the project has low flexibility for future development.</p><p>The second level of project expansion is the development team itself. Once the product becomes successful, sooner or later it leads to the expansion of the development team. The new team members do not know the whole genesis of the project and thus do not have the same understanding of the rules as the older members who set the rules themselves. This leads to misunderstandings and yet another minor deviation from the agreed rules, which again increases the technical debt. A side effect is an increased need for communication during pair programming and code review, which reduces the overall productivity of the team.</p><p>These problems in project expansion are not limited to large development teams, but also happen to smaller ones. For example, when a two-person team introduces two new developers, the productivity of the team may hardly change. And all this is due to the circumstances described above. Without knowing the cause of the problem, it can lead to further blind "strengthening" of the team and make it even worse.</p><h2>Tripping comes before a fall</h2><p>When a development team repeatedly fails to finish agreed features or is unable to release a new version of a product for technical reasons, one of the critical scenarios occurs. At this point, people outside the standard development team get involved in discovering the cause and solving the problem. Together, they all work under stress and with a lot of human effort to get the development back under control. It is only at this point that a retrospective analysis takes place to uncover the true causes of the problems.</p><p>Yet the accompanying symptoms and spring of these problems have been manifesting themselves for a long time in advance. A few subtle situations as examples: </p><ul><li>A developer repeatedly receives feedback on misnaming during code review.</li><li>A ticket in the project issue tracker does not contain a reference to the implementation due to a typo in the project source code. </li><li>A feature that is still under development is enabled in the test version of the application.</li></ul><p></p><p>Often they just look like minor ambiguities, individual mistakes, or accidents that sometimes happen during development. When these situations recur, their negative impact on team productivity and the project's error rate quickly increases. But if we look closely at them, we can see blank spaces in the way we work that are actually easy to fill and solve the problem once and for all.</p><h2>Live rules</h2><p>To avoid the problems mentioned above, we need to have clearly specified development rules. Their content should reflect the individual needs of each project. For some projects, it will be critical to clearly define collaboration with the QA team and describe the release management of the product, while other teams will focus more on collaboration between developers within the development itself.</p><p>The more detailed and specific the rules are, the better their effect on the team's work will be. Therefore, it is not possible to start from a general template, but each team must define these rules themselves.</p><p>Sometimes we see cases where a team defines a few basic rules of a more general nature at the start of a project but does not develop them over time. Thus, the rules never accurately represent how the team works, and even the little they contain becomes meaningless over time.</p><p>Nothing is set in stone, and even an established team changes the tools it uses or discovers new ways of working over time. All these natural changes have an impact on the team rules. They remain alive and valid.</p><h2>Automate everything</h2><p>In the introduction, we briefly discussed the form the rules can take and the possible ways of applying them. To be most effective, rules must be applied automatically without the need for manual control. Likewise, we must think about the productivity of the team, which can be reduced by the influence of a large number of repressive rules. Therefore, tools that help team members automate certain steps are an integral part of this process. These tools save time and their output is naturally in line with the defined rules.</p><p>In practice, it is so common that Code Style or Project Architecture is enforced by automated rules, but at the same time, there are code templates and formatting tools that do most of the work for the developers without them being aware of it.</p><p>Most issue tracking tools provide a programmatic interface so that it is easy to automate the creation of a new development branch in VCS so that the new code is linked to a specific issue. Similarly, it is possible to create a VCS hook that checks that a corresponding issue exists for a given branch or commit for cases when the developer has created the new development branch manually.</p><p>Release management is a completely separate chapter. When releasing a new version of a product, there are generally routine and clearly defined steps that need to be performed. Here, automation not only gives us the assurance that the release of a new version will be done in an orderly and error-free manner but it also speeds up the process and allows for easy knowledge sharing between team members. A bonus is an easy automation of generating release notes, even if only for internal testers.</p><p>Testers will also appreciate the ability to configure the product for internal testing. They can toggle a feature flag, configure the environment the application runs against, or have the ability to simulate scenarios that are difficult to do manually. Besides the undeniable benefit of these test tools for testers, it has benefits for the developers themselves. They don't have to maintain more versions of the product than strictly necessary, which saves them time by fundamentally simplifying the build logic.</p><p>This is just a small sample of the rules we commonly encounter on projects. However, it is far from exhaustive of the options, whether they are related to quantity, depth, or sophistication.</p><h2>How far to go?</h2><p>Some rules may seem strict enough to restrict your freedom to work. Others may seem so vague that they will not have the desired effect. That's all right. Every team and every member has different needs and different perceptions of risk. All of this has a bearing on the form of the rules.</p><p>In our projects, we try to define the rules strictly by default. Over time, when we find that they limit us too much, it's easy to make the rule more generalized or turn it into a recommendation or warning. The opposite approach is considerably more complicated, because the team and its operation have already become accustomed to the more general rule, so it may not be possible to make a change overnight.</p><h2>Project sustainability</h2><p>When developing a product, in addition to the short-term goals of making the necessary features, we always consider the idea of long-term sustainability and viability of the project. Especially in mobile development, it is not an exception to the opinion that a project should be discarded once every 2-3 years and developed completely from scratch. This is a real disaster in terms of productivity.</p><p>In our portfolio, we have apps that are more than 7 years old and have gone through several major changes during their lifetime. On a business level, there has been a change in targeting a different sector of users and aligned with changes in branding and design. On a technical level I would mention the switch from Java programming language to Kotlin, or the transition of asynchronous work from a custom imperative solution to a reactive approach via RxJava and later Kotlin Coroutines. Even so, the development team is still only two people (while they are altering throughout) and at the same pace, it delivers new functionalities according to the business needs.</p><p>Clearly defined development rules and the consistency enforced by them have a major impact on the quality of the final product in every way.</p><p>Next time we will take a closer look at how some rules can be implemented and what tools we have for this.</p><p><br></p><p>Pavel Švéda<br></p><p>Twitter: <a href="">@xsveda</a><br><br></p>​<br>#productivity;#team-collaboration;#architecture;#automation
Our Minimalistic Approach to 1st and 2nd Level Support Minimalistic Approach to 1st and 2nd Level Support<p>​At one of our projects, we're working in a scrum team counting around 10 people. The product has gradually been rolled out to more users and is getting traction. This is good because it provides us with a tangible metric of our product's reach and it gives us more opportunities to validate our ideas in the real world as we see how users react to them.</p><p>Some of the users are also proactively providing feedback about things that are cumbersome, hard to use, or outright buggy. So far we (with a major contribution from our product owner) have managed to gather and process the feedback in an organic way. </p><p>Over time this activity has grown to a considerable effort and has started to consume precious time and we've started to feel like things are slipping through. We need to find a more robust way to handle the user requests.</p><p>The goals we want to achieve by having a link to the users are far from unique. To name a few:</p><ol><li>Collect defect/incident reports</li><li>Collect feature requests</li><li>Help users with troubleshooting</li><li>Have a feeling for the general user's sentiment</li><li>Respond to and inform users</li></ol><p>We don't want to have just a <q>passive</q> way of collaboration with users (meaning only to collect input) but we'd like to be able to respond in a relevant way to their reports or questions. We want them to know what they can expect from us and likewise let them know they're heard and that their contribution is welcome.</p><p>Unsurprisingly, we discovered the majority of users' requests were repeats of the same thing. Users either did not understand a certain feature or a general expectation was misaligned with the product itself.</p><p>Many of the user issues could be resolved quite easily by answering directly and potentially providing further explanation if needed. It became obvious that we need to focus on improving UX here and there. Or bring a new feature because users are repeatedly struggling with certain actions.</p><p>But in order to draw useful conclusions from the numerous inputs and to convert them into prioritized backlog items, we needed more <q>human processing power</q> and a way to somehow standardize the inputs.</p><p>This led us to introduce a combination of a few new concepts.</p><h2>Introduction of bug reports</h2><p>We implemented a bug report function. We wanted to keep it as simple for the user as possible. So after clicking the <em>report bug</em> icon the only thing the user needs to write is an answer to the question <q>What did you expect to happen?</q> and to click a confirmation button.</p><p>We attach a lot of metadata to this and the bug report is then visible in our product's back-office web. This alleviates the need to read through emails and keeps the form uniform to some degree. It also automatically collects crash logs.</p><p>So far we have decided not to integrate this to JIRA for a reason I will explain in a minute.</p><h2>Introduction of support levels</h2><p>The customer for whom we are building the product is a large corporation and one of their business activities is software services. That means they have a department full of people experienced in 1<sup>st</sup> level support activities. So it appeared as a logical option to collaborate with them on this as it was preferred to use in-house personnel.</p><p>This idea posed a few challenges nonetheless:</p><ol><li>How to define competencies?</li><li>How to bring them to a level of knowledge necessary for stand-alone work?</li><li>How to help them with unexpected things?</li><li>Find a way to report problems they can't resolve on their own.</li><li>How to keep them up-to-date with the latest fixes and features?</li></ol><p>We decided to follow the 3-level support model. In our development process it meant the following:</p><h2>1<sup>st</sup> level: </h2><p>Roughly 4 people from the help desk department were selected to join us part-time. Their competence within our development process is:</p><ul><li>Answering general users' questions.</li><li>Resolving user issues that don't require a change of system data or the system itself.</li><li>Passing unresolvable issues to 2<sup>nd</sup> level support.</li><li>Collecting data about frequent bugs.</li><li>Bringing ideas to mitigate the most frequent user complaints/questions.</li></ul><h2>2<sup>nd</sup> level: </h2><p>For the time being, we have decided to bring one extra person who will tackle this alongside our product owner. </p><ul><li>Resolving incidents stemming from bad system data via our system's back-office web.</li><li>Resolving issues that 1<sup>st</sup> level support lacks knowledge of.</li><li>Adding new articles to the knowledge base for the 1<sup>st</sup> level support</li><li>Passing issues to 3<sup>rd</sup> level support</li></ul><h2>3<sup>rd</sup> level: </h2><p>This is the actual scrum team. So the job is to prioritize and implement what comes through the support pipeline.</p><h2>Setting up new flows</h2><p>In order to keep the new 1<sup>st</sup> and 2<sup>nd</sup> level support colleagues in the loop we invited them to our asynchronous communication channels. This way we could quite flexibly answer their questions without the need for yet another regular meeting and it seems it helped their learning process. As of now, they are already quite knowledgeable and their questions are getting more and more <q>advanced</q>. We feared the number of questions could overwhelm us, but it seems we managed it and the ad-hoc communication is effective.</p><p>We also invited all of them to the sprint review meetings, so that they are aware of the current situation and know when the bugs reported by them are done. This is also a perfect place for them to express any general observations and opinions about how they perceive priorities of items reported by them compared to other backlog items.</p><p>For the most frequently occurring questions or problems, we created a simple knowledge base that the 1<sup>st</sup> level colleagues can use while troubleshooting user issues. 2<sup>nd</sup> or 3<sup>rd</sup> level support people occasionally add new articles if a question gets repeated.</p><p>We've been using JIRA as a tool for keeping our backlog since the beginning of the project. Our fear was that introduction of formalized support levels could bring large overhead, so we decided to keep the tools as simple as possible. We don't need any sophisticated helpdesk system. </p><p>Therefore we decided to create two new issue types in JIRA and right in our project space. We called them (no surprise here) a <em>1<sup>st</sup> level ticket</em> and a <em>2<sup>nd</sup> level ticket.</em> Those tickets got a very basic state flow: <em>Open ​→​ In progress →​ Closed + 2 more: Waiting for a reply and Reply obtained</em>.</p><p>We decided to use the original JIRA project space for the 3 support levels. The main reason was to let everyone inspect the backlog if necessary and to check how things are progressing. The second reason was to avoid complexity in our flows.</p><p>By doing this, 1<sup>st</sup> and 2<sup>nd</sup> level support people can also comment on any existing issue in the backlog in case they have relevant additional information. In order to keep things organized we simply created a few new quick filters to view <em>only the 1<sup>st</sup> level tickets</em>, the <em>2<sup>nd</sup> level tickets</em>, or to <em>hide them</em> and view the backlog just as it was before the 1<sup>st</sup> and 2<sup>nd</sup> level people joined in.</p><p>Both of the new issue types also received a button to conveniently convert the issue to a <q>higher</q> one. Meaning that from <em>1<sup>st</sup> level ticket</em> we create a <em>2<sup>nd</sup> level ticket</em> with a click of a button. And from the <em>2<sup>nd</sup> level ticket</em>, we create a <em>bug</em>​ or a <em>user story</em> in the same way. In addition, we created two new boards to display just the respective issues type and their current states.</p><h2>Time will tell</h2><p>So far this model has worked well for us. We get a feeling of safety knowing there is no negative sentiment accumulating among the users we wouldn't know about and could explode later. The test of time will tell if we need to modify the process. Many more users are expected to start using the product. As with anything in such an environment, we will certainly need to adapt eventually. We just don't yet know when. I will come back with an update after we're wiser again.</p>​<br>#agile;#project-management;#scrum
Scope and Time Fixation and Time Fixation<p>​When planning for a milestone such as a release or a development finish, there are several approaches we can choose from. A traditional (and often intuitively chosen) approach is to try to predict and fix all the project imperatives. What does this mean?</p><p>As a countermeasure to reduce the number of unexpected events at the beginning of the project, it is common to make a detailed plan months in advance and expect the development teams to keep it. </p><p>Let's say we want to do a major release of our software. The product owner and the stakeholders make their expectations about a release date, the content (scope) it’s going to include, and the cost. In the best case scenario, their expectation is based upon a discussion with the development team.</p><p>The development proceeds and the release milestone approaches. More often than not, the team encounters unpredicted problems and some of the features are delayed. As the release date approaches, it becomes clear that the release plan is endangered. The team starts to get anxious. Then, shortly before the release date, it is evident that not all of the planned scope is going to be finished. As a result, the date gets postponed by managers with the hope that the remaining scope will be finished on time.</p><p>Moreover, additional requirements from the stakeholders arrive and the product owner wants to include them in the release to gain positive perception. The release has already been postponed once, so it would be great to overperform this time. As it usually happens in development, fresh bug reports arrive. Let's include corresponding fixes in the release too. A vicious cycle begins.</p><p>The point is that the more a release keeps getting postponed, the higher is the temptation to include additional content to make up for previous disappointment. Usually, a release is postponed multiple times and gets delivered weeks or months later with a great deal of nervousness.</p><p>What helped our teams in such situations?</p><h2>Back to the basics</h2><p>The first thing we hear when you learn about project management approaches, is how the combination of time, cost, and scope work together. The traditional approach is that in the planning phase of a project, it is decided what functions we will create, how much it will cost, and how long it will take. As I covered in my <a href="/Blog/Pages/scrum-smells-7.aspx">previous posts</a>, I believe it is a futile effort to attempt to make an exact determination of <em>all of the three project imperatives at once</em> as reality rarely follows them in the long run.</p><p>When we define a fixed scope, fixed timeline, and fixed cost, there is virtually no room for flexibility if something goes wrong. From my observations, the effect is usually that in the (probable) case of unexpected problems, it is the quality of the delivered scope that gets sacrificed. In other words, it is an attempt to make the scope somehow flexible by re-interpreting its definition.</p><p>This usually leads to the project manager trying to negotiate a later time for a handover (or release). There is a tendency to check off as many items of the scope list as possible, so that it looks good in reports and on paper the project can proceed to the next phase (and possibly allowing for a payment milestone). But under the hood, shortcuts were taken and oftentimes the pressure to <em>deliver something</em> comes at the cost of the software being defective and half-functional. </p><p>In scrum terminology the scope items are not done. There is a technical and/or business debt. Contrary to the definition of done, there is still known work to be done on these items.</p><p>The costs for paying off the debt are considerably higher than the effort necessary in getting it right at the first go. In many cases, it also means that <em>nothing</em> can be released due to numerous defects. The whole package remains unacceptable. </p><p>Agile approaches try to keep one of the three imperatives (scope, time and costs) flexible. We have a given team with a certain development capacity. That team consumes a predictable budget over a given period of time. What options do we have?</p><ul><li>Team capacity (staffing): affects the throughput over time. Changing it influences the rate at which budget gets consumed and scope gets developed. In this article I assume that the team is naturally using its resources effectively and attempts to improve its performance over time as it matures.</li><li>Development duration (time): affects how much scope can be delivered with a given capacity and lets us cap the invested budget.</li><li>Scope: changing scope will affect how long a given team consumes the budget.</li></ul><p>So if we have a specific budget we need to invest, we can set a suitable team, calculate how long the budget will last, and keep the scope flexible. Or the other way around, if we want a precise scope to be developed, the timeline becomes the bumper. Also, the team size needs to be chosen adequately. We need to be able to supply it with high value business requirements meeting the definition of ready.</p><h2>How to combine time and scope</h2><p>Unless we are in a very rare case when the product aspects are well predictable (process-like activities), we must accept the fact that we need to prioritize the project imperatives. In my experience trying to juggle both scope and time at once usually leads to a lot of confusion and it often sabotages any rhythm the team may have. I believe prioritizing one over the other is the way to go.</p><p>On our projects we usually keep the team capacity at a reasonable level and then prioritize time over scope. That means we set a particular milestone in the calendar and concentrate the activities into making it happen. The scope is the flexible element. </p><p>Let's use an example. The product owner wants to make a release of an update on the market. He deems that it’s worth doing it a month from now because that will bring a considerable improvement to the user and will create a positive perception.</p><p>The product owner and the team make their preliminary prediction about what backlog items they expect to deliver. The team spends that month working on them. As usual, they discover considerable complications with some backlog items along the way and major defects are also reported from the users. Then it becomes clear that not all of the originally expected backlog items will get done by the release date.</p><p>The development team, together with the product owner re-prioritize the backlog to incorporate these new findings. It is decided that the resolution of certain bugs would bring considerable value. Problematic backlog items are put off, so that the team does not spend effort on something that will probably not be finished. The team focuses on the sole goal of making the product releasable at the given time. They are not obsessed with the necessity of delivering absolutely <em>everything</em> that they originally thought. Functionality that will not be included in this release will be contained in the successive one.</p><p>Figuratively speaking we need to draw a horizontal line in the backlog. There are two options for where to draw it. It's position is either fixed and the exact development duration will be adjusted, or time is set and the position of the line in the backlog can be adjusted along the way - it floats.</p><p>By keeping the backlog constantly refined, well prioritized, and the backlog items as atomic as possible, we are maximizing the chance that what falls over the line isn't vital.</p><p>In the example above we used a release as a milestone. But a milestone can be any other critical event - such as consumption of the project's allocated budget.</p><h2>It sounds easy, but...</h2><p>This idea is nothing revolutionary. But putting it into practice usually includes avoiding a few frequent mistakes:</p><ul><li>Avoid stakeholders from expecting strict time and scope fixation. It takes effort to explain that there always needs to be an approach to minimize risk of critical stuff falling over</li><li>Avoid stakeholders from putting you into a situation where <em>everything is equally important</em>. It is the job of the product owner (with the help of the scrum master) to educate them about this.</li><li>Don't be tempted to postpone the release milestone just a little so that you can fit in that one extra valuable item. It's better to set a regular schedule for releases and be safe in the knowledge that it won't take long before the next release.</li><li>Don't juggle with both scope and timeline at once. Prioritize one over the other.</li><li>Don't cling onto past predictions. The situation always evolves and rather constantly evaluates if the prediction is still valid or not.</li><li>Don't get caught up in details. Use the dailies to take a step back and see how the team is progressing towards a goal and if there are any new obstacles in the path.</li></ul><p>Psychology plays a major role when things don't follow the budget - scope - time triangle. But it would be naive not to proactively take steps for when it happens. Deciding on a general strategy - whether to fix time or scope - takes a lot of weight off the team's shoulders and makes development much more predictable and manageable. So always think about what can be sacrificed from the original predictions if things go wrong.</p><br>#agile;#project-management;#release-management;#scrum
Marginal Utility and Product Management Utility and Product Management<p>​​​​​​Today I'd like to browse into the waters of economics. There are certain concepts that I believe are highly relevant to the way we build software products. You might be wondering, how do these two fields come together, but bear with me, they are more connected than we often realize. Understanding some basic ideas of behavioral economics can help us steer software projects as it provides us with a different perspective on the prioritization and value-maximization process, which I write about frequently.</p><h2>Utility</h2><p>Before we get to the marginal utility we need to understand some basic concepts. What is a utility anyway? It is an economic term that refers to how much satisfaction a person will get from consuming a particular good or service. The important part to understand is it's the total utility one gets from consumption of certain goods. This is given by the sum of satisfaction one gets from consuming all the individual parts of it.</p><p>​Let's look at an example. Assume you are eating a pizza. The total utility you get from that pizza is how much satisfaction it provides for your particular needs when eating all the single slices. In this case the need you satisfy is typically just hunger (need to eat and/or cravings).</p><p>How can we measure utility? Unfortunately, most of the time it is not directly possible. You can't objectively measure how much satisfaction eating a pizza can bring. On top of that it is highly individual. The satisfaction (utility) you get from eating pizza will probably differ greatly from the satisfaction that the same pizza will bring to Bob, who is allergic to gluten and ate lunch a few minutes ago.</p><p>But what we can do is to compare the value that different goods or services can bring to you. In a given moment you can compare the utility of a pizza compared to that of a steak. The one you'd rather eat is the one with the higher utility to you. You can also compare it to the satisfaction a particular water would bring. Or a car. Or a house. You can assign some abstract dimensionless value to each of the potential goods (similar as we do it with story points) and those can be compared.</p><p>It is obvious that utility, even for a single individual, varies greatly depending on the context. You might say a house would be of a much higher value than a bottle of water. But would you still insist on this if you were parched and lost somewhere in a desert? The famous line <em> <q>My kingdom for a horse</q></em> is a good demonstration of this phenomenon.</p><p>Utility is context dependent and that is also why people are willing to pay different money for the same good when the situation changes. Buying used skis is usually going to cost you less in summer than in winter because people don't demand them as much. Trying to sell ice cream on a beach in summer is an easier job than doing the same in winter time. Context matters for utility.</p><h2>Marginal utility</h2><p>Knowing that, what is a marginal utility? This concept measures how much utility will the next unit of a good or service bring. The total utility is then the sum of all marginal utilities you get from individual parts of that good or service.</p><p>Back to that pizza. Eating a first slice will give you much satisfaction because you went from starving to having something to eat. That was the marginal utility of the first slice.</p><p>The second slice will probably be almost equally satisfying because you are still hungry. But will the 8th slice be as satisfying? Probably not because your hunger is gone by the time you get to it. So gradually we usually tend to get lower and lower marginal satisfaction of each additional unit of a particular good we consume.</p><p>An interesting fact is that marginal utility can also be negative. How much satisfaction would eating the 24th slice of pizza bring you? It would likely not be something you would voluntarily eat (unless you're attending some who-eats-the-most-pizza contest). That one extra slice of pizza could make you sick and therefore cause a negative experience. The marginal utility of the 24th slice would be negative and the total utility of the whole meal would start getting lower.</p><h2>How does all this connect with software development?</h2><p>We're building a software product that serves people. Their motivation to use it stems from the fact that they get some satisfaction out of it. Their needs get fulfilled when something that was once difficult gets easier thanks to our product.</p><p>When building a software product, we have limited resources to fulfill those needs. So we all know we should maximize the value of the time (or other resources) we invest into building it. That is no surprise.</p><p>How can the economical concept help us? I have seen a natural tendency by the product owner (and the rest of the development team including the stakeholders) to attempt to define backlog items as the final form of a software feature; a form that immediately brings users the <em> <q>fullest</q></em> and most <em> <q>perfect</q></em> possible behavior.</p><p>I won't go into deeper detail here, but if you are interested please check one of my <a href="/Blog/Pages/product-development.aspx">previous posts</a> on this topic .</p><p>Understanding the marginal utility concept can help us overcome that psychological barrier of not wanting to reduce individual backlog items to atoms. We want to bake the whole pizza with prosciutto and mozzarella on top of it, serve it with water and wine on a table with a nice view of the sunset because that is what we imagine the product is supposed to look like eventually.</p><p>But let's view it from a different perspective. Why do users want our software product? If we use the pizza analogy, what is the <em>first slice of pizza</em> that we can give them? The slice that will not make users feel fulfilled yet and at the same time cause them to not die of hunger anymore. We can apply the same approach to the whole product backlog preparation and simplification of the individual items.</p><p>Frequently a user story as it is written solves multiple users' needs at once without us realizing it. Remember the email example from the post I mentioned above? A typical user story could say that when you view an email, it gets marked as read, it gets rich-text formatted, embedded images get displayed etc. That is how you would imagine such a feature to ultimately behave.</p><p>What happens, when we apply the marginal utility concept to that story? What is the <em>first slice of pizza</em> that we can develop and decide about the rest later? What aspect of that story has the highest <em>marginal utility</em> for the user? Most likely the ability to actually read the text in that email. The <em>marginal utility</em> of being able to read the content is typically greater than the one of rich-text formatting, image display, or marking messages as read. Suddenly it becomes obvious that the story can be broken down into more atomic slices.</p><p>By asking this question over and over again usually helps to make up the mind as to how worthwhile it is to invest effort into something. It also makes negotiations with stakeholders easier because it somewhat materializes the cost/benefit concept.</p><h2>Know the users</h2><p>As stated before, utility is highly individual and context-dependent. That is why the user stories start with <em> <q>As Bob the truck driver, I'd like to have...</q></em>. A software feature for one person will likely have a totally different value (utility) compared to another. That is the reason it is vital to know well who we are building the product for. To know their real-life problems.</p><p>Only then can we evaluate the marginal utility of our product's features relevantly <em>for them</em>. The capability to view images embedded into emails is going to give wildly different satisfaction to a clerk receiving simple instructions in the text compared to a gallery owner wanting to receive previews of paintings from artists.</p><p>When we know the audience we can reasonably decide how we can split backlog items into more atomic ones and identify what <em>the next slice of pizza</em> should be. That's also why getting real-world feedback as early as possible is so crucial for relevant decision-making. Describing utility highly contextual to a particular person is the reason why <em>user</em> stories are called <em>user</em> stories in the first place.</p><h2>Final words</h2><p>Managing the backlog well is a difficult job. We need to keep it meaningfully prepared, juggle with the item's values, compare the costs and returns. That's why it's good to take a chance and look at the same thing from a perspective by applying some basic economic concepts to it. I hope this sparked some inspiration for your own development process.</p> <br>#agile;#development;#project-management;#scrum
The Last Scrum Guide Update Last Scrum Guide Update<p>​​The updated scrum guide has been out for more than a year, so many have already written about it. But I would like to take this opportunity to share a few thoughts about the scrum guide as such and also comment on some of the features in the latest update. </p><h2>Is scrum guide underrated?</h2><p>The scrum guide is in my experience often overlooked by teams or organizations. I dare to believe I might know some of the reasons. When I was first learning about scrum and I was trying to live by it with my colleagues, we needed a lot of guidance. We needed a hands-on approach by our more agile-seasoned colleagues to actually help us set the basics and actually start working in the framework. We needed to discuss the nitty-gritty details of the daily work and all the various aspects of backlog management. We sought after organizational how-tos and best practices to wrap our heads around this interesting, yet somehow elusive concept of scrum. </p><p>Scrum is easy to understand but difficult to master. It is mainly a cultural shift compared to traditional project management and development approaches, so why is it so hard to get right? Sometimes the actual cultural shift is the culprit, but it is also demanding for organizational and planning discipline. </p><p>The actual nuts and bolts are often what teams struggle with and that's where they seek a lot of help in the earlier phases of their maturing. The scrum guide however does not give many answers in this regard. And that's why a lot of people don't find much practical use in reading that document. It seems to me it is rarely a go-to place for teams or scrum masters when searching for scrum answers.</p><p>But the scrum guide was never meant to be a detailed guide. And that is a good thing. Its purpose is to set the boundaries just where they are absolutely necessary, outline the philosophy, and leave the space for interpretation where the scrum team is supposed to bring in its brains and creativity. It tries to be as precise as possible without being taxative. And for this very reason, it needs to be minimalistic. (If only our legislators approached their work this way…)</p><p>In my opinion, the more the team matures, the less it should try to seek exact how-tos about living in scrum, but the more it should return to the bare basics - to the scrum guide.</p><p>That helps to gain some distance from the daily routines and undesired habits and look at their doing from the above to get rid of unnecessary habits and rather focus on the actual philosophical value than a process. Matured teams have a pretty good idea about the philosophy of scrum and want to live by it. Going back to the guide can be an enlightening experience for them. Approach the scrum guide as it's been triple distilled before it got its current shape.</p><h2>Recent updates</h2><p>At the end of 2020, the scrum guide received yet another update. Although some of the changes seem minor or sound just like a wording change, to me it seems like a good step towards helping to clear up several common misconceptions. You can find the changelog easily on the internet, so it is not my aim to cover the update extensively. I want to talk about a few particular changes, which I find the most interesting.</p><h3>1. Ditched the 3 questions for dailies</h3><p>Everyone knows the 3 questions that are the core of the daily - what did I do, what will I do, and do I have any impediments, right? So the guide got rid of them. Why is it a good thing? Because the ultimate team's purpose of the daily is to evaluate sprint backlog's achievability and to make decisions upon this evaluation. Decisions to make the team create the most value within the sprint (and to still meet the sprint goal). Maybe by dropping some sprint backlog items. Maybe by re-assigning backlog items between the developers. Maybe by helping each other out. </p><p>These questions were sometimes obscuring the actual goal of the daily. As if it was forbidden to talk about anything else other than that. Does it mean that these 3 questions should not be used from now on? No, it doesn't. It certainly is necessary that the devs share their progress and sync on it. If the team finds them useful, it will use them. The guide just suggests that these questions are not the pivotal point of the daily and give more freedom to the team to tailor the daily to their needs.</p><h3>2.Stressing the core scrum values and principles</h3><p>The guide now tries to be clearer about the core scrum values and principles of empiricism. It reminds us that being transparent, inspecting, and adapting based on the findings is a vital part of the process. This is as opposed to extensive planning and attempting to achieve perfection for the first time.</p><p>Commitment, openness, and respect are the values that shape the actual outcome. The often-used practices like estimating, tracing velocities, and plotting burn-downs are icing on the cake. But the team should be able to bring high value even without them.</p><h3>3. Team unification</h3><p>Formerly, scrum the guide defined a developer team and a scrum team. Scrum team = development team + scrum master + product owner. From now on, there is just a scrum team. </p><p>To me this is not just a cosmetic change. Sometimes the teams gained a dynamic of the product owner being an outsider. A customer for the team. Subliminally perceived as a competitor or a hindrance to the development team. In some teams, even the scrum master was seen as an outsider.</p><p>Team unification is an attempt to get rid of the us-and-them mentality. When perceived right, all the team members have a common goal to solve problems to create high business value. And the devs can (and should) be in close touch with the product owner to work out how to keep achieving that continuously. It needs to be clear that to the developers, the product owner is not an enemy, but someone who they can use to get answers, opinions, and business insights from, to be efficient. They can negotiate with him about the possible approaches to solving particular problems. When there is a good idea to achieve something in a more efficient or simpler way than originally intended, devs should understand that both them and the product owner will benefit from it. And the product owner should understand that too. They are teammates.</p><h3>4. Commitments for scrum artifacts</h3><p>The hierarchy of artifacts and their commitments is now clearer. A product has its goal. That determines the product backlog's priority. A sprint has a goal, which defines the sprint backlog. And finally, a product increment must meet a definition of done. This is nothing really revolutionary or entirely new, but more clearly formulated, something that most people intuitively already sensed and used.</p><p>In general I see this update as an evolution rather than a revolution. Or better said - another cycle of distillation. Cheers!</p> <br>#scrum;#agile;#project-management
SwiftUI and Architecture: State and Architecture: State<p>A new era has come to the mobile world. At least in the context of UI frameworks. What does this mean for your project? Will your architecture stand strong and allow for incremental adoption? Or will you have to resort to complete rewrite?</p> <h2>​​Welcome to the new old world</h2><p>The cornerstone of user interface development for iOS since its inception has been UIKit (or AppKit for macOS). It provides a mechanism to define window and view hierarchy, navigate between scenes, render content on the screen, and has tools for handling user interaction. UIKit was designed over a decade ago in the Objective-C world and leverages principles that were common back then, like delegates and inheritance. Functional elements of modern languages like Swift naturally lead to a declarative programming paradigm which is where SwiftUI steps in.</p><p>The SwiftUI framework was announced at WWDC 2019 and introduces the aforementioned declarative approach to writing UI code, favors composition, uses value types extensively and provides under the hood optimization. It completely changes how we reason about the UI and how we write the UI code. Its principles and design are inspired by React from the Javascript world, which dates back to 2013, so our thanks and a round of applause are in order for the JS community for working out its kinks!</p><p>Code written in SwiftUI is multiplatform and can be deployed to tvOS, macOS, and watchOS platforms. Interoperability with UIKit and AppKit helps with the transition even further.</p><p>Interestingly, a very similar approach also came to the Android world, known as Jetpack Compose. If you are more interested in this, it is well described in posts "Jetpack Compose: What you need to know", <a href="/Blog/Pages/compose-1.aspx"> <ins>part 1</ins> </a> and <a href="/Blog/Pages/compose-2.aspx"> <ins>part 2</ins> </a>, although since then some things inevitably changed. </p><p>Both of these technologies are ready for production use. Let's focus on what the arrival of SwiftUI means from the architectural point of view, especially regarding state.</p><h2>SwiftUI and state</h2><p>In SwiftUI, a view is a function of a state, not of a sequence of events changing some internal, encapsulated state. What does that mean in practice?</p><p>SwiftUI observes UI state and triggers re-rendering of the view on every change (with some smart optimizations happening under the hood). This is done by property wrappers that annotate UI state objects and/or Combine publishers. It's only up to you to model, hold, transform, compose and distribute the state.</p><p>The state can be perceived from many different angles, for example:</p><ul><li>what is rendered on the screen,</li><li>data that are persisted in the storage,</li><li>state that's spread across multiple screens or features.</li></ul><p>It is crucial to properly separate these kinds of states from each other, as some have a limited role in a merely encapsulated context, while others may span across multiple contexts and may serve the purpose of the source of truth.</p><p>Such a source of truth must be unambiguously defined and shared. Let's take a look at how the currently most discussed architectures approach this.</p><p> <strong>MVx architectures</strong></p><p>MVC was most commonly used in iOS applications back in the day. It got sidetracked with the advent of functional reactive programming and was replaced with MVVM and its derivative MVVM-C which specifies an additional layer for navigation. The place for View and Presentation logic is clear in those cases, but the Model layer has too many responsibilities, which might lead to big components that have too many concerns. In another case, the Model layer may contain only domain objects whereas the Presentation layer deals with networking, storage, business logic, and transformation of domain objects into renderable objects for the view on one side together with handling actions from the view on the other side. Huge ViewControllers with many responsibilities led to the joke saying MVC is short for Massive-View-Controller.</p><p>MVx architectures are not sufficient by their definition to design the whole system. They are merely a pattern for the presentation part of the system. Clean and robust applications may be written with MVVM as the only architecture tool in your toolbox but it requires strict discipline and proper decomposition. The architecture used often branches out into something more sophisticated than 3-layer architecture but with no clear boundaries that are defined somewhere between the lines.</p><p> <strong>Redux</strong></p><p>As the SwiftUI is inspired by React from the Javascript world, where React and Redux often go hand in hand, it's natural to think about how this is mirrored in mobile application development.</p><p>Redux is a mechanism to update and distribute state around. It cannot be considered as "architecture" as it does not answer the important questions</p><ul><li>how to protect the app from the outside world?</li><li>how to enable easy change of technologies and third-party dependencies?</li><li>how to define strict boundaries to isolate features?</li><li>where are the business rules defined?</li><li>which parts deal with navigation, presentation, networking, storage, user input, and so on?</li></ul><p>These discussed architectures do not address modeling and state sharing in complete detail, they are often either used in a poor way that is not very readable and sustainable, or in a way that inherently leads to a more complex architecture with a looser definition of responsibilities.</p><p>Although SwiftUI is a new player on the mobile playground, managing state is definitely not. Let's see if the old and traditional principles still have anything to offer in this new world.</p><h2>Lessons learned from history</h2><p>There are many patterns and principles that are timeless, namely two that enable to store and distribute state in a transparent way.</p><p> <strong>Repository pattern</strong></p><p>A repository is a design pattern that abstracts data access logic from business access logic by exposing the collection-like interface to access business entities. The actual implementation of the interface might communicate with the database, REST API, and what your project requires as long as it doesn't leak its details to the business domain interface.</p><p>Such a repository could easily be the source of the truth for each feature. Repositories obviously hold the state, but let's see how to distribute the same state to multiple parts of the application.</p><p> <strong>Dependency Injection</strong></p><p>Sharing state across features is as simple as sharing the same repository instance. Dependency injection frameworks help organize the dependency graph. Some use Service Locator patterns that abstracts instance resolution behind an abstraction layer. It reduces boilerplate code you would otherwise need with manual dependency injection. The resolution might cause runtime crashes if some requested instances are not registered. That's a downside that can you can handle with unit tests though.</p><p>You can also implement a shared repository using pure language without any dependency frameworks. The principle remains the same in both cases.</p><h2>Architecture and state</h2><p>It's important to design your system</p><ul><li>to be soft and malleable, so you're able to swiftly deliver changes that are desired,</li><li>but robust enough, so that you can be sure those changes are not going to cause unexpected behavior, </li><li>and clear enough so it's easy to navigate and doesn't grow over your head.</li></ul><p>Decoupling is critical to achieving that. To decouple views, view models, scenes, and what have you, you need to figure out how to share the source of truth across the app. If you mishandle it or don't think much about the state, you're going to have a hard time even with UIKit applications as it leads to coupling that results in code that's hard to test, read and reason about, for instance:</p> <img alt="MVVM" src="/Blog/PublishingImages/Articles/swift-ui-and-state-02.png" data-themekey="#" /> <p>ViewModels in this case do way too much. They pass state among each other which makes them difficult to test and harder to read. The source of truth for these data is also lost, it's unclear where the state originated and who owns it.</p><p>State management is not something new that came with SwiftUI, it's been here for decades, and there are no specific new architecture requirements. If you make features independent, inject your dependencies, test, and define the source of truth with a repository pattern, you can design your system to be easier to maintain and grow, regardless of which UI framework you pick.</p> <img alt="Clean Architecture" src="/Blog/PublishingImages/Articles/swift-ui-and-state-01.png" data-themekey="#" /> <p>There's a strict boundary between features in this example. ViewModels only transform data and actions between Views and UseCases. There is one clear source of truth for each feature. Isolation leads to reusability and testability.</p><p>State management was always important in app development, unfortunately often it was neglected or done poorly. Declarative UI concepts do not bring anything new to the table as they just explicitly accent what's important to handle well because the view is a function of a state.</p><h2>Old and new, together</h2><p>Breakthrough technologies such as SwiftUI don't come out that often, but that doesn't mean that your app and architecture should succumb to being completely dependent on the technology and/or derive itself from it. On the contrary, if you adhere to the separation of concerns and decouple your code, you achieve strictly defined boundaries and can start adopting those technologies without having to rewrite most of your app and even do so incrementally.</p><p>SwiftUI is a brand new technology, but that doesn't mean we can't benefit from timeless and classic principles that helped deal with many challenges over many decades. Old and new can go hand in hand together and complement each other to enable us to create brilliant apps.</p>​<br>#swiftui;#architecture;#state