<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Šimon Kručinin</title>
    <description>The latest articles on DEV Community by Šimon Kručinin (@easy-blunders).</description>
    <link>https://dev.to/easy-blunders</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1256412%2F9d14d040-68d9-46f2-aac8-50d542e79f12.jpeg</url>
      <title>DEV Community: Šimon Kručinin</title>
      <link>https://dev.to/easy-blunders</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/easy-blunders"/>
    <language>en</language>
    <item>
      <title>Kaleidoscope of iOS app architectures</title>
      <dc:creator>Šimon Kručinin</dc:creator>
      <pubDate>Mon, 29 Jan 2024 06:00:00 +0000</pubDate>
      <link>https://dev.to/easy-blunders/kaleidoscope-of-ios-app-architectures-516l</link>
      <guid>https://dev.to/easy-blunders/kaleidoscope-of-ios-app-architectures-516l</guid>
      <description>&lt;p&gt;&lt;em&gt;Surely there must be the best way to build an iOS app? Just search the internet for how others do it, or ask a professional.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Model-View-*
&lt;/h1&gt;

&lt;p&gt;The first thing you may hear about and probably start with is a family, or rather an evolutionary chain, of MVC, MVP, and MVVM. After all, Apple officially recommends MVC for UIKit, since it’s well known across the entire software development world, fairly simple, and separates logic from the UI. MVP then separates it a bit more; MVVM still more with a slight twist to it. I’m not going to describe the architectures as others have done a splendid job of it already. For example, &lt;a href="https://medium.com/ios-os-x-development/ios-architecture-patterns-ecba4c38de52"&gt;this timeless article by Bohdan Orlov&lt;/a&gt; or &lt;a href="https://swifting.io/2016/09/07/Architecture-Wars-A-New-Hope.html"&gt;this fun take&lt;/a&gt; on the essentials.&lt;/p&gt;

&lt;p&gt;What I’m going to do is comment based on my experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  MVC
&lt;/h2&gt;

&lt;p&gt;Makes sense for very small apps or experiments in UIKit. If the app starts to grow, it’s up for a rewrite. Not relevant for SwiftUI much, because there’s no “controller” anymore. UI is mixed with logic by default, so the starting point for SwiftUI apps is the “big ball of mud” architecture, which is fine for a prototype. Or you could look into the Atomic Design (see below) to structure your view components better and place logic in them strategically. After all, a SwiftUI view doesn’t have to render anything of its own. It can contain just logic and compose other views based on it. Akin to what React.js apps often do.&lt;/p&gt;

&lt;h2&gt;
  
  
  MVP
&lt;/h2&gt;

&lt;p&gt;Mostly superseded by MVVM.&lt;/p&gt;

&lt;h2&gt;
  
  
  MVVM
&lt;/h2&gt;

&lt;p&gt;Probably the most popular option out there. In combination with the Coordinator pattern, a.k.a. MVVM+C, this is a great starting point for any professional app. If the complexity grows, it can be scaled using additional software design patterns and separating concerns further. Also works well with SwiftUI: All you need is ObservableObject.&lt;/p&gt;

&lt;p&gt;While MVC and MVP strive to separate UI from logic, having display logic still mixed into the “logic” part, MVVM takes a step further. It separates view (UI + display logic) from the application logic. The so called View Model (a terrible name) has no notion of UI elements. It doesn’t reference any view, doesn’t enable any buttons, doesn’t fill in labels… It deals with pure logic: Fetches and formats data (for a display somewhere on screen), initiates tasks triggered by the UI actions, and contains some business rules, in a nutshell. It contains a state for a view. The view reads the state and adjusts accordingly. Very useful for unit testing.&lt;/p&gt;

&lt;p&gt;However, the definition of “the application logic” in this case is quite general. It’s everything not UI related. MVVM doesn’t help much there. View is separated, good. The rest can tie itself into a knot as far as the architecture is concerned, or rather unconcerned: Networking, data persistence, external events, form validation, sharing state, dependency injection, business rules… Do whatever you like. If the logic starts growing over your head, take a look at the Clean Architecture.&lt;/p&gt;

&lt;p&gt;Note: I’m avoiding the term “business logic”, as it may be misleading. Decisions on which REST endpoints to call and when, or which data to cache, for example, have nothing to do with business. In that sense, “business logic” could mean domain logic. Something end users are familiar with. Oftentimes though, it is used as an umbrella term for the application logic. I admit, the “application logic” isn’t that much better either. Is it all logic found in the app? What about displaying views? There are many kinds of logic. Still, I hope the context here is clear.&lt;/p&gt;

&lt;h2&gt;
  
  
  Difference between MVP and MVVM
&lt;/h2&gt;

&lt;p&gt;If you look at the diagrams often offered when explaining the two architectures, there is no difference. The concepts are quite similar. The devil is in the details. And there’s a fundamental distinction.&lt;/p&gt;

&lt;p&gt;In MVP, the Presenter drives the view. It has a reference to it and manipulates it on updates. It doesn’t only calculate the text to be displayed in a text field, for example, it also applies it to the component, albeit through an abstract interface. The Presenter is the View Controller split in two, taking care of more general parts of its responsibilities. When unit testing, the view has to be mocked in order to observe the output.&lt;/p&gt;

&lt;p&gt;In MVVM, the View Model knows nothing about the view. It exposes a state that is modelled roughly for the view’s purposes, but it doesn’t manipulate the view. It signals the state via reactive properties. So it can provide something like isSavingEnabled property, but it doesn’t enable or disable any buttons or add asterisks to the title. It is, in fact, an information model of a screen that can be rendered in different ways. The outputs can be observed directly during unit testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  MVI
&lt;/h2&gt;

&lt;p&gt;Model-View-Intent is more at home on the web and on Android. It sort of marries the UI/logic split and observable store concept I write about below, so it belongs to both camps, I think. It’s a question whether it does it well and whether it provides any additional value to the more mainstream alternatives. The one you should answer for yourself. I don’t have much experience with it and there aren’t that many good resources about it. The few original articles that proposed the idea are referenced here. Myself, I’m not too intrigued.&lt;/p&gt;

&lt;p&gt;The earliest mention I could find is by André Staltz on &lt;a href="https://staltz.com/unidirectional-user-interface-architectures.html"&gt;his blog&lt;/a&gt;, who was probably at the inception since he used the architecture for a JavaScript framework Cycle.js.&lt;/p&gt;

&lt;p&gt;Later it was &lt;a href="https://hannesdorfmann.com/android/mosby3-mvi-2/"&gt;adapted by Hannes Dorfmann&lt;/a&gt; for Android.&lt;/p&gt;

&lt;p&gt;To me it gives an impression like MVP and Redux had an affair and produced this unusual child by surprise.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Clean Architecture
&lt;/h1&gt;

&lt;p&gt;It all started with &lt;a href="https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882"&gt;this book&lt;/a&gt; by &lt;a href="https://en.wikipedia.org/wiki/Robert_C._Martin?wprov=sfti1"&gt;Uncle Bob&lt;/a&gt;, and &lt;a href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html"&gt;this blog post&lt;/a&gt;. The main ideas are separation of concerns and one-way dependencies.&lt;/p&gt;

&lt;p&gt;I’d say more important than architectures sprouting from the concept — famously VIPER and VIP — are the guiding principles.&lt;/p&gt;

&lt;h2&gt;
  
  
  VIPER
&lt;/h2&gt;

&lt;p&gt;VIPER goes beyond the separation of UI/not UI and actually addresses the logic part more thoroughly than the MVVM does. It’s a solid example of a practical application of the Clean Architecture. Here’s an &lt;a href="https://mutualmobile.com/blog/meet-viper-mutual-mobiles-application-of-clean-architecture-for-ios-apps"&gt;introduction by the authors&lt;/a&gt; at Mutual Mobile.&lt;/p&gt;

&lt;p&gt;It’s a good fit for larger apps and it scales well. It forces certain structure.&lt;/p&gt;

&lt;p&gt;If not approached dogmatically, but seen rather as an inspiration, it can guide an evolution of an MVVM+C app. View Model would replace the Presenter and would be further split into Interactor, a.k.a. Use Case, that would take care of some of the logic related to data marshalling and domain logic (business rules). The Interactor would communicate with services, leaving the state for the View Model. Interactors would support reuse of operations within a module, as they are not tailored to a specific view. They could be called from anywhere within a scope. Easy to shuffle functionality around different screens. As a bonus, View Models don’t need protocols, unless you want to unit test views, which are better covered by UI tests. Only views depend on View Models.&lt;/p&gt;

&lt;p&gt;Coordinators would already handle navigation, so no need for Routers. Assembly of units could be done by DI containers, which are better suited for the task anyway and can handle also other dependencies.&lt;/p&gt;

&lt;p&gt;Additionally, the &lt;a href="https://martinfowler.com/eaaCatalog/repository.html"&gt;Repository pattern&lt;/a&gt; is indispensable in governing the data queries and converting between domain and persistence data models. (The format of the data stored and used by the app logic is likely to diverge eventually. It’s a good idea to model them separately from the start.)&lt;/p&gt;

&lt;h2&gt;
  
  
  VIP
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://clean-swift.com/clean-swift-ios-architecture/"&gt;Another take&lt;/a&gt; on the Clean Architecture. Not sure how it meshes with SwiftUI. I suspect that if adapted, it would end up as a variant of an observable store solution (see below).&lt;/p&gt;

&lt;h1&gt;
  
  
  Observable Store
&lt;/h1&gt;

&lt;p&gt;There’s a category of architectures that promote separation of the app state into a standalone, passive store and unidirectional data flow. Since the main feature is the independent state, that is essentially a big data structure with no logic of its own that changes constantly and emits notifications about the changes, I call the concept as “observable store”. It fits naturally with state-driven libraries like SwiftUI or React.&lt;/p&gt;

&lt;p&gt;The allure of the concept lies in the idea of a centralized state that is easy to examine, persist, and test at any point in time. It is a data-complete description of the app; the rest is just a visual representation of it. The unidirectional data flow makes it easy to follow the UI updates. UI emits an action, that triggers some logic that lives in a separate place, eventually the logic updates the state, UI listens to the state and updates itself. No complicated ping-pong between UI and logic, no matter how complex and interconnected the UI is.&lt;/p&gt;

&lt;p&gt;The price to pay is more difficult traceability of code. Normally, there is a method that calls another method and that calls another method… Here, an event is emitted and that is handled somewhere by something, hopefully, hopefully just once. The logic can emit also other events. Prepare to hone your search skills to extreme. Scoping and sharing state needs to be approached very carefully, too. As anything can theoretically change any state if you lump it all together in a single store. If you structure your code neatly and consistently, maintain discipline, these are not big problems. It’s easy to make a mess, though.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Composable Architecture
&lt;/h2&gt;

&lt;p&gt;TCA for short. Very scalable, quite promising, quite popular. A decent alternative for MVVM enhanced by the Clean Architecture. You can learn more about it in a &lt;a href="https://pointfreeco.github.io/swift-composable-architecture/main/tutorials/meetcomposablearchitecture"&gt;Point-Free tutorial&lt;/a&gt; and on &lt;a href="https://github.com/pointfreeco/swift-composable-architecture"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Redux
&lt;/h2&gt;

&lt;p&gt;Originally created for React web apps. Difficult to navigate the code, messy side-effects. &lt;a href="http://reswift.github.io/ReSwift/master/getting-started-guide.html"&gt;ReSwift&lt;/a&gt; is a prominent implementation for iOS, although the project doesn’t show much activity anymore. There are others. &lt;a href="https://github.com/SwiftRex/SwiftRex"&gt;SwiftRex&lt;/a&gt;, for example.&lt;/p&gt;

&lt;h2&gt;
  
  
  MVI
&lt;/h2&gt;

&lt;p&gt;Mentioned already above.&lt;/p&gt;

&lt;h1&gt;
  
  
  Atomic Design
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://atomicdesign.bradfrost.com/chapter-2/"&gt;Atomic Design&lt;/a&gt; focuses on structuring UI in a reusable manner and that drives hoisting application-specific state and logic up. Although the AD doesn’t meddle with logic per se, it ties in nicely with the &lt;a href="https://phuoc.ng/collection/this-vs-that/stateless-vs-stateful-components/"&gt;stateful vs. stateless component concept, or container-presentational pattern&lt;/a&gt;. If you want to treat your SwiftUI app as mostly UI with a bit of logic sprinkled in, this is the way to go. But these principles are also applicable to any app that wants to structure its UI with less pain involved.&lt;/p&gt;

&lt;h1&gt;
  
  
  Common Topics
&lt;/h1&gt;

&lt;p&gt;All these architectures try to structure code in a “better”, ultimately more efficient, way. “Better” can mean different things to different people. So rather than bounce around fancy names and expect a revolutionary concept in every proposal, let’s examine the recurring underlying topics they aim to address.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separation of concerns
&lt;/h2&gt;

&lt;p&gt;Is about splitting the code to smaller parts to be able to reason about them easier. Less concerns, less circumstances we need to consider, simpler to make a change. Units are more focused. Spaghetti code is harder to write. It basically reduces time to understand the code locally and to make a change.&lt;/p&gt;

&lt;p&gt;Lack of any separation is referred to fondly as “big ball of mud”.&lt;/p&gt;

&lt;p&gt;Every architecture mentioned above addresses the separation to a varying extent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testability
&lt;/h2&gt;

&lt;p&gt;Breaking down components to small enough and relatively simple units that can be covered by relatively simple &lt;em&gt;unit&lt;/em&gt; tests. It’s much, much easier to robustly test tiny pieces of logic a hundred times than write a couple of tests to verify a component with a hundred of gnarly conditions. It’s easier to maintain, too.&lt;/p&gt;

&lt;p&gt;Exposing internals for testing without making them a part of API can be tricky without proper decomposition. Have you ever seen comments like: Don’t use this method! It’s just for testing!&lt;/p&gt;

&lt;p&gt;Code covered by unit tests is more reliable as it has been re-examined carefully after the implementation. It also provides a regression safety net against continuous changes. Not mentioning benefits of treating tests as usage documentation. Bottomline: Fewer bugs, duh.&lt;/p&gt;

&lt;p&gt;MVP, MVVM, and VIP take a step towards better testability. VIPER and observable store architectures, especially TCA, take more steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data flow a.k.a. who calls whom
&lt;/h2&gt;

&lt;p&gt;Even with a good separation of concerns it’s possible to weave some spaghetti. UI calling logic, which calls back to the UI, that in turn calls to navigation and passes some dependencies provided by the logic, navigation updates data storage… Sounds twisted? Add cascading changes to the mix.&lt;/p&gt;

&lt;p&gt;Most architectures are concerned with the data or control flow. They offer lovely diagrams of it. Unidirectional flow got a lot of attention lately. Meaning a unit sends events to a single other unit and listens to another single unit, so units are connected in an ouroboros. It’s easy to reason about, because inputs arrive from one place and outputs depart to one place. There’s no coordinator or controller. Observable stores (TCA, Redux, MVI) follow this pattern.&lt;/p&gt;

&lt;p&gt;Why would you care about the data flow? To have a clear answer to what caused which changes on screen. With one source at a time, run-time changes are much better traceable through the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transparency
&lt;/h2&gt;

&lt;p&gt;What’s going on in the app at any given time? In order to debug efficiently, we need to examine the app’s state. To enable a straightforward examination, it makes sense to extract the state from various components and centralize it in a store. That store can be persisted, recorded, and observed. Mutations of the store can be regulated and actions that lead to mutations can be recorded and replayed. Following this concept, we can have a detailed insight into the app’s internals and even capture tricky scenarios.&lt;/p&gt;

&lt;p&gt;This is supported by observable store architectures (TCA, Redux, MVI).&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing state complexity
&lt;/h2&gt;

&lt;p&gt;The state can be modelled differently and can get very complex. Multiple properties can pertain to one state and mutate together. Some transitions may be invalid. If you look at the state as a plain data structure, there can be a multitude of variations in its values. In reality however, the combinations are limited. That’s where finite state machines (FSM) come to the rescue, to manage that complexity, to make possible states and transitions explicit.&lt;/p&gt;

&lt;p&gt;TCA makes use of FSMs. There are also separate frameworks like &lt;a href="https://ilya.puchka.me/implementing-features-with-reactivefeedback/"&gt;ReactiveFeedback&lt;/a&gt; and &lt;a href="https://github.com/sergdort/CombineFeedback"&gt;CombineFeedback&lt;/a&gt; that can be plugged in. There’s a &lt;a href="https://www.vadimbulavin.com/modern-mvvm-ios-app-architecture-with-combine-and-swiftui/"&gt;good article&lt;/a&gt; by Vadim Bulavin that showcases the CombineFeedback in action.&lt;/p&gt;

&lt;p&gt;Careful though, on a small scale it could be an overkill. It could result in a boilerplate full of switches that is hard to read. You may live happily with enums and good old methods instead of events in your view models.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reusability
&lt;/h2&gt;

&lt;p&gt;There’s certainly an appeal to reuse UI elements or pieces of logic to shorten the development time and avoid bugs by utilizing mature software. Not many architectures address this need though.&lt;/p&gt;

&lt;p&gt;In VIPER, Interactors could be made for reuse to an extent. Atomic Design, TCA, and MVI are designed with reuse in mind. Observable store architectures in general are well decoupled and can facilitate reuse of logic more easily.&lt;/p&gt;

</description>
      <category>technology</category>
      <category>ios</category>
      <category>mobiledevelopment</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Teal teams at differently structured organizations</title>
      <dc:creator>Šimon Kručinin</dc:creator>
      <pubDate>Mon, 22 Jan 2024 06:00:00 +0000</pubDate>
      <link>https://dev.to/easy-blunders/teal-teams-at-differently-structured-organizations-4ldk</link>
      <guid>https://dev.to/easy-blunders/teal-teams-at-differently-structured-organizations-4ldk</guid>
      <description>&lt;p&gt;&lt;em&gt;Why don’t you build a team that will work autonomously and solve our main problems, while performing well above everyone else? And yeah, make them work with the rest of our company. Easy peasy.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;First things first, Frederic Laloux made a study of how different organizations across the world are structured and published his discoveries in a book — &lt;a href="https://www.reinventingorganizations.com"&gt;Reinventing Organizations&lt;/a&gt;. He categorized them into five broad categories and labeled them by color. Roughly summarized, from autocracy, through master-servant, measured efficiency and business value, to mutual consensus models, culminating into the latest emerging one — autonomous self-organization, a.k.a. teal organization. If you haven’t heard about it, definitely give it a read. It provides a fresh perspective.&lt;/p&gt;

&lt;p&gt;Now let’s think smaller. Scale down from thousands of people to a Scrum team. Imagine a group to whom you designate a responsibility, explain constraints, provide feedback, and measure its output and then… simply leave them alone. They will deliver what you need. Sounds like a fairy tale? It isn’t. People have the natural ability to self-organize to achieve what they need to achieve on their own. How do you think clans and tribes operated? If you set up the environment, explain the expected ways of working, give a little time and guidance, the team will form a self-contained organism that will optimize towards its prosperity. The prosperity translating into different things: money earned, amount of positive feedback, user satisfaction, good output metrics, solved problems, internal feeling of happiness… It does require a certain mindset, culture, and competence to raise a competent team, but good news is: Once established, most of it can be learned by newcomers. Another good news: You don’t need to get too involved. Just set the expectations, communicate clearly and consistently, tweak the prosperity factors. The team will do the rest.&lt;/p&gt;

&lt;p&gt;Sounds good? In a small company, this is well achievable. After all, there’s only livelihood of a few people on the line. But how does it fit a larger organization? Having no control over the produced results is scary, however great they may be at the moment. Never mind that any control at any given time is an illusion for anything slightly complex. In my opinion, the best you can hope for is a perfect alignment and motivated people. Still, if you’re a manager, your job is to understand the reality as best and as fast you can and react to it quickly. You are responsible for the bigger picture. It’s hard to put your career in the hands of others, especially if you don’t understand how they work.&lt;/p&gt;

&lt;p&gt;So how would a teal team fare in a larger company? It would likely succeed short-term, showing exceptional results. Then it would draw attention, scrutiny, and fear of not being able to maintain the high performance bar. The more I observe different companies from within, the more I become to realize: Teal teams would not survive unless left to their devices or unless having teal-aware leadership. Once their autonomy is compromised, they’re gone. Their ability to self-organize, to take ownership, to make independent decisions becomes damaged and they cannot function self-sufficiently anymore. Involvement from outside becomes necessary, which further increases the damage.&lt;/p&gt;

&lt;p&gt;Autocratic and hierarchical structures would simply assert control for the power sake. There’s a strong desire to control the important decisions. Value and performance measurement approaches tend to get narrow-minded, focusing on things that can be easily measured and a simplified model of the output. Subtle, long-term value is easily lost when observing day-to-day, week-to-week indicators. A teal team could exist in such environment, but would likely get misaligned and would not prosper. On the other hand, using metrics as an informal indicator of the team’s health is not a bad idea. The dangers are micromanagement and short-sightedness. Democratic or consensus-based structures, in general, are ridden by decision paralysis. They also  tend to force their values and operation model on all levels. This would interfere with a teal team’s ability to self-organize and make qualified, independent decisions by a single team member. Responsibility and ownership are often diluted if spread over a larger crowd.&lt;/p&gt;

&lt;p&gt;All in all, I would only attempt to build a teal team if there’s understanding top-tier leadership, compatible culture, or as a separate business. Otherwise, it’s best to stick to the model, by which the company operates, and let the high-rung leadership play with company transformations. Autonomy is a luxury.&lt;/p&gt;

</description>
      <category>teamwork</category>
      <category>teal</category>
    </item>
    <item>
      <title>Team building</title>
      <dc:creator>Šimon Kručinin</dc:creator>
      <pubDate>Mon, 15 Jan 2024 06:00:00 +0000</pubDate>
      <link>https://dev.to/easy-blunders/team-building-4b9a</link>
      <guid>https://dev.to/easy-blunders/team-building-4b9a</guid>
      <description>&lt;p&gt;&lt;em&gt;What are the most important things in a high-functioning team?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We had a team building recently and it was intense. 17 people gathered together at a rural location for a day and a half of non-stop activities.&lt;/p&gt;

&lt;p&gt;Seriously, I got up at 7:00, got into shape, picked up several of my colleagues and drove us for an hour to a village with a huge wigwam. Lightning-fast breakfast and ready for introductions at 9:00. After an ice-breaker and a signed disclaimer about our health condition, we were rushed outside and split into 3 groups. Groups meant to solve problems: build a square with a long rope, blindfolded, extract a bucket full of water from the center of a large circle without touching the ground inside the circle, navigate through sparsely scattered wooden platforms given 3 heavy logs and a rope while not touching the ground. The 3 tasks had different conditions. For the square, we had a planning phase and only 1 try for execution. With the bucket, we could iterate, practice the approach. On the platforms, only a couple of people could actually do something at a time.&lt;/p&gt;

&lt;p&gt;Lunch. No longer than an hour.&lt;/p&gt;

&lt;p&gt;Back outside, split into 2 groups, playing sort of chess. With a caveat. There was a manager sitting inside, who couldn’t go outside. S/he had a supervisor who ran back and forth to facilitate communication between the manager and the team in the field. And the team in the field, a few minutes away if running, was crammed into a tight grid outlined on the ground, enjoying cold, windy weather and a drizzle.&lt;/p&gt;

&lt;p&gt;To be honest, I didn’t know we could choose the strategy. I thought the rules were set. I just ran between the manager and the team trying to sync them and pass on instructions. We went straight for the top-down approach in our group while people were freezing outside. The game went slowly, but fairly well. We eliminated 2 cones and outsmarted the rest, so 4 people almost passed to the other side. Except we forgot to track time and in reality: 0 points. No one managed to pass in time. Guess what the other group did? That’s right, they let the people in the field play by themselves, and they scored points.&lt;/p&gt;

&lt;p&gt;I think our team could have started to play by themselves instead of waiting, too. They had initiative and good ideas. But we started to give instructions by default and it set the mode of cooperation. That they didn’t have clear information about the goals didn’t help either.&lt;/p&gt;

&lt;p&gt;We followed by an evaluation session after the game, inside, when people shared their experiences. Needless to say our “workers” were pissed.&lt;/p&gt;

&lt;p&gt;With no time to spare, another task. We had to rescue an egg from a space flight gone wrong. Er… to prevent breaking when dropped from a 4-meter altitude. We had a limited amount of paper, duct tape, plastic straws, thread, and creativity. 2 eggs to risk their fate in our contraptions.&lt;/p&gt;

&lt;p&gt;During many successful and some not-so-successful landings it was dark already. We rushed for an opulent buffet dinner afterward and had about an hour to eat and rest. The day was not over yet. We still had an activity ahead of us, shrouded in mystery. It was called The Day of the Triffids.&lt;/p&gt;

&lt;p&gt;We went outside, into the darkness, got helmets, got blindfolded… and were forbidden to speak. Then for an hour and a half, roughly, we were led in a hapless, disoriented file across fields, over ditches, through bushes, and under fences. Any instructions were given only by touch, as we learned later, by different people rotating as the leaders. Our trust was tested, which was exactly the point.&lt;/p&gt;

&lt;p&gt;We finished at 21:30, with casualties claimed only by morale. I drank one beer and opted for sleep at 22:00 instead of a midnight mingle. It was a wise choice.&lt;/p&gt;

&lt;p&gt;Breakfast the next day started at 8:00. We had to vacate our rooms. At 9:00 we already sat down in a group to evaluate our evening stroll. Everyone shared how their level of trust changed during the exercise and what they wished for when they were marching into the unknown. We had some profound learnings.&lt;/p&gt;

&lt;p&gt;The last activity tested our fitness — physical and mental. We had to run all over the place to gather animal cards to form certain combinations and score points. It was a contest between 2 teams. The one with the most points won. I ran at least for 36 minutes, as fast as I could without breaking my neck, taking only short breaks in between. In the end, most of us runners were exhausted. It was a relief to sit down for a while and evaluate our interactions in the game.&lt;/p&gt;

&lt;p&gt;Then lunch, then a drive home. As I wrote, intense.&lt;/p&gt;

&lt;p&gt;Over a month later, here I am, thinking: So how was it? It was worth it. I would do it again. Although this time I would maybe drop some of the problem-solving activities or stretch them over the entire two days, and spend more time talking to my colleagues instead, learning more about their lives and interests. It doesn’t always have to be about work or solving problems.&lt;/p&gt;




&lt;p&gt;What are the learnings? What are the main factors for a group of people to deliver the best results they can?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Trust.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Trust enables cooperation. Without it, the best you can hope for is individuals working on individual tasks, passing the results to each other with different amounts of friction. If you’ve ever dreamed of colleagues pulling towards the same goal single-mindedly, this is the answer. Build trust.&lt;/p&gt;

&lt;p&gt;It is not a given. It requires work and encouragement. People usually need to know what to expect and whether they can rely on each other. Hence bonding and forming relationships helps them to adjust their expectations and secure assistance in the future. Getting to know each other informally, team buildings, situations that require mutual dependence can go a long way.&lt;/p&gt;

&lt;p&gt;As much as it is important among peers, trust is also paramount towards leadership. How much would you invest in the team where the leader signals to you that you’re replaceable (you most likely are, most of us are, but still) or reduces you to a KPI number? What about changing directions every 2 weeks, or not communicating at all? Does that inspire confidence? Does s/he even know your name? Incompetence or disregard makes people wonder whether they are being marched to a feast or a slaughter, and they adjust accordingly. The ability to retain top talent and keep the team motivated can be very much attributed to competent leadership. If that person crystallizes from within the team, s/he has somewhat easier going. The trust is already there.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cooperation.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now that you have trust, people will spontaneously team up to solve hard problems, ask for help, and provide ready advice, right? Hold your horses. Trust is necessary for meaningful, long-term cooperation, but the former doesn’t automatically yield the latter. People may still happily work “together alone” and not know any better. It could go like this: I’m taking this ticket, you take that ticket. When we’re done, Joe over there will test it, maybe next sprint. Sounds familiar? Many teams work like this. It produces results, just slower and usually in worse quality.&lt;/p&gt;

&lt;p&gt;How about this approach: Let’s design or review the feature together. What needs to be built? What are your ideas? Does everyone understand the logic? Here, we’ll need these pieces, this interface, such and such acceptance criteria, logic can branch like this, see where the complexity lies? Let’s focus on that. That part will be complicated; let’s put at least a couple of folks on that in a group effort (pair programming, anyone?). Have you fallen behind because of an unexpected problem? What’s the hitch? Mark, can you take a look, too, or take over if needed? Hey guys, how do you intend to implement that thing? I’m writing a test for it and I need to know the details. Everything done within the sprint, different solutions considered, code expertly reviewed, tested, documented, follow-ups outlined. It’s possible. I’ve experienced the miracle and now can testify to it.&lt;/p&gt;

&lt;p&gt;It’s rare though and difficult to set up from scratch because of a certain mindset. The mindset usually goes like: Why do we need more people on a task that can be performed by one person? Isn’t it expensive?&lt;/p&gt;

&lt;p&gt;I think the answer is the same as to why you would hire a skilled craftsman with an outstanding track record to build your precious item albeit charging more rather than a student who would ask only for a fraction of the price. And there’s no guarantee the student would be cheaper at the end (provided you really want your item built as intended).&lt;/p&gt;

&lt;p&gt;Such cooperation also requires responsibility and competence, besides trust.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Room to make mistakes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The team is bonded, working together… What can go wrong? Sooner or later something usually does. And that’s life. A bug, an honest mistake, not enough training, infrastructure malfunctions… Heck, even a wrong design choice. Can you afford it?&lt;/p&gt;

&lt;p&gt;Well, I hope so. Otherwise, it’s walking knee-deep in the sand and innovation paralysis for you.&lt;/p&gt;

&lt;p&gt;The point is: To come up with better solutions, you need to iterate. To iterate effectively, you should fail fast. If you’re afraid to fail, you will avoid trying new things. If you don’t try new things, you fail to adjust to the real need, as the world outside changes constantly. So by punishing the team for failure, you will hurt whatever product you work on.&lt;/p&gt;

&lt;p&gt;The team will instinctively react to feedback. If the message is not to fail, they will simply eliminate the situations that lead to failure, i.e. everything unknown, i.e. everything new. What if failing were acceptable, with emphasis on quick detection and fixes? Imagine that.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Autonomy.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you hire a competent team to do fairly complex work, let them do their job. Why would someone think s/he is more qualified to make a decision without knowing the exact situation, which is very difficult to get understanding of in a timely fashion, and without having the expertise? Isn’t it more efficient to teach the team to make decisions that align with your goals? Power games aside.&lt;/p&gt;

&lt;p&gt;Interfering with how the team operates, taking away ownership of responsibilities, fear of losing control will drastically affect the results as well as motivation. Think about it this way: To take full ownership of the results, one needs to have free hands to make the decisions that lead to the results.&lt;/p&gt;

&lt;p&gt;Here’s where management as opposed to leadership can do real damage. If a team doesn’t perform to satisfaction, can it be due to misalignment rather than incompetence? If it’s incompetence, you’re likely to be better off re-building and re-training your team anyway. I have an outrageous proposition: If you’re missing alignment, give your team &lt;em&gt;more&lt;/em&gt; responsibility. Let them feel the full wrath of it.&lt;/p&gt;

&lt;p&gt;Do they break things often and users are complaining? Let the team use the product as users would. Let them read the feedback and respond apologetically.&lt;/p&gt;

&lt;p&gt;Do they work too much on things that do not bring money in? Let them manage their own budget, aligning their profits with the company’s profits or whatever value you want the team to produce. They will re-orient towards that promptly.&lt;/p&gt;

&lt;p&gt;If you think of it, it’s the only way to learn. Exposure to the problem.&lt;/p&gt;

&lt;p&gt;Resorting to patching things — allocating a manager, putting the QA department in charge, moving in another team to troubleshoot, etc. — will only insulate the team from reality. Now the manager, QA, another team is responsible for the results. So how is it better? It can only work short-term.&lt;/p&gt;

&lt;p&gt;Team members, if trained well and motivated, can make excellent decisions; far better than any single person would. It is humbling to realize and easy to underestimate.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Clear communication.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Even the best team will produce a useless trinket if they don’t know what they’re building. But it’s not just about what. It’s also about why, when, under which constraints, the bigger picture, and many other things. If you want the team to deliver something, tell them clearly what you want. Then again, and again, and again… Once is never enough.&lt;/p&gt;

&lt;p&gt;Progress, feedback, goals, alignment, culture echoed throughout. It’s easy to lose direction in a group, focusing on something slightly different than the person next to you. There are different interpretations, conjunctures, personal opinions, loss of attention, or misunderstandings. So yeah, expect confusion and battle it with clear, consistent messaging, at the right time.&lt;/p&gt;

&lt;p&gt;The only thing worse than the lack of information is an abundance of disinformation. Or is it the other way around?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Predictability.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At this point, we have an amazing, self-sufficient, cooperating team that knows what to do and when to do it. Surely this must be the pinnacle of awesomeness. Success is guaranteed. Let’s consider one more thing.&lt;/p&gt;

&lt;p&gt;The team is communicated a certain message, but the actions may not match. It can come from the leadership or the customer… For example a prompt from the leader: We’d love to hear your ideas. Please, bring them forward. Then they’re all shut down with a “thank you”. Or from the customer: I’d like to see some innovative designs, sure. I don’t like this one, nor this one, nor this one. Can it be more like what we have, but with rounded corners?&lt;/p&gt;

&lt;p&gt;How do you think it will turn out?&lt;/p&gt;

&lt;p&gt;Sometimes even the message may be accurate, but the directions change all the time. Without predictability, knowing what to expect, uncertainty settles in pretty fast. The trust crumbles and we’re back to square 1.&lt;/p&gt;

&lt;p&gt;The team may not know where they are going, but with a steady pace and the leadership they can rely on, they will be confident they’ll reach a wonderful destination.&lt;/p&gt;




&lt;p&gt;Learning all that I still have a question: What did I get out of the team building, personally?&lt;/p&gt;

&lt;p&gt;Let’s see… Change of scenery, free food, unique experiences I’ll remember for some time, deeper connection with my colleagues, better understanding of their behavior in certain situations and my adjusted expectations, clearer understanding of the components that make for great teamwork. Not bad, huh?&lt;/p&gt;

&lt;p&gt;Don’t be shy, team-build. &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t4H1PAnt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/1f609.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t4H1PAnt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/1f609.png" alt="😉" width="72" height="72"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>teamwork</category>
      <category>teambuilding</category>
    </item>
    <item>
      <title>Unique IDs</title>
      <dc:creator>Šimon Kručinin</dc:creator>
      <pubDate>Sun, 14 Jan 2024 18:34:44 +0000</pubDate>
      <link>https://dev.to/easy-blunders/unique-ids-4l66</link>
      <guid>https://dev.to/easy-blunders/unique-ids-4l66</guid>
      <description>&lt;p&gt;&lt;em&gt;Let's make our IDs truly unique. Easy!&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TL;DR Use UUID v4.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;How can we generate actually unique IDs for our entities on client?&lt;/p&gt;

&lt;h2&gt;
  
  
  On a single device
&lt;/h2&gt;

&lt;p&gt;Let's start this exercise with the simplest solution that comes to mind: ID is a number that we increment by 1 each time we generate a new one. Easy enough. But there's a technical limit. The number will eventually overflow and start generating the same values or fail. In reality though, if we choose a big enough representation, like a 64-bit integer, for example, most applications will never exhaust the limit. 2ˆ64 = 18,446,744,073,709,551,616 (over 18 quintillions) unique entities could take several lifetimes to create. However, this approach requires that we remember the last generated number, i.e. we need to persist the last value. Can we have unique IDs without persistence?&lt;/p&gt;

&lt;p&gt;How about randomly generated numbers? &lt;a href="https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)"&gt;UUID version 4&lt;/a&gt; is considered unique enough by experts. Indeed, the chance of finding a duplicate within 103 trillion version-4 UUIDs is 1:1,000,000,000. But notice it is not zero. It may well happen that the same number will be generated even let's say on the next attempt; it's just extremely rare. Probably rarer than &lt;a href="https://en.wikipedia.org/wiki/Single-event_upset"&gt;having cosmic radiation affect your program&lt;/a&gt;. This is an issue with any randomly generated number -- since they're random, there's a probability they will produce collisions. Can we do better?&lt;/p&gt;

&lt;p&gt;We can. We can look to the ever-increasing system clock and follow a similar approach as &lt;a href="https://en.wikipedia.org/wiki/Snowflake_ID"&gt;Snowflake ID&lt;/a&gt;. On a single device/installation the machine ID is always the same, so we can drop it. We take the timestamp and add an in-memory counter, which we don't need to persist. It's fine that the counter restarts on app re-launch. We only need to differentiate between IDs happening at the same instant. The timestamp can even be less granular, like seconds or milliseconds only. The counter can overflow (i.e. restart) at will, as long as it has sufficient size. How many entities an app would create in an instant anyway? I'd say much less than over its entire lifetime. So we could end up with something as simple as: &lt;code&gt;ID = timestamp + sequence number&lt;/code&gt;. With one problem. The clock on client can be modified by user and thus it is not reliable. We can't control the clock.&lt;/p&gt;

&lt;p&gt;We could work around it. We can store the last used timestamp and compare it with the timestamp on the next generation. If it's not growing, i.e. it's equal to or bigger than the latter timestamp, it's been tampered with. We can increase and store our clock change counter and proceed as before, with the ID being: &lt;code&gt;ID = clock change counter + timestamp + sequence number&lt;/code&gt;. It has one downside though. We need persistence again to store the last timestamp and the clock change counter. Back to square one, which is way simpler.&lt;/p&gt;

&lt;p&gt;So what's the best approach if we want to avoid persistence? I think the UUID is a good start. Then it's about storage policy. If we accept the fact that collisions may happen, but are very rare, we may consider them so rare that we don't need a recovery strategy. We just need to identify them and fail. Thus, once we create an entity and generate an ID for it, when we try to add it to a collection where identity matters or save it to persistence storage, we should check whether an entity with the same ID already exists and if so crash the app, making the user repeat the operation. If the chance of that actually happening is so infinitesimally small to affect one or two users once over several years, why even bother to support a technical solution for recovery? Many persistence frameworks (databases) make the task even easier by distinguishing create and update operations. They already check IDs on create. For those that only support &lt;a href="https://en.wikipedia.org/wiki/Merge_(SQL)#Synonymous"&gt;upserting&lt;/a&gt;, we should check manually in code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Across a distributed system
&lt;/h2&gt;

&lt;p&gt;In a regular server-client application that supports multiple clients per user, the situation is more challenging. Imagine we allowed our users to start locally, then they could eventually synchronize their data to a server under an account, connect a different client, e.g. a mobile app on a different device, download data there, share it for a while across devices, then unenroll one device and later enroll it again. How unique is that?&lt;/p&gt;

&lt;p&gt;Sadly, IDs generated on one client are more likely to collide with IDs from another client. Even if there's not much data overall and we wanted to take the previous approach of identifying collisions and failing, it wouldn't work well here. The data is already created and persisted on client. If the server refuses synchronization, without a strategy for amending IDs, the data would get stuck on a device and wouldn't propagate across the system. No matter how many times the user repeats the process. This calls for a coordination authority.&lt;/p&gt;

&lt;p&gt;The server can ensure unique IDs. One way is to make IDs hierarchical, for example &lt;code&gt;ID = installation ID + local entity ID&lt;/code&gt;. The client can negotiate a unique installation ID (because the device ID is not always available for security reasons) with the server when enrolling. But there's a number of problems like support for changing the installation ID on enrollment, identifying previous installations on re-enrollment to avoid duplication of data, and similar.&lt;/p&gt;

&lt;p&gt;There's a better way. The server can generate its own IDs for new data. Hence the globally unique ID in the system could be: &lt;code&gt;ID = server entity ID ?? local entity ID&lt;/code&gt;. In practice probably a tuple &lt;code&gt;ID = (server entity ID, local entity ID)&lt;/code&gt;. Before the data is uploaded to the server for the first time, the local ID should be unique to the given installation. Afterward, the server ID is enough to identify an entity across the system. So far so good on paper.&lt;/p&gt;

&lt;p&gt;Consider the mechanics practically:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The client generates a local unique ID. ✅&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sends new entity with the ID to the server. ✅&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The server generates a new, globally unique ID to avoid conflicts between clients and stores the entity. ✅&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The server communicates the new ID back to the client, but the connection drops. ❌&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The client sends the same entity to the server again, only with the local ID. ✅&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The server creates a new record, duplicating the entry. ❌&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Communication between the server and clients may fail. How can we ensure the IDs are kept consistent?&lt;/p&gt;

&lt;p&gt;The installation ID can still help us here. We can consider a combination of &lt;code&gt;installation ID + local entity ID&lt;/code&gt; unique. If we keep record of the installation ID for each created entity (i.e. the client that uploaded the entity), we can then doublecheck an entry for the ID pair doesn't already exist. Then resolve the conflict if needed.&lt;/p&gt;

&lt;p&gt;That's easy, right?&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>technicaldesign</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Atomic sync blocks in Swift</title>
      <dc:creator>Šimon Kručinin</dc:creator>
      <pubDate>Mon, 08 Jan 2024 07:00:00 +0000</pubDate>
      <link>https://dev.to/easy-blunders/atomic-sync-blocks-in-swift-47f</link>
      <guid>https://dev.to/easy-blunders/atomic-sync-blocks-in-swift-47f</guid>
      <description>&lt;p&gt;&lt;em&gt;We will access state from different threads synchronously and do it in a safe manner. That must be easy!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When considering concurrent access to data (a.k.a. state, a.k.a. variables) in Swift, from different threads, the usual practice is to use &lt;a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency"&gt;Structured Concurrency&lt;/a&gt; or &lt;a href="https://developer.apple.com/documentation/DISPATCH"&gt;Grand Central Dispatch&lt;/a&gt; (Dispatch Queue, anyone?). Combine and other reactive frameworks also provide support. But there’s a catch. These are all asynchronous APIs, meaning that if I call it now, I’ll get results sometimes later. What if I need the result now and continue some logic based on it? What if I don’t use async/await tasks everywhere yet?&lt;/p&gt;

&lt;p&gt;Well, Dispatch Queues have also &lt;code&gt;.sync()&lt;/code&gt; method, but from experience it’s best to avoid it. We don’t always have the luxury of knowing which Dispatch Queue we’re currently running on and calling &lt;code&gt;.sync()&lt;/code&gt; on the same queue is a certain death (or deadlock).&lt;/p&gt;

&lt;p&gt;Certainly, the code can and should be restructured to run asynchronously if thread safety is needed. We should rewrite our codebases towards modern approaches. Rainbows and unicorns await those who always do all the right things. Using Structured Concurrency or GCD is still the best practice, no doubt about it. But sometimes we just need that sync block in our test or a routine already running in background and we’re willing to wait for it. Can we make it happen, please?&lt;/p&gt;

&lt;p&gt;Yes, we have &lt;a href="https://developer.apple.com/documentation/os/osallocatedunfairlock"&gt;OSAllocateUnfairLock&lt;/a&gt; (iOS 16+) or &lt;a href="https://developer.apple.com/documentation/foundation/nsrecursivelock"&gt;NSRecursiveLock&lt;/a&gt; (iOS 2+) at our disposal. Use them as mutexes to guard a critical section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let myLock = OSAllocatedUnfairLock()
myLock.withLock {
    consistentState1 = "Some"
    consistentState2 = "information"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Foundation

let myLock = NSRecursiveLock()

func changeState1(_ value: String) {
    myLock.lock()
    consistentState1 = value
    myLock.unlock()
}

myLock.lock()
changeState1("Some")
consistentState2 = "information"
myLock.unlock()

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, there’s a &lt;a href="https://swiftrocks.com/thread-safety-in-swift"&gt;great summary&lt;/a&gt; of available thread safety tools by SwiftRocks.&lt;/p&gt;

</description>
      <category>technology</category>
      <category>ios</category>
      <category>swift</category>
    </item>
  </channel>
</rss>
