<?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: Futurice</title>
    <description>The latest articles on DEV Community by Futurice (@futurice).</description>
    <link>https://dev.to/futurice</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%2Forganization%2Fprofile_image%2F3021%2F41011d05-9976-4ed6-a82b-909914599c45.png</url>
      <title>DEV Community: Futurice</title>
      <link>https://dev.to/futurice</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/futurice"/>
    <language>en</language>
    <item>
      <title>Bringing Back the Technical Excellence: Rules of Thumb for Effective Software Lifecycle Management</title>
      <dc:creator>Niko Heikkilä</dc:creator>
      <pubDate>Fri, 19 Nov 2021 07:58:16 +0000</pubDate>
      <link>https://dev.to/futurice/bringing-back-the-technical-excellence-rules-of-thumb-for-effective-software-lifecycle-management-12nc</link>
      <guid>https://dev.to/futurice/bringing-back-the-technical-excellence-rules-of-thumb-for-effective-software-lifecycle-management-12nc</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;In software, legacy code is a code that runs in production.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Don't you love the defeatist attitude of this quote? You might have stumbled upon it on many occasions. But, sadly, it is not too far from the &lt;em&gt;truth&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;There are many definitions for legacy code. I've settled to define it as the code we are afraid to change, yet we need to. The code whose developer experience converges asymptotically to zero over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complexity as a Driver for Legacy Code
&lt;/h2&gt;

&lt;p&gt;Without realising it, we tend to create software like we construct buildings. The hard way: layer after layer, too late to look back and improve things in retrospect. We fail to keep software &lt;em&gt;soft&lt;/em&gt; as we lock the details in place with complexity in both design and implementation.&lt;/p&gt;

&lt;p&gt;Complex design often comes directly from complex business requirements. We might rewrite a service &lt;em&gt;en masse&lt;/em&gt; without criticism only because the customer asked us to do so. We are keen to ask what kind of software they want us to deliver while the more pressing question is: what problem do they want us to solve?&lt;/p&gt;

&lt;p&gt;Complex implementation, therefore, is a direct consequence of complex design. However, the effects of complex implementations become more detrimental via their ability to feed themselves and keep on growing during the software lifecycle.&lt;/p&gt;

&lt;p&gt;The common culprits for complex implementations are the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  teams are not abiding by the technical excellence and software craftspersonship — also known as having &lt;strong&gt;immature senior engineers&lt;/strong&gt; in the team&lt;/li&gt;
&lt;li&gt;  too high (100 %) utilisation rates keeping everyone as busy as possible therefore stifling innovation&lt;/li&gt;
&lt;li&gt;  severe blindness towards the wastes in the development process&lt;/li&gt;
&lt;li&gt;  allowing the unplanned work (e.g. production incidents) to stall the team's throughput by holding planned work hostage&lt;/li&gt;
&lt;li&gt;  working through tasks in isolation (one-person silos) and not sharing and integrating code daily&lt;/li&gt;
&lt;li&gt;  accepting too much work, and as a result, cutting corners under pressure to get tasks done&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of the above contribute to unhealthy codebases, but the fastest way is to cut corners regularly.&lt;/p&gt;

&lt;p&gt;Often, we have a situation where our time and budget constraints seemingly do not allow us to deliver our best software craftspersonship. Unfortunately, cutting corners under pressure from stakeholders is a temptation many of us are not prepared to resist.&lt;/p&gt;

&lt;p&gt;As a result of cutting corners, our codebases typically lack automated tests, technical documentation, and sometimes even styling. So, you may only wonder, what could be the reason for not even having the chance to add a style guide to the project. Time? Carelessness? Lack of skills? All of it?&lt;/p&gt;

&lt;p&gt;The above are the definitive signs of a legacy codebase. But why should we care about legacy code?&lt;/p&gt;

&lt;p&gt;Because most legacy codebases still deliver heaps of value to their users. However, what they lack is &lt;strong&gt;cost-efficiency&lt;/strong&gt;. The cost of developing new features has risen to extreme heights due to emerging complexity. What took three hours to implement a year ago might now take three or more days, especially if the team compositions have been changing in-between and silent (undocumented) knowledge runs wild.&lt;/p&gt;




&lt;p&gt;Having worked in software lifecycle management for a significant portion of my career, I have gathered a set of practices to fight back the costs emerging from complexity.&lt;/p&gt;

&lt;p&gt;In this post, I present a brief — constantly evolving — guide on gradually bringing back technical excellence and driving down development costs.&lt;/p&gt;

&lt;p&gt;I will focus mainly on writing tests and documentation, the two most crucial things regarding missing technical excellence. Other important factors like increasing security, observability, and accessibility of a product are not discussed in this guide (yet).&lt;/p&gt;

&lt;h2&gt;
  
  
  Increasing Cost-Efficiency Through Automated Tests
&lt;/h2&gt;

&lt;p&gt;When investigating an insufficient test coverage, it's easy to let the &lt;a href="https://thedecisionlab.com/biases/the-sunk-cost-fallacy/"&gt;&lt;strong&gt;Sunken Cost Fallacy&lt;/strong&gt;&lt;/a&gt; tell us that we shouldn't bother with automated tests at &lt;em&gt;this point&lt;/em&gt; in the project.&lt;/p&gt;

&lt;p&gt;We judge that the costs of covering the &lt;em&gt;entire&lt;/em&gt; codebase with tests are already too high and thus not worth the investment. Besides, the people who originally developed the application should have paid attention to writing tests from day one.&lt;/p&gt;

&lt;p&gt;How do we fix the situation? I've found it helpful to traverse the &lt;a href="https://martinfowler.com/articles/practical-test-pyramid.html"&gt;&lt;strong&gt;Test Pyramid&lt;/strong&gt;&lt;/a&gt; from top to bottom.&lt;/p&gt;

&lt;p&gt;We start by migrating our &lt;em&gt;definition of releasable&lt;/em&gt; through automated end-to-end tests that usually test the user interface flows. Next, we sink into delivering new features, fixing defects, and refactoring code by leveraging fine-grained tests and test-driven development. Ultimately, this guides us to build coherent technical documentation through well-defined test suites.&lt;/p&gt;

&lt;h3&gt;
  
  
  End-to-End Tests
&lt;/h3&gt;

&lt;p&gt;When the codebase has zero automated tests, it usually means that all the acceptance testing before a release is done manually.&lt;/p&gt;

&lt;p&gt;It is not unusual to manage test cases in software like &lt;em&gt;Jira&lt;/em&gt; or &lt;em&gt;PractiTest&lt;/em&gt;. Within these tools, a special QA team designs and runs the tests, compare the actual test outputs to expected, and notifies the release team of any critical issues they uncovered.&lt;/p&gt;

&lt;p&gt;Meanwhile, developers are watching Youtube waiting for the bug reports to arrive.&lt;/p&gt;

&lt;p&gt;If we need to manually verify that our user interfaces are functioning correctly, the automation of said test cases is easy. Instead of clicking through pages in the browser, we can add these steps as scripts using tools like &lt;strong&gt;Cypress&lt;/strong&gt; and &lt;strong&gt;Playwright&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Yes, but... our product doesn't contain a browser interface. We have a set of legacy APIs instead.&lt;/p&gt;

&lt;p&gt;Suppose we want to verify that our backend integrations return the expected responses to given requests, it is helpful to use a technique called &lt;a href="https://blog.thecodewhisperer.com/permalink/surviving-legacy-code-with-golden-master-and-sampling"&gt;&lt;strong&gt;Golden Master&lt;/strong&gt;&lt;/a&gt;, also known as characterisation testing. If you have ever used snapshots when verifying that the shape of a complex object or a structure of a UI component did not change, you are familiar with the Golden Master technique.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Rather than revert to the Guru Checks Output antipattern, however, I take a snapshot of the last-known acceptable output — I call that the &lt;em&gt;golden master&lt;/em&gt; — and save it for future use. When I run the test again, I compare the output to the golden master, and if they match, then the test passes; if they don't match, then the test fails." — J.B. Rainsberger.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yes, but... how do I sell the initiative of adding tests? It must cost us a fortune to have developers study automated testing techniques and then migrate our specialised test cases.&lt;/p&gt;

&lt;p&gt;Fortunately, expenses are modest if we carry out the migration in tiny steps.&lt;/p&gt;

&lt;p&gt;We can order our test cases by priority. Users being able to sign in to a self-service portal is naturally a higher priority than the business contact information being rendered in a specified order. The stakeholders are happy to know that by automation, we have eliminated the chance of human error.&lt;/p&gt;

&lt;p&gt;Alternatively, we can find out what test cases consume the most of our time. For example, clicking through the whole e-commerce flow from adding products to a shopping cart, filling in details, choosing a payment method, and eventually checking from the confirmation page that the order was processed is a significant time sink. We should record these steps and automate them. The stakeholders are happy to know that we have eliminated the time cost of manual testing and saved additional bandwidth for solving other problems by automation.&lt;/p&gt;

&lt;p&gt;Yes, but... now that we are automating everything, does it mean I have to fire our QA team?&lt;/p&gt;

&lt;p&gt;No, you don't need to fire your testing specialists. Instead, they can free up their bandwidth and expertise from mundane regression checks before releases to continuous, investigative, and exploratory testing through automation.&lt;/p&gt;

&lt;p&gt;Each &lt;em&gt;sprint&lt;/em&gt; should include a feasible amount of test case migrations. When planning the next sprint's contents, everyone must understand that our velocity drops slightly because we will not deliver as many new features right &lt;em&gt;now&lt;/em&gt;. However, after a few sprints, the automation benefits kick in, and the velocity restores to normal levels and even higher.&lt;/p&gt;

&lt;p&gt;Having a stable suite of automated end-to-end tests gives us a preliminary safety net. It guards us against breaking the whole application while we are changing it.&lt;/p&gt;

&lt;p&gt;However, refactoring and thus keeping the codebase in prime health is still potentially dangerous. For that, we need to dig deeper...&lt;/p&gt;

&lt;h3&gt;
  
  
  Fine-Grained Tests
&lt;/h3&gt;

&lt;p&gt;At this point, your most valuable revenue flows are covered with high-level end-to-end tests. The problem is, when one of these high-level tests fail, there can be multiple causes for it.&lt;/p&gt;

&lt;p&gt;When high-level end-to-end and integration tests fail, it's similar to a fire alarm buzzing you that something is burning somewhere in your city, but you don't know what it is. Alas, the only way to find out is to follow the smoke.&lt;/p&gt;

&lt;p&gt;Perhaps the worst trait of end-to-end tests is that they are slow. When a test run takes a long to complete, I'm incentivised to skip running tests frequently. When I don't run tests for each tiny change, I risk adding more and more risky changes into the batch, taking away my chance to safely change the codebase.&lt;/p&gt;

&lt;p&gt;Enter fine-grained tests, more often referred to as &lt;em&gt;unit tests&lt;/em&gt;. Practical unit tests verify &lt;strong&gt;a single behaviour of the system under test&lt;/strong&gt;. Thus, they fail for &lt;strong&gt;one and only one&lt;/strong&gt; reason.&lt;/p&gt;

&lt;p&gt;Furthermore, we can run unit tests fast side-by-side with code changes using a watchdog functionality. Whenever I write new code, tests related to my changes are run automatically. Thus, I get instant feedback telling me if I'm straying from a safe path. It's precious while refactoring: if my changes pass the tests, I commit them and carry on — otherwise, I revert my codebase back to the last working state.&lt;/p&gt;

&lt;p&gt;Yes, but... we don't have any unit tests in our codebase right now. Where should we start?&lt;/p&gt;

&lt;p&gt;Sprinkling unit tests here and there in the codebase doesn't motivate us. It's best to focus on adding tests to parts of the codebase you have changed frequently and recently (&lt;em&gt;frecency&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;We write an expectation for every new feature, witness it fail for the right reason, and finally write enough code until the expectation is satisfied.&lt;/p&gt;

&lt;p&gt;For every new defect raised, we should write an expectation exposing the fault and then write code until the expectation is satisfied and the defect has vanished.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test-Driven Development and Refactoring
&lt;/h3&gt;

&lt;p&gt;The technique I described above, also known as &lt;strong&gt;test-driven development&lt;/strong&gt;, is the easiest and safest way to introduce new features to our codebase in a controlled manner. You are free to disagree with me, but I dare you to find me a more effortless and safer way.&lt;/p&gt;

&lt;p&gt;Unfortunately, many developers still take a step backwards and judge you when they hear the acronym TDD. They may decry it as a mantra, or something sinister practised within a religious cult. To those people, we can tell that programming is always about setting expectations for your code. Without TDD, these expectations are stored in your head and verified with your human senses. With TDD, the expectations are held as executable tests and confirmed by the computer. Do you really think the human brain is more effective?&lt;/p&gt;

&lt;p&gt;That being said, TDD is not a silver bullet for every situation. Nevertheless, I like &lt;a href="https://kentcdodds.com/blog/when-i-follow-tdd"&gt;the points&lt;/a&gt; &lt;strong&gt;Kent C. Dodds&lt;/strong&gt; writes on their blog post. Precisely, I embrace the notion of not using TDD while doing exploratory coding.&lt;/p&gt;

&lt;p&gt;I, too, have found out that when I'm trying to figure out how a library or a framework works, I tend to hack some code together and learn it through exploring. Hacking is not an issue unless every task you work on becomes a feeble attempt at exploratory coding. Such is prone to happen when we don't split nor refine our tasks to concrete implementation details. The more I need to duct tape my code, the less incentivised I'm to write tests first, and my main driver is simply to make the code work.&lt;/p&gt;

&lt;p&gt;Let's remember that TDD is not a testing tool. Instead, it forces us to design our code before writing it. If we never pay attention to good design, our codebase will eventually become a rotten cavity that only gets worse before a dentist needs to operate the whole tooth with a root canal, or in our case, rewrite the code.&lt;/p&gt;

&lt;p&gt;Yes, but... using TDD, we can't write tests for the existing code by definition, right?&lt;/p&gt;

&lt;p&gt;When we are writing tests for the existing production code, we often find it difficult. As a result, our design likely contains serious flaws, usually caused by a lack of continuous refactoring, which has not played a significant role due to a lack of tests as a safety net.&lt;/p&gt;

&lt;p&gt;Fortunately, we can practise test-driven development also for the existing code by following the steps below.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the codebase, locate the code (&lt;em&gt;behaviour&lt;/em&gt;) you want to test&lt;/li&gt;
&lt;li&gt;Comment out the code as if it never existed in the first place&lt;/li&gt;
&lt;li&gt;Write a failing test&lt;/li&gt;
&lt;li&gt;Start restoring the commented out code line by line until the new test passes&lt;/li&gt;
&lt;li&gt;If necessary, write another failing test and make it pass&lt;/li&gt;
&lt;li&gt;Remove (do &lt;em&gt;not&lt;/em&gt; comment out) all the code not required for the tests to pass&lt;/li&gt;
&lt;li&gt;Refactor until the code satisfies your taste&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are many good resources written about refactoring. I tend to follow &lt;a href="https://martinfowler.com/bliki/BeckDesignRules.html"&gt;the four rules of simple design&lt;/a&gt; by &lt;strong&gt;Kent Beck&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  make the tests pass&lt;/li&gt;
&lt;li&gt;  refactor until the intention is clear&lt;/li&gt;
&lt;li&gt;  remove duplication where feasible&lt;/li&gt;
&lt;li&gt;  remove everything not needed to satisfy the first three rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More succinctly: &lt;strong&gt;test, refactor, remove, and repeat&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If the codebase is extremely convoluted as a consequence of lousy engineering, we find this process difficult. In those cases, instead of commenting out old code, we should consider writing a new module or class from scratch. Then, when we are ready, we can swap it with the old implementation helped by the interfaces defined in our type system. Doing so leaves us the possibility of quickly reverting back to the old implementation if things go wrong.&lt;/p&gt;

&lt;p&gt;Most importantly, writing tests side-by-side with both the existing and new production code takes away the reason to ask how much writing tests cost. The cost of writing tests is now embedded within the feature development.&lt;/p&gt;

&lt;p&gt;In some projects, I've seen teams creating separate tickets for writing tests and refactoring. Doing so, the developers think they get proper permission for these tasks, but they actually look as if apologising for following the quality standards of their craft.&lt;/p&gt;

&lt;p&gt;Differentiating tests and refactoring from feature development is &lt;strong&gt;a huge red flag&lt;/strong&gt; and makes us developers look unprofessional. We must never allow ourselves to think a feature is &lt;em&gt;done&lt;/em&gt; unless we have proved it with tests. Respectively, refactoring is a mandatory continuous practice, which must never require explicit permission.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Boring Part: Document All the Things
&lt;/h2&gt;

&lt;p&gt;Let's assume that through rigorous testing and refactoring efforts, our codebase is in better shape now. End-to-end tests ensure we can release safely, and fine-grained tests provide we can rapidly develop and refactor new features.&lt;/p&gt;

&lt;p&gt;What do we miss? Documentation!&lt;/p&gt;

&lt;p&gt;When studying a codebase for the first time, I often reach for three different types of documentation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do I install and run this application locally?&lt;/li&gt;
&lt;li&gt;What features does it have, and how do I use them?&lt;/li&gt;
&lt;li&gt;What past decisions have affected the design of this application and the way it works today?&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Read Me, Read Me!
&lt;/h3&gt;

&lt;p&gt;We should ensure we have a &lt;strong&gt;README&lt;/strong&gt; file in the project root for the first task. This is the front page of your documentation in modern version control systems, which people consult first. As a bare minimum, it should contain the following information.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  How to install the application&lt;/li&gt;
&lt;li&gt;  How to start the application&lt;/li&gt;
&lt;li&gt;  How to test the application manually&lt;/li&gt;
&lt;li&gt;  How to run the automated tests&lt;/li&gt;
&lt;li&gt;  How to deploy the application&lt;/li&gt;
&lt;li&gt;  How to contribute to the codebase&lt;/li&gt;
&lt;li&gt;  Who to ask for support in case the documentation can't provide answers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Executable Documentation
&lt;/h3&gt;

&lt;p&gt;The second task, however, might surprise you. Having covered our codebase with automated tests, we actually have the relevant technical documentation right there, and we can even run it — aren't we the lucky ones.&lt;/p&gt;

&lt;p&gt;End-to-end tests document how the users interact with our application and how the client applications interact with our backend systems. When written clearly and concisely (see &lt;a href="https://automationpanda.com/bdd/"&gt;&lt;em&gt;behaviour-driven development&lt;/em&gt;&lt;/a&gt;), every developer can quickly grasp the basics.&lt;/p&gt;

&lt;p&gt;Fine-grained tests document how our internal interfaces are used and how public methods are called. Without fine-grained tests, we would have to read the entire source code to understand how to call its public methods, what inputs they require, and what kind of outputs they produce. By looking at well-defined tests, it becomes evident like reading a user manual.&lt;/p&gt;

&lt;p&gt;Yes, but... my excellent IDE shows enough information when I hover my cursor over the method name. So why do I need more documentation?&lt;/p&gt;

&lt;p&gt;Indeed, many state-of-the-art omnipotent god-given IDEs can also display the intent and signature of methods by hovering over their name. However, our code often contains intricate handling for edge cases and errors, which are not apparent by looking at the type signatures. It bears repeating that type systems, despite their value, never have, and will never, be a substitute for proper tests and documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architectural Decision Records
&lt;/h3&gt;

&lt;p&gt;The third task is perhaps the most exciting one. Despite our best efforts, we can't know what we don't know. Even with codebases that could be a little more than a year old, we tend to find ourselves in peculiar waters.&lt;/p&gt;

&lt;p&gt;We may ask ourselves, how did this class come to be? Why is this state shared between these components? Why does our database table contain an index for this column? Why do we require an API key for all our public REST APIs?&lt;/p&gt;

&lt;p&gt;Surely we can figure out the answers to the above questions ourselves, or more traditionally, by asking other developers. However, wouldn't it be &lt;em&gt;nice&lt;/em&gt; to read the answers explained to you in plain text, ideally next to the source code?&lt;/p&gt;

&lt;p&gt;Yes, but... I can just as quickly run &lt;code&gt;git log&lt;/code&gt; and check the history from there.&lt;/p&gt;

&lt;p&gt;Stop right there! Commit messages in version control systems are great for capturing and explaining the motivation behind micro-level changes such as renaming a variable. However, they perform poorly for significant architectural changes spanning across tens or hundreds of small commits.&lt;/p&gt;

&lt;p&gt;Some developers are keenly obsessed with keeping the version control history linear to tell a logical narrative of changes between points A and B in time. I admit to doing it myself from time to time. Other developers like to squash merge entire feature branches so that one commit equals precisely one feature. In most situations, both approaches come with tradeoffs that make them more harmful than beneficial.&lt;/p&gt;

&lt;p&gt;Thus, we should use &lt;a href="https://adr.github.io"&gt;Architectural Decision Records&lt;/a&gt; instead.&lt;/p&gt;

&lt;p&gt;ADRs capture a single decision that has significant consequences towards the design and implementation of the product for the foreseeable future. Typically, they include but are not limited to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  title of the decision&lt;/li&gt;
&lt;li&gt;  status (proposed, accepted, rejected, or superseded by another ADR)&lt;/li&gt;
&lt;li&gt;  context (why did we have to discuss this?)&lt;/li&gt;
&lt;li&gt;  decision (where did our discussion lead us?)&lt;/li&gt;
&lt;li&gt;  possible consequences (what later impacts did our decision have?)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ADRs work well with internal meetings, and therefore we should set a requirement that no architecture meeting takes place unless a decision or proposal is produced.&lt;/p&gt;

&lt;p&gt;Yes, but... aren't the ADRs useless for us? I mean, who can't remember what we discussed yesterday or last week?&lt;/p&gt;

&lt;p&gt;You might feel like it now, but try telling that yourself in six months. I can assure you that when enough time has passed in a project, even the code you wrote is indistinguishable from someone else's.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you, like me, have worked in maintaining the software in the later stages of its lifecycle, I hope you have enjoyed this post and found pieces of wisdom in it.&lt;/p&gt;

&lt;p&gt;The bottom line is that we should not run away from legacy codebases. Granted, I can name a dozen more exciting tasks than trying to get an old application without tests or documentation up and running. However, that is not for us to decide. All we have to decide is what to do with the code that is given to us.&lt;/p&gt;

&lt;p&gt;Keep calm and carry on!&lt;/p&gt;




&lt;p&gt;&lt;small&gt;Photo by &lt;a href="https://unsplash.com/@carlevarino"&gt;Cesar Carlevarino Aragon&lt;/a&gt; on Unsplash&lt;/small&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>tdd</category>
      <category>productivity</category>
      <category>design</category>
    </item>
    <item>
      <title>Being a Good Developer: Tips for an Effective Code Review</title>
      <dc:creator>Niko Heikkilä</dc:creator>
      <pubDate>Sat, 02 Oct 2021 14:26:19 +0000</pubDate>
      <link>https://dev.to/futurice/being-a-good-developer-tips-for-an-effective-code-review-fpo</link>
      <guid>https://dev.to/futurice/being-a-good-developer-tips-for-an-effective-code-review-fpo</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Hey!&lt;/strong&gt; An &lt;a href="https://dev.to/nikoheikkila/being-a-good-developer-six-tips-for-a-painless-code-review-2la9"&gt;earlier revision of this post&lt;/a&gt; described how to survive the world of pull request workflows. However, since then, I've grown more convinced that asynchronous development is among the well-known root causes why software teams struggle to ship working code fast. Thus, I've decided to rewrite this post to reflect the way I currently think, enjoy!&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Many of us have been there. A software project with significant business value should ship to end-users as soon as possible. But, unfortunately, the budget has run over. Management is throwing a furious fit. Developers are doing their best to sustain and control damage by explaining that the features are being reviewed and tested, but all they need is a little more time.&lt;/p&gt;

&lt;p&gt;Rapid feature delivery is impossible when code reviews become a blocker, which they often are because of our inability to &lt;em&gt;shift left&lt;/em&gt; (move events earlier in the process instead of later).&lt;/p&gt;

&lt;p&gt;Some developers' comfort zone is buried under noise-cancelling headphones working on a feature isolated from the rest of the world. After a couple of days, the feature is "finished", and a pull request is submitted for peers to scrutinise. However, an effective code review can't occur because the changeset is made of inconceivable hunks of code totalling over &lt;strong&gt;1000 changed lines&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Feeling the insufferable pressure from management, another developer takes a quick glance at the changes, writes "looks good to me", and approves the pull request. Finally, another developer spots a couple of minor design issues and apologises for nitpicking while commenting. The reply is a famous line:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Yeah, let's fix this later when we have time."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Legacy code is born when we fail to build quality in.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All those moments where we play a safe bet and write another page of technical debt explaining how we had a tight schedule. Surely, we can pay back the technical debt later. So in a sense, we can, but we &lt;em&gt;won't&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I've done this too many times and always felt ashamed, profoundly questioning my professionality. This post will explain how you can avoid these pitfalls and make code review a pleasant part of the development experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ask for a Review Before Committing
&lt;/h2&gt;

&lt;p&gt;The greatest thing you can do to improve your team's performance is to integrate feedback into your work early and often. In practice, this means you shouldn't delay improvements to a post-development phase.&lt;/p&gt;

&lt;p&gt;Many professional teams have been influenced too heavily by open-source development workflows fashioned by GitHub, where all the changesets must be submitted as pull requests. Certainly, pull requests have become a disastrous plague for many teams: they promise a sense of security but deliver only bottlenecks and constraints in return.&lt;/p&gt;

&lt;p&gt;Pull requests have their place in open-source development where trust doesn't exist. They are also helpful on those occasions where deployment to a temporary preview environment is needed. However, in other situations, pull requests do little to facilitate the code review experience, often making it worse.&lt;/p&gt;

&lt;p&gt;When the development happens asynchronously, developers work on their tasks and are forced to wait until their peers are available for review. Naturally, this incentivises starting new tasks before previous ones have been finished. It's a trait rooted in our mind that we should keep ourselves busy, lest a judging eye of the management might find us slacking and not working. However, the more tasks we start, the more context-switching penalties we suffer, and the slower our velocity become.&lt;/p&gt;

&lt;p&gt;Fortunately, the great minds of the &lt;em&gt;Extreme Programming&lt;/em&gt; community have had a solution to this for a long time: &lt;strong&gt;test-driven development&lt;/strong&gt; and &lt;strong&gt;pair/mob programming&lt;/strong&gt;. To achieve the most effective form of code review, we should use linters to check our code style, write the minimum amount of code to make tests pass, and finally use &lt;del&gt;a rubber-duck&lt;/del&gt; a teammate to verify our design. All this should happen at the same time, in the same space, on the same computer.&lt;/p&gt;

&lt;p&gt;I've written extensively about &lt;a href="https://dev.to/futurice/when-to-pair-program-and-when-to-go-solo-26jl"&gt;the benefits and pitfalls of pairing&lt;/a&gt;, so suffice to say here that the best code reviews take place instantly after a single line has been written.&lt;/p&gt;

&lt;p&gt;The bottom line is that &lt;strong&gt;code review doesn't need online tools&lt;/strong&gt;. Instead, discuss code face-to-face (in person or through screen sharing) and resolve any issues in real-time. Defects are best fixed when it's cheapest and fastest: before creating a commit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Split the Changes by Concern
&lt;/h2&gt;

&lt;p&gt;The unfortunate truth is that defects will occur despite our best intentions. Therefore, it's equally important to limit the scope of our changes by concern. That means working in the smallest feasible batches. These can be integrated into the codebase as independent &lt;a href="https://www.industriallogic.com/blog/whats-this-about-micro-commits/"&gt;&lt;em&gt;micro-commits&lt;/em&gt;&lt;/a&gt; without breaking a thing.&lt;/p&gt;

&lt;p&gt;Defects are much easier to find from micro-commits, and they are effortless to revert where needed. For example, I've lost count of how many times &lt;a href="https://git-scm.com/docs/git-bisect"&gt;&lt;code&gt;git bisect&lt;/code&gt;&lt;/a&gt; has saved the day because I've used micro-commits.&lt;/p&gt;

&lt;p&gt;Practising Continuous Integration dictates that we should push to the trunk at least daily — I prefer multiple times a day. However, developers sometimes reject this notion stating that their changes are too large and risky to integrate &lt;em&gt;now&lt;/em&gt;. Hence, they stash their batches in branches, allowing them to grow in size and become more challenging to review.&lt;/p&gt;

&lt;p&gt;A reinforcement loop where we are forced to write large batches because we're afraid of integrating reveals a malodorous design smell. The task you took wasn't correctly broken into subtasks, and it likely contains dependencies to other developers (or teams) work. Unfortunately, it's too late for us to fix lousy design during a code review, but we can monitor and improve for the future by limiting the scope and writing smaller user stories.&lt;/p&gt;

&lt;h2&gt;
  
  
  Invite the Right People to Review
&lt;/h2&gt;

&lt;p&gt;If you have written a fresh new algorithm for solving a computational problem, have it reviewed by someone who genuinely knows about code performance and the Big-O notation. In addition, people with impeccable CSS grid skills will serve you better when you're designing those fancy new UI changes later.&lt;/p&gt;

&lt;p&gt;Often team compositions vary greatly. Sometimes teams are built from generalists (&lt;em&gt;jacks of all trades&lt;/em&gt;) and sometimes specialists or deep experts in different areas. In the case of specialists, inviting more than one person to review is helpful. Doing so facilitates knowledge sharing and allows the team to level their specialities, guiding them to fluidly grow as generalists.&lt;/p&gt;

&lt;p&gt;Expecting more than one person for review might tempt us to walk our code through multiple rounds. However, what we need is a live mob review, again &lt;strong&gt;without tools&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, changes to APIs handling sensitive data may require additional attention for security details. If the team has a security specialist, have them lead this code review and invite the team to learn.&lt;/p&gt;

&lt;p&gt;Likewise, the review for introducing a new design system to improve mobile responsiveness could be led by the group's front-end specialist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Grab the Mentoring Opportunity
&lt;/h2&gt;

&lt;p&gt;In the past, I've used code review as a strict gatekeeping and controlling tool to prevent lousy code from entering the codebase. After all, that is its purpose, right? As a result, I've criticised some design decisions sharply without realising how my tone and message have influenced my team's work.&lt;/p&gt;

&lt;p&gt;Trust is in the heart of code review and deeming that all code is faulty unless proved otherwise will significantly damage the spirit of your team.&lt;/p&gt;

&lt;p&gt;Instead of scrutiny, we should use code review for mentoring. Instead of telling what all is wrong in the code, we should guide people to improve. Fix the defects together and allow the mutual trust to grow. Soon the same developers have a tremendous amount of self-confidence, and implicitly they contribute to a better and healthier codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trust the Infinitely Improvable Code
&lt;/h2&gt;

&lt;p&gt;Similarly, as an avid gatekeeper, it took me a lot of time to understand that the code written by others is not inherently faulty. The code might not meet my expectations of good design, but that's rarely an issue. All the code is &lt;em&gt;infinitely improvable&lt;/em&gt;, and our responsibility as developers is to improve it.&lt;/p&gt;

&lt;p&gt;As arguments arise in code reviews, it's important to practice humility and not push your solution too firmly. By saying that, do I mean that code review doesn't matter? No, but it's to be used wisely. Likely, the code reviewed to be acceptable now wouldn't pass the same inspection in six months.&lt;/p&gt;

&lt;p&gt;Keeping the code easy to change allows us to refactor it to better serve our purpose long after writing. There's no need to expect perfect software to emerge during a code review when we can perpetually grow it. That is what makes software &lt;em&gt;soft&lt;/em&gt;.&lt;/p&gt;




&lt;p&gt;&lt;small&gt;Photo by Alvaro Reyes on Unsplash.&lt;/small&gt;&lt;/p&gt;

</description>
      <category>codereview</category>
      <category>programming</category>
      <category>codequality</category>
      <category>github</category>
    </item>
    <item>
      <title>When to Pair Program and When to Go Solo</title>
      <dc:creator>Niko Heikkilä</dc:creator>
      <pubDate>Mon, 24 May 2021 14:58:16 +0000</pubDate>
      <link>https://dev.to/futurice/when-to-pair-program-and-when-to-go-solo-26jl</link>
      <guid>https://dev.to/futurice/when-to-pair-program-and-when-to-go-solo-26jl</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;Despite all the praise pair programming gets, it is not a silver bullet and we should carefully practise it to get the most benefit from it.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I recently finished reading &lt;a href="https://www.goodreads.com/book/show/57518328-practical-remote-pair-programming"&gt;&lt;em&gt;Practical Remote Pair Programming&lt;/em&gt; by &lt;strong&gt;Adrian Bolboacă&lt;/strong&gt;&lt;/a&gt;. In the description, the author promises to teach you the structure, organisation, communication, and tools for making (remote) pair programming successful in your (distributed) team.&lt;/p&gt;

&lt;p&gt;Pair programming is complicated. Despite that, I've been practising and advocating it for a while, trying to build solid habits around it. Thus, the book naturally caught my eye. Besides, today most of the programming work is remote, making the book a timely publication.&lt;/p&gt;

&lt;p&gt;In addition to describing when and how pair programming works to speed up your delivery process, it is crucial to understand situations where it might only slow you down. In this post, I will go over these situations briefly. However, I warmly recommend reading the book as well for complete insights.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; I will use the term &lt;em&gt;pairing&lt;/em&gt; a lot in this post in place of pair programming. Many pairing techniques also apply to &lt;em&gt;mobbing&lt;/em&gt; (mob programming), which means working in groups of three or more people. For beginners, I recommend starting in pairs and moving on to mobs after a while. In some texts, you might also stumble upon the term &lt;em&gt;ensemble programming&lt;/em&gt;, a friendlier name for mobbing. After all, we are not here to smack down the code like an angry mob, even though programming can be frustrating at times.&lt;/p&gt;




&lt;h2&gt;
  
  
  The (Not-)Obvious Benefits of Pairing
&lt;/h2&gt;

&lt;p&gt;Trying to convince your team to take on pairing can be even more challenging than programming in pairs itself. In this section, I will tell how and why pairing can make us better developers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pairing Is Mentoring
&lt;/h3&gt;

&lt;p&gt;When I began to build software for a living, I was introduced to new projects, their conventions and other ways of working through pairing. I'm eternally grateful to all my colleagues who have paired with me.&lt;/p&gt;

&lt;p&gt;The pairing has allowed me to grow orders of magnitude faster than being thrown to survive in a project alone because pairing is a pure form of mentoring. After a while, I too began pairing with new hires passing forth all the knowledge I had gained.&lt;/p&gt;

&lt;p&gt;As in martial arts, those with a higher rank are responsible for teaching others with a lower rank. Pairing is all about this. Therefore, the best pairs are often junior-senior pairs. The junior is ideally a new hire or otherwise unknown to the codebase or domain. Pairing with someone on your level can work, too, although it involves less mentoring and growing.&lt;/p&gt;

&lt;p&gt;The next time your team gets a new member, do not only throw entry-level tasks at them — pair with them, instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pairing Is a Learning Tool
&lt;/h3&gt;

&lt;p&gt;Like many others, I started my career studying computer science in study groups. The fundamental programming classes I attended always involved exercises. Often we would solve the given problems together, sitting next to the same computer sharing the same keyboard.&lt;/p&gt;

&lt;p&gt;In the book, the author references the four levels of knowledge related to a concept known as &lt;em&gt;staff liquidity&lt;/em&gt;. These describe the skills you possess about the current system or parts of it. They are as follows.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;"I know nothing!"&lt;/em&gt; (beginner)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"I can run it"&lt;/em&gt; (intermediate)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"I can tweak and fix bugs"&lt;/em&gt; (advanced)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"I &lt;strong&gt;own&lt;/strong&gt; it!"&lt;/em&gt; (master)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Although you typically climb these levels independently with occasional support from your team, the journey towards mastery is fastest travelled by pairing. When you pair to learn, you will develop a solid understanding of the system, enabling you to redesign or refactor it faster and safer than working alone.&lt;/p&gt;

&lt;p&gt;The next time you need to learn a complex system or domain to manage it, pair with the one who knows it best.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pairing Is Sharing Knowledge
&lt;/h3&gt;

&lt;p&gt;The more we work alone, the more we gather silent knowledge about the inner workings of our code. It's inefficient and time-consuming to share knowledge only through documentation despite its importance for product longevity. We can conveniently build shared conventions about developing the product through pairing without having to sit in meetings or glance at massive pull requests.&lt;/p&gt;

&lt;p&gt;A well-established technique is to form pairs from people working with different parts of the system. For example, a back-end developer should pair with the front-end developer working with requests to the back-end interfaces. Successfully applying pairing techniques will tear down the invisible walls in your team.&lt;/p&gt;

&lt;p&gt;Note, however, that the shared knowledge should also be written down. Otherwise, it is only silent knowledge in your and your pair's heads.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pairing Is a Social Event
&lt;/h3&gt;

&lt;p&gt;Developers come in all sorts of flavours. Some like to do focus work being buried under music from noise-cancelling headphones. In contrast, others enjoy the company of their peers and have a chance to brainstorm complex problems together.&lt;/p&gt;

&lt;p&gt;I belong to the latter group. In fact, I often feel more stressed and anxious when working alone. These feelings have also begun to intensify during the pandemic. Being isolated in continuous long stretches has made my performance significantly weaker. Thus, I need social programming to live and thrive.&lt;/p&gt;

&lt;p&gt;Pairing and mobbing (style of pairing with three or more people) can also happen in social events organised within a community. Hackathons are a prominent example. If the employees are suffering from isolation, organising a community event is a beautiful way to build up the spirit and see new innovations grow.&lt;/p&gt;

&lt;p&gt;In the book, there is a fascinating anecdote about the social aspect of pairing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"During a community event that I was facilitating, while the programmers were pairing, &lt;strong&gt;a CEO appeared&lt;/strong&gt;. He heard about this event and he was curious what was going on. Nobody had any idea about his role, and he joined, paired, and discussed just like any other attendee. Only after the event did I find out that he wasn't really a programmer."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pairing is not only for developers. You can pair with designers, testers, product owners, managers and even your CEO under some circumstances. What value does your solution have if you can't explain it to your CEO, anyway?&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes Made While Pairing
&lt;/h2&gt;

&lt;p&gt;By now, you most likely noticed that you have tried pairing at least once, whether it was during your studies or junior years.&lt;/p&gt;

&lt;p&gt;The unfortunate fact is that many of us stop pairing at some point. We might blame bad prior experiences or incompetent managers who think that features are done fastest when everyone is working independently.&lt;/p&gt;

&lt;p&gt;It cannot be denied that pairing does not mean eating cake and drinking champagne from golden carafes all day. Hence, avoid these common mistakes.&lt;/p&gt;

&lt;h3&gt;
  
  
  You Should Be Pairing All Day
&lt;/h3&gt;

&lt;p&gt;Pairing all day every day can make you exhausted and emotionally zapped at the end of the day. I can usually last no longer than two hours talking and writing code at the same time. Then I need to rest for at least 15 minutes to ease the fatigue. Continuously keeping up a pace like this will more than likely grind our wellbeing and drop our interest in pairing.&lt;/p&gt;

&lt;p&gt;Doing the devil's math shows that we can split the average day of eight hours to a maximum of three to four extended sessions with short breaks in between. On paper, this sounds efficient, but it quickly proves as wasteful as any approach where developers are fully utilised. Remember, 100 % utilisation is a parking lot – or an express lane to sick leave.&lt;/p&gt;

&lt;p&gt;It's better to start by pairing for 25-30 minutes straight (in total 1-2 hours daily), pausing briefly, and rotating roles before carrying on. If the task is finished, you can rotate pairs before starting a new task. I recommend you download a &lt;strong&gt;Pomodoro application&lt;/strong&gt; or use any suitable timer to keep track of time. Rotating often keeps the spirit up as you are not stuck working with the same partner repeatedly.&lt;/p&gt;

&lt;p&gt;Efficiently managing the time spent in the pairing will eventually make you less and less tired while you get used to this new way of working. From there on, you can increase the amount of pairing slowly. I have found out that I can roughly keep on pairing 75 % of the day. The rest 25 % I reserve for a slack time where I learn, research, or work independently. Your perfect percentage may vary, but don't let it creep towards 100 %.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pairing in Hostile or Unknown Waters
&lt;/h3&gt;

&lt;p&gt;While pairing, we need to bounce ideas back and forth when trying to develop optimal solutions. Inevitably some of our clever ideas can sound utterly crazy or prove ineffective right after saying them.&lt;/p&gt;

&lt;p&gt;Therefore, pairing requires a psychologically safe space where you are not laughed at no matter what you say. Without psychological safety, you cannot bring forth your best ideas. In the worst case, you might end up silently following what others say, effectively reducing the pair to a solo effort.&lt;/p&gt;

&lt;p&gt;If there are any tensions within your team, you should resolve those first before starting to pair. Suppose no one in the group knows the other person, as is sometimes the case in fast-paced consultancy projects. In that case, you should wait until the team has passed its forming phase and is comfortable working as a unit.&lt;/p&gt;

&lt;p&gt;If the whole development organisation is on fire and people hate working with each other, then... well, just hand over your resignation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Expecting a Formal Code Review After Pairing
&lt;/h3&gt;

&lt;p&gt;Some developers accustomed to the ways of working in highly bureaucratic, process-oriented, and hierarchical cultures adamantly state that pairing is no substitute for a formal code review. It is further reasoned by saying that a third person with &lt;em&gt;fresh eyes&lt;/em&gt; is supposed to catch all the mistakes you and your pair have made.&lt;/p&gt;

&lt;p&gt;In these situations, ask how the third developer — who has no context or deep understanding of the problem at hand — could review the solution any better? Asynchronous ways of working have instilled the notion that we must always invite an outsider to scan our code. Contrary, the code review is most useful coming from peers who understand the context and problem. They are your pairs.&lt;/p&gt;

&lt;p&gt;Suppose we have a process demanding an external code review despite pairing. In the worst case, you first have to wait for the third developer to detach from their current task. Then they suffer through all the negative impacts of context switching before studying the code you have written. Finally, they present you their often flawed feedback before switching back to their previous task again. This drastically reduces the team's throughput and increases your lead times.&lt;/p&gt;

&lt;p&gt;Instead, try pairing in a continuous delivery mindset. Design, implement, review, test, and finally deploy your solution. Then make a (virtual) high-five, grab coffees, and move on to the next task. I've efficiently completed user stories with tens of subtasks without creating significant defects in a day or two doing so.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pairing With Unclear Requirements
&lt;/h3&gt;

&lt;p&gt;When your team has no clear understanding of the problem or the domain, pairing is not fruitful. You will likely end up staring at a task description — often phrased verbatim by the client or product owner — with open mouths for a couple of minutes before moving on to an easier task.&lt;/p&gt;

&lt;p&gt;Fortunately, pairing is not always about programming because solving problems is not always about writing code either. You can pair with your product owner or team lead and together write high-quality requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pairing with Bad Coding Practices
&lt;/h3&gt;

&lt;p&gt;Pairing is ineffective when tight schedules force your team to cut corners daily, resulting in technical debt. After deciding to improve the codebase quality, you can slowly start slicing through the legacy cruft and refactor the code in pairs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Tips Before Starting Pairing
&lt;/h2&gt;

&lt;p&gt;This section shall briefly describe small tricks that have helped me whether pairing remotely or in the office.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Ensemble Commits
&lt;/h3&gt;

&lt;p&gt;During pairing, we usually share the same codebase, which means that version control tools cannot accurately determine who has done what. It is not always crucial to attribute commits to specific authors. After all, the team should have &lt;em&gt;collective ownership&lt;/em&gt; of the solution. However, it is a good practice to give credit where it is due.&lt;/p&gt;

&lt;p&gt;This can be done with a technique called &lt;em&gt;ensemble commits&lt;/em&gt;, in which you simply write the name and email of your pair in the commit message footer. See the example below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feat(api): add a new route '/films' for fetching IMDb data

// optional longer description here

Co-authored-by: Steve McQueen &amp;lt;kingofcool@gmail.com&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not all source control providers display this information correctly. However, &lt;a href="https://docs.github.com/en/github/committing-changes-to-your-project/creating-and-editing-commits/creating-a-commit-with-multiple-authors"&gt;&lt;strong&gt;GitHub&lt;/strong&gt;&lt;/a&gt; favours this approach when specifying multiple authors. It is a great way to give credit to your pair. It also helps other developers to see who should they ask about this commit later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Assign Roles
&lt;/h3&gt;

&lt;p&gt;Besides writing informative commit messages, make sure to commit early and often. You can also assign roles — minding the rotation — while pairing. Test-driven development while pairing is particularly effective when the other developer is unfamiliar with solid testing practices.&lt;/p&gt;

&lt;p&gt;In TDD pairs, the other developer writes a failing test. The other developer follows by writing the code to make the test pass. After a passing test, save the game by committing and proceed to refactor the solution. After the code is clean enough and the test is still passing, commit again. Eventually, you may squash the commits together if needed before pushing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use a Proper IDE
&lt;/h3&gt;

&lt;p&gt;This is a matter of taste, but for myself, tools like &lt;em&gt;JetBrains' Code With Me&lt;/em&gt; and &lt;em&gt;Microsoft's Visual Studio Live Share&lt;/em&gt; are among the best pairing tools. You can also share a terminal session through a multiplexer like &lt;code&gt;tmux&lt;/code&gt;. Still, I would avoid this unless my pair is perfectly comfortable swimming in the terminal and using a terminal editor like &lt;em&gt;Emacs&lt;/em&gt; or &lt;em&gt;Vim&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I have found Visual Studio Live Share the best tool for my pairing sessions. Most of the time, I share my local environment through the remote port forwarding feature. Doing so allows my pair to navigate to the same &lt;code&gt;http://localhost:&amp;lt;port&amp;gt;&lt;/code&gt; address and see the live development environment. I can also share access to my terminal when pairing, which helps them to see what commands I use in my development flow. All this is done with few clicks, and it makes remote pairing almost as frictionless as sitting together.&lt;/p&gt;

&lt;p&gt;While IDEs are geared towards remote pairing, they also work locally, given an ideal network setup and low latencies. For many, it's uncomfortable to share a keyboard (feel the germs! 🦠). Sharing an environment between two or more laptops is the better option.&lt;/p&gt;

&lt;h3&gt;
  
  
  Share the Screen for Context
&lt;/h3&gt;

&lt;p&gt;Nevertheless, do not rely solely on your IDE because sometimes you need to show your pair the precise situation. Especially when working on front-end tasks, make sure you're sharing the right browser tab so your team can see what is happening.&lt;/p&gt;

&lt;p&gt;Platforms we typically use for remote meetings like &lt;em&gt;Google Meet&lt;/em&gt;, &lt;em&gt;Zoom&lt;/em&gt;, and &lt;em&gt;Microsoft Teams&lt;/em&gt; are viable choices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Invest in the Equipment
&lt;/h3&gt;

&lt;p&gt;Make sure you have a decent webcam, headphones and microphone available when pairing.&lt;/p&gt;

&lt;p&gt;Never, ever use your laptop's built-in microphone and speakers. The sound of your typing and the echo of your pairs voice will severely distract their thoughts and abruptly thrash the experience. The book walks an extra mile describing different high-end podcasting setups with proper mic stands and pop filters. Still, you can make do with affordable headsets as long as they are not the cheapest earbuds. A good rule of thumb for headphones is to try them out while pairing for an hour. If your ears hurt, change the headphones.&lt;/p&gt;

&lt;p&gt;You don't always need to have your webcam on. Sometimes it can make pairing feel more personal, but not everyone is comfortable with having cameras on all the time. Discuss this with your pair if needed before your first session. If you choose to have your webcam on, adjust the lighting so you don't end up looking like a black silhouette in front of bright daylight. Shut down any backlight sources and turn on a front light – not too bright – to make your face more visible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ensure a Stable Network Connection
&lt;/h3&gt;

&lt;p&gt;Sloppy connection causes your voice to stutter or become robotic, which is a distraction. However, you don't need 1 GB optic fibre for pairing. As long as you make sure the connection is stable, latencies are low, and there's enough extra bandwidth for audio and video. The rest of the family should not be watching too much Netflix in the other room.&lt;/p&gt;

&lt;p&gt;If you're using Wi-Fi, move as close to the router as comfortable. Plugin the Ethernet cable whenever you can. If the current task does not require using a VPN connection or other proxies, disable them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should I Pair?
&lt;/h2&gt;

&lt;p&gt;In this post, I outlined many benefits, pitfalls and practical tips to ease your journey into pairing. However, the critical question is: when should I pair?&lt;/p&gt;

&lt;p&gt;It is not always easy to decide. In my experience, there are specific tasks that are often better solo. These include but are not limited to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deploying builds and running scripts&lt;/li&gt;
&lt;li&gt;documenting existing features and writing simple instructions&lt;/li&gt;
&lt;li&gt;checking if a reported bug can be reproduced&lt;/li&gt;
&lt;li&gt;doing mundane and routine tasks, which should be automated, anyway&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For all other tasks that require levelling knowledge, learning new concepts, or solving challenging problems, the answer is often &lt;em&gt;yes&lt;/em&gt;. You should always be ready to pair.&lt;/p&gt;

&lt;p&gt;If you need more help to get started with pairing, read the book. You can also contact me for coaching. Let us make the development world better by working together.&lt;/p&gt;




&lt;p&gt;Photo by &lt;strong&gt;Nathan Dumlao&lt;/strong&gt; on &lt;a href="https://unsplash.com/photos/QMhc3D_zwJ0"&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>productivity</category>
      <category>books</category>
      <category>codereview</category>
    </item>
    <item>
      <title>You Can't Grow Yourself Unless You Grow Others</title>
      <dc:creator>Niko Heikkilä</dc:creator>
      <pubDate>Sat, 01 May 2021 08:24:11 +0000</pubDate>
      <link>https://dev.to/futurice/you-can-t-grow-yourself-unless-you-grow-others-3230</link>
      <guid>https://dev.to/futurice/you-can-t-grow-yourself-unless-you-grow-others-3230</guid>
      <description>&lt;p&gt;During our careers, almost everyone has regular one-on-one meetings, sometimes referred to as performance reviews. There we take time to go through our past, present, and future in the context of our jobs. In Futurice, these are called &lt;a href="https://github.com/futurice/myRetro-template/blob/master/MyRetro.md"&gt;&lt;strong&gt;MyRetros&lt;/strong&gt;&lt;/a&gt;, where my supervisor and I specifically look back on the last six months, the current state, and possible future endeavours.&lt;/p&gt;

&lt;p&gt;Often it's not enough to have a minimum of two one-on-ones per year. Given that our supervisors may have many people under their supervision, it's essential that we also grow each other in a &lt;strong&gt;peer-to-peer&lt;/strong&gt; fashion.&lt;/p&gt;

&lt;p&gt;I'm happy to have been mentored by several experienced developers during my career. Still, I'm even more delighted to take that knowledge and pass it on to my mentees. Too often, we might think that advancing in our careers requires supreme technical understanding gained only through decades of hard work. Equally important is our set of soft skills and our capability to grow others.&lt;/p&gt;

&lt;p&gt;We should set clear expectations during our performance reviews to not be promoted unless we have grown others. Our careers should have more meaning than plainly satisfying our egos and boosting our monthly salaries.&lt;/p&gt;

&lt;p&gt;In the last couple of years, I've been actively transforming myself from a regular software developer to a mentor developer. It is challenging, but doing so keeps the spark lit, giving me a direction to progress.&lt;/p&gt;

&lt;p&gt;In this post, I explain how you can transform yourself too.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Several Benefits of Mentoring
&lt;/h2&gt;

&lt;p&gt;Mentoring can sometimes be seen as a very formal relationship where you have to be a genuine senior staff member before mentoring juniors.&lt;/p&gt;

&lt;p&gt;What is often missing from the picture is that we can also mentor each other irrelevant of our current titles. Everyone who has been a part of multiple teams knows what techniques have worked in particular contexts and can carry that wisdom to future projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  You Learn Through Mentoring
&lt;/h3&gt;

&lt;p&gt;A crucial aspect of mentoring is to understand that it is not unidirectional teaching and preaching. As mentors, we must learn and improve based on the feedback we receive from our mentees. I find the traditional division of junior and senior employees holding us back, especially in mentoring.&lt;/p&gt;

&lt;p&gt;I've worked with seniors who have struggled with fundamentals and worked with juniors who have expanded my thinking with much more efficient solutions. In a sense, we are all juniors, but let's call ourselves people for the sake of equality.&lt;/p&gt;

&lt;p&gt;Like our business models should not be strictly about business-to-consumer or business-to-business, our learning should not be from seniors to juniors, but peer-to-peer.&lt;/p&gt;

&lt;h3&gt;
  
  
  You Can Level Team Competencies
&lt;/h3&gt;

&lt;p&gt;When you practice mentoring as part of your daily team routine, you end up levelling your team's competency. As a result, wide knowledge gaps occur more rarely, which is facilitated by continuous knowledge sharing.&lt;/p&gt;

&lt;p&gt;Your design-oriented frontend developer should be able to help with databases and securing backends. Respectively, the developer handling DevOps tasks should be able to help with sketching new user interfaces. Everyone in the team should be comfortable talking to the client, bringing forth new ideas and challenging the old ways of working.&lt;/p&gt;

&lt;p&gt;Furthermore, levelling the team helps to reduce the bus factor. The project doesn't halt when the integration specialist gets sick or when the business director burns out and is set aside for a couple of months. Thus, we need to build a team of solid generalists – also known as T-shaped professionals.&lt;/p&gt;

&lt;p&gt;The desired side-effect of levelling the competencies is increased autonomy. When people are comfortable working in a generalist mindset, they feel a greater sense of freedom regarding what tasks they can pick. As I mentioned in &lt;a href="https://nikoheikkila.fi/blog/the-unsurprising-truth-about-what-motivates-developers/"&gt;my earlier blog post&lt;/a&gt;, &lt;strong&gt;autonomy&lt;/strong&gt; leads to &lt;strong&gt;mastery&lt;/strong&gt; which leads to finding our &lt;strong&gt;purpose&lt;/strong&gt;. The three elements together significantly boost the retention and desire to work in your company.&lt;/p&gt;

&lt;h3&gt;
  
  
  You Contribute to a Better Hiring and Onboarding Experiences
&lt;/h3&gt;

&lt;p&gt;Mentoring begins from the very first moment I meet someone. Interviews are a great place to practice mentoring.&lt;/p&gt;

&lt;p&gt;If a developer is applying to your company either for a full-time position or a summer gig, I can mentor them. How could they improve their cover letter or resume? Did we give them a homework assignment? How could they improve their solution? As a bare minimum, I must give them a thorough code review in return.&lt;/p&gt;

&lt;p&gt;When the new employee is hired, I can become a mentor for them. In Futurice, we have the concept of FutuBuddies, and we are the first ones who welcome the new employees into the house on their first day. From there on, we can agree to meet daily or weekly for a catch-up session which is naturally mentoring.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do We Mentor?
&lt;/h2&gt;

&lt;p&gt;Being a good mentor is a lifelong challenge to which there are no simple answers. We can, however, define techniques every good mentor should possess in their belt. Below are six strategies I've learned to be effective.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't Shoot Down, Encourage
&lt;/h3&gt;

&lt;p&gt;Let's imagine a situation where a new developer approaches me with the idea of rewriting a codebase with another language. Say, for example, they want to switch from Python to Golang or from Java to Kotlin.&lt;/p&gt;

&lt;p&gt;Chances are they have been only thinking it through themselves without proper feedback, and the cost of unnecessary codebase rewrite might be high. As a mentor, I don't shoot down unprepared initiatives. Instead, I encourage them to think more. What if the developer would organise a workshop on the said language? How could this developer mentor the rest of the team to solve domain problems using the new language more efficiently?&lt;/p&gt;

&lt;p&gt;I have always enjoyed recognising the process bottlenecks in my vicinity and trying to optimise them. Unfortunately, some of my ideas have been shot and even ridiculed in public channels in the far past. People have stated that it couldn't possibly work the way I have imagined. While the others might have had a grain of truth in their words, their approach was not encouraging.&lt;/p&gt;

&lt;p&gt;Luckily, I was born with a strong head and resilience (what in Finland we call &lt;em&gt;sisu&lt;/em&gt;), so the mental damage has been minimal. However, for others, aggressive approaches might even end up terminating promising careers.&lt;/p&gt;

&lt;p&gt;As a mentor, I must always keep in mind &lt;a href="https://en.wikipedia.org/wiki/Reciprocity_%28social_psychology%29"&gt;&lt;em&gt;reciprocity&lt;/em&gt;&lt;/a&gt; from social psychology.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"As a social construct, &lt;strong&gt;reciprocity&lt;/strong&gt; means that in response to friendly actions, people are frequently much nicer and much more cooperative than predicted by the self-interest model; conversely, in response to hostile actions they are frequently much more nasty and even brutal."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Wonder why that co-worker has been ignoring you or acting offensively? It might be what you did to them in the past.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't Feed Them with a Spoon, Challenge
&lt;/h3&gt;

&lt;p&gt;Sometimes mentees approach with simple questions. Instead of doing their homework and spoon-feeding answers, mentors ask follow-up questions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Where is the documentation located?&lt;/strong&gt; Where have you looked? Who have you asked?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How can I make my code cleaner?&lt;/strong&gt; Do you see any repeating patterns that could be abstracted to a shared function or library?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Niko is writing crappy code, and it's killing me!&lt;/strong&gt; What are &lt;strong&gt;you&lt;/strong&gt; going to do about it? How can I help to solve this problem without firing Niko?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Don't Reserve, Delegate
&lt;/h3&gt;

&lt;p&gt;As you level up in your career, one of the most rewarding sensations is your increased ability to take on new challenges without feeling like an impostor. The more difficult task at hand, the more confident you are in your ability to tackle it faster and better than others.&lt;/p&gt;

&lt;p&gt;It's not a surprise that mentors do not act like this. Instead of reserving the juiciest tasks to themselves and letting the team do mundane stuff, they delegate. Successful leaders take pride in watching their team complete challenging tasks while staying in the background and occasionally offering help. An approach like this requires rigour, but in the end, you have made your team an unstoppable value delivery machine.&lt;/p&gt;

&lt;p&gt;It's also important to delegate responsibilities. Don't be the only one talking to the client. Let Alex book, prepare and handle the next demo. Let Emma guide the next sprint retro the way they feel would be necessary right now.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't Hold, Share
&lt;/h3&gt;

&lt;p&gt;Many discussions between mentors and mentees follow the pattern of mentees explaining their situation and mentors asking questions. What's crucial and may often be missed is for mentors to share their experience as well.&lt;/p&gt;

&lt;p&gt;Does your mentee have a difficult time focusing on work due to a personal life crisis? Try to share some of your experiences and how you overcame them – without belittling their experiences. While interviewing a candidate, make the event more relaxed by sharing how anxious you too were in one of your first interviews. Sharing is caring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set the Rules
&lt;/h3&gt;

&lt;p&gt;We all work under specific rules. Particular rules like reporting our hours for invoicing or delivering work on time are self-explanatory. There are also many invisible rules – conventions – which could help your team further.&lt;/p&gt;

&lt;p&gt;For version control, small atomic commits and conventional commit messages ensure the codebase history is linear and easier to follow. For quality, test-driven development rules us to write only so much code that our tests pass. For faster delivery, continuous integration rules us to push our work into a shared main branch daily.&lt;/p&gt;

&lt;p&gt;As mentors, we set clear rules on how the team works effectively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do Together
&lt;/h3&gt;

&lt;p&gt;Finally, the shiniest gem of them all is &lt;em&gt;co-creation patterns&lt;/em&gt;. It makes me sad to see how many developers like to work things independently, even in the office. Outdated management views further incentivise solo work. Some managers think that people working on many simultaneous tasks is somehow more effective.&lt;/p&gt;

&lt;p&gt;In truth, we should voraciously swarm to solve problems. We are already doing this early on in the design phase when we co-create with tools like Google Docs, Sketch, and Miro. When it comes to coding, we tend to split tasks as far as possible and let people pick their favourites to work.&lt;/p&gt;

&lt;p&gt;As mentors, we understand that our team is a cohesive unit and not a random bunch of individuals. Lead by example. Always be ready to pair with different people in your team. Experiment and gather feedback regarding what worked and who enjoyed it. Rotate pairs and iterate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Relationships Through Mentoring
&lt;/h2&gt;

&lt;p&gt;Mentoring is an effective way of getting to know our co-workers. To give meaningful feedback and advice, we should have established a relationship with the other person. Do we know what our mentees are interested in and what goals they have for their career?&lt;/p&gt;

&lt;p&gt;As a mentor, I can inspire these interests and goals myself. Suppose I'm practising clean code and extreme programming principles in a team and continuously showing how I build quality while delivering remarkable results on time. In that case, others will surely follow me with interest and attempt to learn. They can be set off to a great path of software craftsmanship.&lt;/p&gt;

&lt;p&gt;Naturally, as human beings, everything we speak of doesn't have to be professional. After a weekend, I can mind the team member who had to take their cat to a vet on Friday. How is the cat doing now? Continuously showing interest in people's lives helps gain trust and respect, which goes a long way in helping you work better as a team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Traits of a Great Mentor
&lt;/h2&gt;

&lt;p&gt;Finally, here is a non-exhaustive list of traits that matter when developing yourself as a mentor.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge.&lt;/strong&gt; What experience and skills do you possess. How extensive is your professional background?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authority.&lt;/strong&gt; Who are you? Why should people listen to you? Do other people know what you have achieved?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confidence.&lt;/strong&gt; How confidently can you express your ideas and solutions?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Charisma.&lt;/strong&gt; What kind of body language do you use? How does your voice sound?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emotional Intelligence.&lt;/strong&gt; How easy it is for people to trust you. How well can you empathise with others? How deeply can you collaborate?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team reputation.&lt;/strong&gt; How successful your team and its members are in the eyes of the organisation and client?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thought leadership.&lt;/strong&gt; Are you a recognised blogger or speaker? Are people lining up to work with you?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep calm and carry on &lt;strong&gt;mentoring&lt;/strong&gt;!&lt;/p&gt;




&lt;p&gt;This is the second post about observations I gained from &lt;a href="https://principal.dev/"&gt;&lt;strong&gt;The Principal Developer&lt;/strong&gt;&lt;/a&gt; workshop. Read also &lt;a href="https://nikoheikkila.fi/blog/reducing-the-lead-times-with-littles-law/"&gt;my earlier post&lt;/a&gt; on reducing the work-in-progress and increasing throughput following Little's Law.&lt;/p&gt;

&lt;p&gt;Photo by &lt;strong&gt;John Schnobrich&lt;/strong&gt; on &lt;a href="https://unsplash.com/photos/2FPjlAyMQTA"&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>career</category>
      <category>psychology</category>
      <category>leadership</category>
      <category>management</category>
    </item>
    <item>
      <title>How Spice Program supported my creation of 235</title>
      <dc:creator>Juha-Matti Santala</dc:creator>
      <pubDate>Mon, 19 Apr 2021 12:43:15 +0000</pubDate>
      <link>https://dev.to/futurice/how-spice-program-supported-my-creation-of-235-2cjj</link>
      <guid>https://dev.to/futurice/how-spice-program-supported-my-creation-of-235-2cjj</guid>
      <description>&lt;p&gt;At the end of 2020, I decided to finally start learning Rust. For over a year before that, I had been playing with the idea of it but it took me all the way until the end of 2020 to get started. Rust is an interesting language for me, as I have mostly programmed with languages like Python and Javascript. Rust is something quite different and from the outside looking in, its community looked great as well.&lt;/p&gt;

&lt;p&gt;After my initial steps with the language where I was solving &lt;a href="https://adventofcode.com/"&gt;Advent of Code&lt;/a&gt; puzzles, I decided to build my first software with &lt;a href="https://www.rust-lang.org/"&gt;Rust&lt;/a&gt;. I'm an active command-line user so for me the obvious first choice was building a CLI tool. Hence, on a dark wintery Friday evening, I started working on a hobby project that would become &lt;a href="https://hamatti.github.io/nhl-235/"&gt;235&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's 235?
&lt;/h2&gt;

&lt;p&gt;For the small subset of readers who live in Finland and have been fans of the &lt;a href="https://www.nhl.com/"&gt;National Hockey League (NHL)&lt;/a&gt; for a long time, the number 235 rings a bell. For decades, the Finnish broadcasting company Yle has provided NHL results on their &lt;a href="https://yle.fi/aihe/tekstitv"&gt;teletext service on the page 235&lt;/a&gt;. For me, and many others like me, it's a habit to start every day by checking the page 235 to see the results of previous night's games.&lt;/p&gt;

&lt;p&gt;Inspired by this cultural phenomenon, I decided to build a tool that combined the minimalist and iconic style of that teletext page with data from an API for NHL results.&lt;/p&gt;

&lt;p&gt;235 is my first Rust program and it provided me a great opportunity to learn a new language – the spec was small and well-defined - it didn't require complex advanced features of the language - I knew it would be useful for me and people like me on a daily basis.&lt;/p&gt;

&lt;p&gt;For learning &amp;amp; hobby projects, that combination of usability, simplicity and small scope is key. I know I'm not the only one with dozens of unfinished projects that grew too big from the original idea and with limited time to work on, personal projects never ended up being finished.&lt;/p&gt;

&lt;p&gt;235 is published with MIT license and &lt;a href="https://github.com/Hamatti/nhl-235"&gt;the code can be found on GitHub&lt;/a&gt;. &lt;em&gt;(The project is called nhl-235 because Rust doesn't allow project names to start with a digit.)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Distributing executables is a very different world than web apps in browsers
&lt;/h2&gt;

&lt;p&gt;As I mentioned above, this is my first Rust project and coming from a background of really different languages, there has been a lot to learn. This is the first time I've been working with binary executables. For almost two decades, I've loved web for its distribution model — you write code, deploy to server and it's updated for everyone. With executables, people need to proactively update their versions which means I need to think about new ways to reach them and communicate.&lt;/p&gt;

&lt;p&gt;Certain things are also much slower for me to develop. One thing I really enjoy with Python and Javascript (both given their dynamic style and my experience writing them) is how I can focus much more into the content and domain, and much less on meta level things. I recently shared &lt;a href="https://hamatti.org/posts/learning-rust-2-option-result/"&gt;my thoughts about Option and Result types on my blog&lt;/a&gt;. Even though I have a theoretical understanding of how they work and what their benefits are, my development too often comes to a halt and I need to rethink and refactor things a lot more with Rust.&lt;/p&gt;

&lt;p&gt;Luckily, the Rust community is great and I've gotten so much help in my learning journey from local and global Rust developers who have been so helpful and compassionate when I've been stumbling around trying to understand the basics of the language and how to write it.&lt;/p&gt;

&lt;h2&gt;
  
  
  And my employer supports my work on 235
&lt;/h2&gt;

&lt;p&gt;In 2013, &lt;a href="https://futurice.com/blog/futurice-open-source-program-the-spice-program"&gt;Spice Program was born&lt;/a&gt; as our open source and social impact program. Part of it is the support for open-source contributions of Futuriceans. In a nutshell: when you work at Futurice and do open source work on your own time, we support that with a monetary bonus of 15 euros/hour, capped at 30 hours/month.&lt;/p&gt;

&lt;p&gt;In 2019, &lt;a href="https://futurice.com/blog/futurice-professional-volunteering-bonus-extended"&gt;we expanded it to be more inclusive to people in the company who don't code&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The key purpose of our volunteering bonus is to make use of and develop your professional skills for social impact. For us, open source is always considered social impact, but there are many other ways to achieve that impact.&lt;/p&gt;

&lt;p&gt;When a designer helps to create a beautiful web presence for a poor non-profit on an important mission, it should count, even if the graphical assets cannot be properly published as open source.&lt;/p&gt;

&lt;p&gt;When an HR specialist helps in organising and running code schools for kids, it should count, even if there are no digital deliverables.&lt;/p&gt;

&lt;p&gt;When a business advisory professional teaches principles of lean service creation to an NGO striving to make sure whales don't start smoking, it should count.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;From a perspective of a developer, I'm happy that I get to build things that I want to see in the world and be appreciated for that with a small bonus.&lt;/p&gt;

&lt;p&gt;And even more, it enables and incentivises me to learn more and to contribute to the open source ecosystem. With its flexibility, I'm not forced to do anything or have to make choices between other things in live and coding: sometimes I spend a weekend on a personal passion project and sometimes it's months that I don't code anything on my free-time.&lt;/p&gt;

&lt;p&gt;One thing I realised only after I had built the first version of my 235: &lt;a href="https://github.com/peruukki/nhl-score-api"&gt;the API I decided to use&lt;/a&gt; was also developed with Spice support back in the day. That's the beauty of the open source ecosystem and community: &lt;strong&gt;things you build today can be fundamental in helping others build new things.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Over the past few months, we've been averaging at roughly 700 hours of Spice contributions per month. You can find more about the &lt;a href="https://spiceprogram.org/"&gt;Spice Program here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>rust</category>
      <category>commandline</category>
    </item>
    <item>
      <title>Reducing the Lead Times with Little's Law</title>
      <dc:creator>Niko Heikkilä</dc:creator>
      <pubDate>Tue, 30 Mar 2021 18:18:10 +0000</pubDate>
      <link>https://dev.to/futurice/reducing-the-lead-times-with-little-s-law-1ok1</link>
      <guid>https://dev.to/futurice/reducing-the-lead-times-with-little-s-law-1ok1</guid>
      <description>&lt;p&gt;There's a fascinating law of mathematical theory applicable to agile software development, which helps you deliver features faster without sacrificing quality. It's called &lt;a href="https://toggl.com/track/littles-law/"&gt;&lt;strong&gt;Little's Law&lt;/strong&gt;&lt;/a&gt;, and it dictates that the average lead time of delivery is the team's work in progress amount divided by its throughput.&lt;/p&gt;

&lt;p&gt;First, let's define the terms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Work in progress&lt;/strong&gt; (WIP) is the number of backlog items the team is currently working on. These items are not yielding value for the customer. WIP can be determined by counting those cards in your project board that are not in the &lt;em&gt;Backlog&lt;/em&gt; column and not in the &lt;em&gt;Done&lt;/em&gt; column but somewhere in between.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Throughput&lt;/strong&gt; is the measured amount of backlog items a team can complete in a fixed period, which is usually a day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The team has 20 tasks in progress, and its average throughput is four cards/day. Following the law, this gives an average lead time of &lt;strong&gt;20/4&lt;/strong&gt; = &lt;strong&gt;5&lt;/strong&gt; days.&lt;/p&gt;

&lt;p&gt;To foster an effective software development process, we should target our efforts towards shortening the lead time. Following the laws of mathematics, we can achieve this by limiting the WIP and increasing the throughput.&lt;/p&gt;

&lt;p&gt;Often we fool ourselves to think that high WIP and high throughput are synonymous with performant processes, but this leads to stagnation, low motivation, low innovation, and burnouts.&lt;/p&gt;

&lt;p&gt;In this post, I attempt to share approaches to doing it right, but your mileage may vary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reducing the Work in Progress
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A golden rule of limiting the WIP is to &lt;strong&gt;stop starting and start finishing&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Total WIP should be smaller than the number of people in the team. If possible, strive for a WIP limit of &lt;strong&gt;one&lt;/strong&gt;, but mind that it's not always a feasible choice.&lt;/p&gt;

&lt;p&gt;When working under a strict WIP limit, you should leverage the daily stand-up with your team for prioritizing and selecting the tasks for today. If the WIP limit is reached, nobody is allowed to start new work. Instead, everybody should help finish the ongoing work – be it developing, reviewing, testing, or deploying a new feature.&lt;/p&gt;

&lt;p&gt;Teams wanting to reduce WIP should focus as many people as possible on as few tasks as possible. Some people think this only applies to Kanban, but Scrum too has a specific technique for this: &lt;a href="https://www.scruminc.com/swarming-instantly-boost-scrum-team-productivity/"&gt;&lt;em&gt;swarming&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Pair/mob programming is also a natural and effective enemy towards high WIP. Instead of distributing one task for each developer, make them solve the problem together. Pairing and mobbing are not only for programming, as you can also practice design, testing, monitoring, leadership, and many other tasks together.&lt;/p&gt;

&lt;p&gt;Essentially, when people pile on a single task, they can design, develop, test, and deliver it more cost-efficiently. Mobbing has its limits, though, and we should find balance through careful studying. Too many people working on a single task invokes &lt;a href="https://www.investopedia.com/terms/l/lawofdiminishingmarginalreturn.asp"&gt;the law of diminishing returns&lt;/a&gt; and eventually hurts the performance.&lt;/p&gt;

&lt;p&gt;Additionally, to make the mobbing work, all teams should be cross-functional, consisting of designers, developers, testers, and deployers with a well-balanced skill set. These teams deliver &lt;a href="https://en.wikipedia.org/wiki/Vertical_slice"&gt;&lt;em&gt;vertical slices&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Note that the latter two roles don't often require separate people because developers can test and deploy the changes themselves. In case you have an independent QA team, make sure to involve them early on in the process, tear down the walls, and enable deep collaboration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Increasing the Throughput
&lt;/h2&gt;

&lt;p&gt;There are three actions a company can do to increase its teams throughput.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Hire more people, but not too much (consider &lt;a href="https://jasoncrawford.org/two-pizza-teams"&gt;a two-pizza team&lt;/a&gt; 🍕🍕 the maximum size – leaving the exact number for you to decide).&lt;/li&gt;
&lt;li&gt;Make the team more proficient by fostering &lt;a href="https://en.wikipedia.org/wiki/Extreme_programming#Principles"&gt;Extreme Programming principles&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Eliminate patterns of waste (see below).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I consider XP principles and eliminating waste very effective actions here. Below are the most common forms of waste you may encounter in your development process.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Partially Done Work
&lt;/h3&gt;

&lt;p&gt;We cancel or postpone tasks, our work is stuck in the testing queue, and essential features are waiting for deployment. Swarming and a low WIP limit ensures the team is focused on a fixed number of tasks at any given time. Remember, partially done work does not yield value.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Overproduction
&lt;/h3&gt;

&lt;p&gt;We are often tempted to design non-trivial, abstract, and flexible code for the speculative future, which might never happen. We may add complex data analysis and charts functionality to the project instead of adding an &lt;strong&gt;Export as CSV&lt;/strong&gt; button. Instead, think about how you can solve problems with less or no code.&lt;/p&gt;

&lt;p&gt;We might drive ourselves into an endless loop during refactoring code where we polish secondary or unimportant code. Such code might not even change that often nor slow us down, so why bother with it?&lt;/p&gt;

&lt;p&gt;Alternatively, we apply the best development principles while developing throw-away prototypes. Refactor only so much to keep the code maintainable and easy to understand until the next time it's changed.&lt;/p&gt;

&lt;p&gt;We might deliver features with low or negative user impact. We should carefully observe and respond to UX metrics and customer feedback.&lt;/p&gt;

&lt;p&gt;We adopt trendy technologies and tools, whereas the tools we already know how to use would suffice (see &lt;a href="https://en.wikipedia.org/wiki/Marchitecture"&gt;&lt;em&gt;Marchitecture&lt;/em&gt;&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;We chase 100% test coverage for our unit, integration, and acceptance test suites. Still, we ship design defects that are difficult to detect and recover from in case of disasters. Customer finding out a bug in production before your team does is a bad, bad thing.&lt;/p&gt;

&lt;p&gt;Our product owners maintain huge backlogs with more user stories than needed for the next few sprints. &lt;a href="https://www.martinfowler.com/bliki/Yagni.html"&gt;&lt;em&gt;YAGNI&lt;/em&gt;&lt;/a&gt; rule is the single best defence shielding us from this.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Waiting, Delays, and Handoffs
&lt;/h3&gt;

&lt;p&gt;We are maintaining a slow and unstable regression test suite relying on external integrations. Running it keeps us waiting for results due to constant failures. Additionally, the build server is shared with other teams and maintained by a fantasy creature referred to as the &lt;em&gt;DevOps Engineer&lt;/em&gt;. Why not use on-demand testing environments, or even better: run all the tests locally?&lt;/p&gt;

&lt;p&gt;For the better part of the lead time, the code is waiting for someone to review it. Some features require review from a senior developer who is at the moment drinking mojitos in Bali. Align the team's skills so knowledge gaps can't happen.&lt;/p&gt;

&lt;p&gt;Teammates are involved in multiple projects, and the same human resources are being shared across squads. Build long-lasting teams with domain expertise as a core objective.&lt;/p&gt;

&lt;p&gt;Unexpected, critical, and non-trivial production incidents might pop up in the middle of other work delaying the feature work further. Good observability and XP principles protect us from this.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Rework
&lt;/h3&gt;

&lt;p&gt;Pull requests are bounced back and forth between the author and reviewer in asynchronous code reviews. Use &lt;a href="https://trunkbaseddevelopment.com/"&gt;trunk-based development&lt;/a&gt;, &lt;a href="https://martinfowler.com/articles/on-pair-programming.html"&gt;pair programming&lt;/a&gt;, and a &lt;a href="https://martinfowler.com/articles/continuousIntegration.html"&gt;continuous integration&lt;/a&gt; mindset to avoid this.&lt;/p&gt;

&lt;p&gt;We need to re-implement solutions due to misunderstood requirements or fix the same bugs twice. If the product owner can't define the requirements, go and talk to the customer yourself. Use &lt;a href="https://en.wikipedia.org/wiki/Behavior-driven_development"&gt;behaviour-driven development&lt;/a&gt; to make sure work is only considered done when acceptance criteria are met.&lt;/p&gt;

&lt;p&gt;Due to poor communication, we need to answer the same questions, or the lack of automation forces us to run mundane routines repeatedly. We should capture the necessary knowledge in software documentation and &lt;a href="https://adr.github.io/"&gt;architectural decision records&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Non-value added activities
&lt;/h3&gt;

&lt;p&gt;Long-lived feature branches force us to rebase continuously and deal with resulting merge conflicts. Stop branching and start integrating.&lt;/p&gt;

&lt;p&gt;At the end of each sprint, we have a retrospective without action points and assigned responsibilities. Shake up the process and start setting action points.&lt;/p&gt;

&lt;p&gt;Our calendars are filled with never-ending meetings and attempts to reach consensus without making progress (impasse). Apply Basecamp's &lt;a href="https://basecamp.com/guides/how-we-communicate"&gt;internal communication strategies&lt;/a&gt; to heal this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Little's law is one of the most powerful drivers in serious software development efforts because of its simplicity. You don't have to maintain complex models or calculations to observe your delivery performance – a fractional operation does it for you.&lt;/p&gt;

&lt;p&gt;I gained the majority of these observations in reducing the WIP and eliminating waste during &lt;a href="https://principal.dev"&gt;&lt;strong&gt;The Principal Developer&lt;/strong&gt;&lt;/a&gt; workshop. Workshops like these provide invaluable tools altering the way you think about processes, teams, and cultures. I argue they offer a more significant return-on-investment in your career than simply learning frameworks and tools like React or Docker.&lt;/p&gt;




&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@epicantus?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Daria Nepriakhina&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/agile?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>agile</category>
      <category>productivity</category>
      <category>leadership</category>
      <category>architecture</category>
    </item>
    <item>
      <title>How we co-created our technology strategy – and what we learned in the process</title>
      <dc:creator>jushac</dc:creator>
      <pubDate>Wed, 24 Mar 2021 10:25:52 +0000</pubDate>
      <link>https://dev.to/futurice/how-we-co-created-our-technology-strategy-and-what-we-learned-in-the-process-59o0</link>
      <guid>https://dev.to/futurice/how-we-co-created-our-technology-strategy-and-what-we-learned-in-the-process-59o0</guid>
      <description>&lt;p&gt;&lt;strong&gt;Building a strategy is always an involved process. This past fall, we took it upon ourselves to build a technology strategy for Futurice leading up to the year 2022. By structuring the work in a smart way, we were able to make it fairly easy on ourselves and complete it in less than three months. In addition to an actionable tech strategy, the process also yielded a ton of important lessons.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The primary focus of our strategy work was on the business landscape in Finland, but naturally many of the themes and trends around it are global. The main reason for building the strategy was to create clarity and focus, both for our people within the technology domain and others around it, like sales and HR, or HC as we like to call it – short for Human Care.&lt;/p&gt;

&lt;p&gt;Additionally, with a technology strategy in place, we are better equipped to take a stand on what we want to do and what we don’t. It also gives us a handy tool to help guide our focus and efforts in the long term, and conversely, it will also be an instrument we can check retrospectively and see which bets we got right and which ones we didn’t. Having those insightful "Hey, we nailed that one" and "Yeah, didn't see that coming" moments.&lt;/p&gt;

&lt;p&gt;In order for our tech strategy to do its job properly, we needed it to be an inspiring read for our technologists and touch their daily life at work. On the other hand, it would also have to be easy for our business people and other stakeholders to utilize in their work. Not exactly an easy task.&lt;/p&gt;

&lt;p&gt;Our desired level of detail was set to be tangible enough to apply to everyday work, but not get all the way down to the nitty-gritty. We can expect to see lots of changes in tech over the next two years, so there’s little use trying to make guesses on an unnecessarily detailed level.&lt;/p&gt;

&lt;p&gt;When creating our strategy, we wanted to get as much information from our tech community as possible. It was clear from the get-go that the strategy would be the culmination of our technological knowledge gathered from the community, and not just a handful of key people. All told, the process spanned little more than two calendar months and unfolded over the course of about 10 workshops of various sizes.&lt;/p&gt;

&lt;h2&gt;
  
  
  From the high level to the day-to-day
&lt;/h2&gt;

&lt;p&gt;The strategy was designed to work on all levels from the bird’s-eye view all the way to more specific grassroots items with the level of technical details increasing when moving from the higher-level items to more detailed issues, like the use of TypeScript in frontend development. The transition from "fluffier" themes towards the hardcore technology landscape felt natural and gave our strategy more structure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CPE9Nm3K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e08ouf02b3lya6h3xm5h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CPE9Nm3K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e08ouf02b3lya6h3xm5h.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  Figure 1: A gradual transition from high level items to technical details
&lt;/h6&gt;

&lt;p&gt;First, we needed to align our technology strategy with our wider, company level strategy. We did this by binding our company level items to technological items on the country level to create a natural progression. At the same time, this also helped outline what kind of projects we take on, and with what kinds of teams. And so, the basis for the rest of our technology strategy was set.&lt;/p&gt;

&lt;p&gt;Next up, we created a country level vision for our technology business. One can always argue whether this is necessary, but we felt that there was a need for a simple and concise statement that encapsulates what we stand for:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Inspire our clients to use technology in creative ways to solve complex problems for their customers, employees and society at large.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And building on the above statement, we also defined a set of principles that we see as overarching guidelines of how we want to run our technology practice. This step takes us closer towards concrete things. The roughly dozen items on that list contain statements like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Our technology choices are guided by feasibility, maintainability, and business rationale. We enable people to evolve within the tech domain and outside of it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Many of these are things that go without saying, but putting them in writing makes them more effective and something we can use for guidance when making decisions in the future.&lt;/p&gt;

&lt;p&gt;Naturally, a strategy also requires us to have goals. These goals are something we should be able to reach with the right actions. They describe our desired state in market position, people development, partnerships and the kinds of projects we do. Since these are long-term items, they require incremental progression to reach them. This progression happens through concrete actions within all of our specialty areas – hence the next and most concrete part of the strategy, specialty areas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M2VdVCpY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/agkrmxfukq0xs9zidq7f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M2VdVCpY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/agkrmxfukq0xs9zidq7f.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  Figure 2: Inputs to the strategy, its alignment outside the tech domain, and use after the process
&lt;/h6&gt;

&lt;h2&gt;
  
  
  Specialty areas
&lt;/h2&gt;

&lt;p&gt;The various areas we cover technology-wise is massive, and basically extends from mobile to cloud infrastructure, and everything in-between. To make the work more manageable we ended up splitting it into these specialties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web development (frontend and backend)&lt;/li&gt;
&lt;li&gt;Mobile development&lt;/li&gt;
&lt;li&gt;Data science and data engineering&lt;/li&gt;
&lt;li&gt;Cloud and architecture&lt;/li&gt;
&lt;li&gt;Technology in the business context&lt;/li&gt;
&lt;li&gt;Agile delivery&lt;/li&gt;
&lt;li&gt;Partnerships&lt;/li&gt;
&lt;li&gt;Tech community&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Naturally, there is lots of overlap between all of these – for example, consider Firebase, which can land either on Cloud, Web development or Mobile development. When such issues came up, we simply made an educated judgement call. For the end result, it didn't really matter which side of the fence the items were on.&lt;/p&gt;

&lt;p&gt;In that list of specialties, two areas – Partnerships and Tech community – stand out as slightly different from the rest, but both nonetheless involve analysis of our current state and include focus points for the next two years.&lt;/p&gt;

&lt;p&gt;Each specialty needed to reflect on three main points:&lt;/p&gt;

&lt;p&gt;What are we good at now and where do we have room for improvement?&lt;br&gt;
What trends affect us globally and through our clients?&lt;br&gt;
What should we focus on for the next two years?&lt;br&gt;
Again, we wanted these topics to give us a nice flow. The first step would be to look at where we are now with a CSA-type of approach. We did this by analyzing our data on what kind of skills our people have and what we've been using in our projects. This gave us a good picture on where we are and where the market is at regarding the specialties. This yielded us insights like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In front-end development, we have 195 people skilled with React and the most common choice in our projects is React with TypeScript. In web development, we are experts at building complex, high-performing and scalable web applications like the Sanoma News Platform.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We then started researching global trends, our clients’ future needs and our own views on where the world would be going. The goal here was to create a clear and focused outlook from the point of view of technology-enabled business. Naturally we tried not to embrace the whole world and instead stay focused on technology in our context. On the other hand, this also meant technology in almost all business verticals – which is not exactly a small focus... This gave us outputs like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;While in most cases APIs serve a specific purpose and it may not be necessary or even desirable to centralize everything, there is a clear trend towards a more structured API development strategy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After compiling these two parts it was finally time to make choices on where to focus based on the background work done so far. This part also included choosing where not to focus.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The growing need from our clients to move their on-premises monoliths to serverless cloud environments also requires us to keep building our capabilities in that area.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The final result was a package that described what to do next as well as the background behind that decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we organized the process
&lt;/h2&gt;

&lt;p&gt;The building blocks that eventually made up the core insights within each specialty area, as well as the underlying trends, were generated by assigning people the responsibility to facilitate the process under each specialty area, and gather information from our technology community and other sources.&lt;/p&gt;

&lt;p&gt;In practice, this meant looking into lots of data sources and workshopping with the relevant people. In the end, the results were distilled into a more condensed format, while all the material that went into them and was created during the process, like slides, documents, Miro boards etc. were of course stored for future reference. Once all the specialties were packaged, it was a question of doing a once-over and checking that everything was aligned, logical and made sense business-wise.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0050srBU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yknmbe5o9wbaxs97upd8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0050srBU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yknmbe5o9wbaxs97upd8.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  Figure 3: Involving people outside the core team benefits the knowledge gathering phase
&lt;/h6&gt;

&lt;p&gt;Our approach was highly participatory, and it involved dozens and dozens of contributors from across the company. A big part of why we did it this way was to be inclusive throughout the process. Managing contributions from a large number of participants always runs the risk of devolving into a sprawling mess, but we were able to avoid this by introducing precisely the right amount of structure – not too rigid, but chaotic either.&lt;/p&gt;

&lt;p&gt;Looking back, I feel that this was by far the leanest strategy process I have ever been involved with, but at the same time, we ended up with a very clear and usable document going forward. It will also be an important input for planning our future activities around recruitment, training and business.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;In its plainest version, a strategy is just a document in a cloud folder. That is why the road that took us there was already important in and of itself, having involved multitude of technologists and business people. Right now, we are in the process of planning the actions based on the strategy, and agreeing on them with all the stakeholders within the company. To ensure the planned actions are executed, they will be a part of our quarterly OKRs on the country and/or team level.&lt;/p&gt;

&lt;p&gt;To remain agile, we will have strategy reviews every six months. The changes in technology never stop, so we need to assess what we have been doing and adjust accordingly. Now that the strategy is already in place, adjustments are much easier to make.&lt;/p&gt;

&lt;p&gt;As a byproduct of this work, we have spun off the Futurice Tech Trends 2021–2022 report from the strategy work, and made it into a standalone website and document that describe the driving technology trends affecting our business and that of our clients. Definitely an interesting read for anyone working in the technology industry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start with the “why”.&lt;/strong&gt; Make it super clear why you are doing the strategy, and keep that as your north star.
&lt;strong&gt;Know your audience.&lt;/strong&gt; Know who you are trying to reach, and speak their language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Involve technologists.&lt;/strong&gt; Use your people to gain the best possible overall picture as well as their buy-in. A good technology strategy does not come from the heads of only a few senior experts. On the other hand – make sure to keep moving, lead the process, and avoid analysis paralysis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don’t forget the business.&lt;/strong&gt; Technology is never an island. Every tech decision needs a business rationale, and you will also need the business buy-in. Furthermore, business has unique knowledge on client needs and the overall market situation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make it tangible.&lt;/strong&gt; Company level strategies can be more high level and inspirational, but a tech strategy has to be something that people can relate to in their everyday work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relentless actions.&lt;/strong&gt; Align your actions with the strategy, and relentlessly drive them forward. Otherwise the strategy will amount to nothing more than just another document on your cloud drive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Establish follow-up.&lt;/strong&gt; Schedule a review every six months and go through the strategy. What did we get right? What needs adjusting? After the foundation is there, fine tuning will be much easier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this raised any comments or questions, I'm happy to hear them in the comments section.&lt;/p&gt;

&lt;p&gt;This post was originally published in the Futurice blog here --&amp;gt; &lt;a href="https://futurice.com/blog/how-we-co-created-our-tech-strategy"&gt;Link&lt;/a&gt;&lt;/p&gt;

</description>
      <category>technology</category>
      <category>strategy</category>
      <category>developers</category>
      <category>organization</category>
    </item>
    <item>
      <title>Blocking Time for Tasks with Toggl</title>
      <dc:creator>Niko Heikkilä</dc:creator>
      <pubDate>Mon, 22 Mar 2021 07:05:39 +0000</pubDate>
      <link>https://dev.to/futurice/blocking-time-for-tasks-with-toggl-2jic</link>
      <guid>https://dev.to/futurice/blocking-time-for-tasks-with-toggl-2jic</guid>
      <description>&lt;p&gt;For people doing mainly project work, planning daily tasks is a constant struggle, which can cause severe issues with productivity and mental well-being.&lt;/p&gt;

&lt;p&gt;As a software developer with multiple projects on my daily schedule, I used to waddle in a sea of chaos. Attempting to swim and survive throughout my days impacted my work in many ways. The loss of context made it difficult to focus on tasks, which caused my productivity to halt and gave a diminishing sense of accomplishment in return.&lt;/p&gt;

&lt;p&gt;Furthermore, when I needed to recall what I had been doing on a given day, I had to resort to checking my browsing history. As you might guess, it had little relevance to what I had worked. Daily standup meetings mainly were a burden where I was supposed to figure out what I did yesterday and what shall I do today. Similarly, the reported hours contained some time to this project and some time to that.&lt;/p&gt;

&lt;p&gt;The technique of surviving with simple to-do lists — where &lt;strong&gt;Todoist&lt;/strong&gt; is still the king — I had learned previously was suitable for single-project environments. There I could split my days between writing and reviewing code in one domain. It didn't scale at all for multiple sequential tasks. Fortunately, later on, I discovered the magnificent technique called &lt;a href="https://todoist.com/productivity-methods/time-blocking"&gt;&lt;em&gt;time blocking&lt;/em&gt;&lt;/a&gt;, where every minute of the day is given a purpose.&lt;/p&gt;

&lt;p&gt;Let me tell you how.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basics of Time Blocking
&lt;/h2&gt;

&lt;p&gt;Time blocking means saving time for important — not necessarily urgent — tasks in your calendar. With your chosen tool, start by dividing a day into slices and decide &lt;strong&gt;one and only one theme&lt;/strong&gt; you're working on during a particular time block.&lt;/p&gt;

&lt;p&gt;Don't worry. With time blocking, you get to keep your regular breaks and days off. This post is not one of those foolish blurbs hailing 60+ hour work weeks and waking up 4:30 every day to solve productivity issues.&lt;/p&gt;

&lt;p&gt;After dividing your days into slices, your day might look a bit like in the picture below. Note that the themes are only examples, and I usually write those down precisely to help me later recall what I worked on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LdGm7snA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l8xm079f7lh5jeedg4b6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LdGm7snA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l8xm079f7lh5jeedg4b6.png" alt="Time blocking example sketch"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do I Split the Day?
&lt;/h2&gt;

&lt;p&gt;My typical day is as follows. Due to the dynamic nature of my profession, some variations may occur, but mostly it's easy to stick with the plan.&lt;/p&gt;

&lt;h3&gt;
  
  
  From Morning to Noon
&lt;/h3&gt;

&lt;p&gt;I start working between 8–9 in the morning and sketch my time blocks for the day. Next, I begin responding to urgent stuff like emails and messages before clearing out the path for focusing on tasks. Then I grab a few planned tasks and complete them at my own pace.&lt;/p&gt;

&lt;p&gt;After the first round of intensive focus, I attend a daily standup with my team. Here I leverage the time blocks from yesterday and today while explaining my status and possible blockers. If any meetings have been invited, they are usually held around mid-day.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lunch Break / Time Off
&lt;/h3&gt;

&lt;p&gt;With the first half of the day completed, I allow myself to take a decent amount of time off eating, drinking and relaxing. Together with the daily shutdown, it's one of the most important events of the day, and you shouldn't skip it.&lt;/p&gt;

&lt;h3&gt;
  
  
  From Noon to Afternoon
&lt;/h3&gt;

&lt;p&gt;When I return to focus work, I then go over the pending code reviews or help team members debugging issues. This kind of work fits my afternoon mental state as most of the urgent stuff has already been done and now there's time to shine some creative light.&lt;/p&gt;

&lt;p&gt;To call it a day, I begin slowing the pace down around 16–17 and make note of all the tasks I've achieved. Shutting down at regular times is essential for the mind to function correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Toggl Track to the Rescue
&lt;/h2&gt;

&lt;p&gt;I first tried using traditional paper and the &lt;strong&gt;Remarkable&lt;/strong&gt; tablet for time blocking, but having my schedules tied to one device quickly drove me to use &lt;a href="https://track.toggl.com"&gt;&lt;strong&gt;Toggl Track&lt;/strong&gt;&lt;/a&gt;. It comes with excellent desktop, mobile, and web apps allowing me to access and edit my schedule from virtually anywhere. I don't use Toggl's flagship timer feature that much. The very intention of time blocking is to plan and control my time spent instead of spontaneous tracking.&lt;/p&gt;

&lt;p&gt;Toggl web app has a nifty calendar view which is ideal for drawing blocks of time with a mouse and marking them to specific projects. You can also extend it with your calendar. I've hooked my Google work calendar into it, which allows me to duplicate each calendar event as a time block. Fun fact: when you're involved in a project with all-day meetings the time-blocking is automatically there, but it will hurt you in other ways.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Command-Line? Why Not?
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i3JOwpme--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nikoheikkila"&gt;
        nikoheikkila
      &lt;/a&gt; / &lt;a href="https://github.com/nikoheikkila/hours"&gt;
        hours
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A command-line companion for the Toggl Track software. Check the README for supported features.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
⏰ Hours&lt;/h1&gt;
&lt;p&gt;Working as a consultant requires you to mark your billed project hours periodically for invoicing. This is boring but luckily &lt;a href="https://toggl.com/" rel="nofollow"&gt;&lt;strong&gt;Toggl&lt;/strong&gt;&lt;/a&gt; is there to help. Unfortunately, not everyone is using it directly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hours&lt;/strong&gt; is a command-line tool built with &lt;strong&gt;Go&lt;/strong&gt; for integrating to Toggl Track. Currently, it supports the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;listing saved time entries in various formats&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Upcoming and planned features are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;creating new time entries&lt;/li&gt;
&lt;li&gt;deleting saved time entries&lt;/li&gt;
&lt;li&gt;starting and stopping the timer on certain tasks&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
Documentation&lt;/h2&gt;
&lt;p&gt;Documentation is divided into the following sections.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://raw.githubusercontent.com/nikoheikkila/hours/main/docs/01-installation.md"&gt;Installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://raw.githubusercontent.com/nikoheikkila/hours/main/docs/02-listing.md"&gt;Listing time entries&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nikoheikkila/hours"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;However, one thing I was missing from Toggl was a performant terminal app. So, as a hobby project and because my current employer sponsors the personal time spent in open-source, I started writing one. Enter &lt;a href="https://github.com/nikoheikkila/hours"&gt;&lt;strong&gt;Hours&lt;/strong&gt;&lt;/a&gt;. It's a lightweight, single-binary, open-source terminal companion for Toggl written in &lt;strong&gt;Go&lt;/strong&gt;. At the moment, Hours ships the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;listing the saved time entries in various formats using the public Toggl API&lt;/li&gt;
&lt;li&gt;styling the plain text output with &lt;code&gt;termenv&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;converting the output to Markdown, JSON, and CSV allowing you to post-process data with other scripts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fortunately, the Toggl API is convenient to work with and I've been delighted how easy it is to marshal Go structures to JSON and vice versa. Thus, more features are definitely on the roadmap. I'm thinking of implementing features such as starting and stopping timers without forgetting the basic time entry CRUD operations (create, read, update, and delete). Since &lt;strong&gt;Hours&lt;/strong&gt; is still in the very early stages of development, you can help me improve it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Blocking time ensures I can complete essential tasks while still reacting to urgent tasks. Having a clear daily plan helps me to recall individual days back to mind. I can also enjoy the rewarding sensation of accomplishing tasks. Most importantly, it helps me to stay away from unnecessary distractions. By the way, I don't have any desktop or web notifications enabled while working, so deal with it. Naturally, time blocking can't eliminate all the stress that a busy world with many projects brings forth, but it guarantees continuous calmness throughout the day.&lt;/p&gt;

&lt;p&gt;Throw me with a message if you need help organizing your day with time blocking.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo by &lt;strong&gt;Aron Visuals&lt;/strong&gt; on Unsplash&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>tooling</category>
      <category>go</category>
      <category>showdev</category>
    </item>
    <item>
      <title>The Rules of React Hooks - And How We Messed up</title>
      <dc:creator>Olavi Haapala</dc:creator>
      <pubDate>Mon, 15 Mar 2021 10:22:25 +0000</pubDate>
      <link>https://dev.to/futurice/the-rules-of-react-hooks-and-how-we-messed-up-4015</link>
      <guid>https://dev.to/futurice/the-rules-of-react-hooks-and-how-we-messed-up-4015</guid>
      <description>&lt;p&gt;React Hooks have quickly become the recommended way to handle component local state and side effects in React function components. Getting started with hooks is quite straightforward, but you might need to change the way you think about your components, especially when it comes to the useEffect hook.&lt;/p&gt;

&lt;p&gt;This blog assumes you know the basics of React Hooks – if you don’t &lt;a href="https://reactjs.org/docs/hooks-intro.html"&gt;you can find out more here&lt;/a&gt; – and will dive a bit deeper into how they should be used. I’ll also be sharing a bit about the mistakes we made and how it took us nearly a month to fix the mess.&lt;/p&gt;

&lt;h3&gt;
  
  
  React hooks - easy to learn, hard to master
&lt;/h3&gt;

&lt;p&gt;React Hooks were launched in React version 16.8 and they have quickly become a popular way to handle components, local states, and component side effects, among other things. They’re quite easy to get started with, but they're challenging to master properly – you have to learn to think a bit differently compared to React’s traditional class components and lifecycle hooks, and there are certain rules that you have to follow. &lt;/p&gt;

&lt;h3&gt;
  
  
  Some examples of hooks and how to use them
&lt;/h3&gt;

&lt;p&gt;The simplest hook is the useState hook, which takes as an argument the initial state. useState is a function that returns an array with two items in it: the first is the actual state and the second is a function that sets the state. Another of the built-in hooks is useEffect, which is for running side effects in your React function components. For example, if you have a shopping cart with a button to add a banana, when a banana is added you might want the document title to be updated as a side effect. With useEffects, you define the dependencies – you can think of it like defining the array and how often you want to run the function. If you leave it as an empty array, it will only run once, after the initial render; otherwise, it will run after every render of the function, unless you define the dependencies. So, when the state changes, React just calls this function again. And from a useEffect function, you can return a cleanup function. &lt;/p&gt;

&lt;p&gt;To understand the useEffect cleanup, try this analogy from &lt;a href="https://twitter.com/ryanflorence"&gt;Ryan Florence&lt;/a&gt;. Imagine you have only one bowl in your house to eat cereal from. You wake up in the morning and eat cereal whether you're hungry or not – that's the initial render. Time passes, the state changes, and you become hungry again. Now you need to clean the bowl because it's dirty from when you ate earlier. You clean it up first and then you eat again – this is the same as React running a cleanup before running the effect again, which is also why when a component is unmounted it runs the cleanup when it's removed. &lt;/p&gt;

&lt;h3&gt;
  
  
  Easy mistakes to make with React hooks
&lt;/h3&gt;

&lt;p&gt;I’ve just mentioned two of the most important hooks, but let's talk a bit about typical mistakes with hooks. The first mistake you might make when you start using useEffect is you might forget to add the dependency array, meaning your effect will run on every render. Why is this a problem? Imagine you're doing a fetch in your useEffect. This would happen on every render, causing a new render because something was changing the state of the component. This would make it render again, causing an infinite loop. Another typical mistake you can make when you start refactoring useEffects is having a useEffect that depends on the state that is saved inside it. This causes another infinite loop, but you can solve it by doing functional state updates instead of traditional useState calls. &lt;/p&gt;

&lt;h3&gt;
  
  
  Rules to follow – and what happens when you don’t
&lt;/h3&gt;

&lt;p&gt;The simplest rule is that hooks must start with &lt;strong&gt;“use”&lt;/strong&gt; – I think React will even warn you if you try to do something that doesn't start with use. Next, call hooks should only be used at the top level of your function components, so you can't nest them in statements. This is because React only relies on the order of the hook calls, so for every render you should call the same number of hooks so that React knows which hook is which. Finally, you can only call hooks from React functions. This should probably be self-explanatory, but when I started using hooks, I wanted to use them in some utility functions, and I realized quickly it just isn't possible. ESLint is very useful to check these rules. There are two plugins that I can recommend: &lt;strong&gt;react-hooks/rules-of-hooks&lt;/strong&gt; and &lt;strong&gt;react-hooks/exhaustive-deps&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So where did we go wrong? In the beginning of a project, we used TSLint instead of ESLint, because at that point TSLint wasn't deprecated yet, so we thought it would be fine. We had the React Hooks plugin installed and enabled, but for some reason we forgot to enable the React Hooks rules, so TSLint wasn’t actually checking the rules. We had it there for months and didn't notice, and because we didn't know the rules well enough, we didn't notice that our code was piling up into a huge mess.&lt;/p&gt;

&lt;p&gt;At that point we changed from TSLint to ESLint, which was already a big refactoring PR because we also made our rules stricter. At first we had the exhaustive deps rule disabled after the refactoring, as well as one huge component where we had to add the ESLint “disable React’s rules of hooks” line, because the file was just too large to be fixed in that PR. And then I started fixing this mess and enabled the exhaustive deps rule and decided to just do what ESLint tells us. I thought it would take me a couple of days, it ended up taking more than a month to fix just the exhaustive-deps violations, including causing some regressions in production. &lt;/p&gt;

&lt;h3&gt;
  
  
  Lessons learned with React
&lt;/h3&gt;

&lt;p&gt;The most important thing we learned was to keep it simple, in both your React code base and in hooks. Even though you can make huge effects, it's better to split them into multiple effects – and if this makes your component code looks ugly, you can abstract it away into a custom hook. Secondly, you should always enable ESLint rules and enforce them, and it’s best to have ESLint in your editor. At this point I’d also like to recommend &lt;strong&gt;&lt;a href="https://github.com/phenomnomnominal/betterer"&gt;Betterer&lt;/a&gt;&lt;/strong&gt; – a cool tool that can be used in legacy projects and in larger, ongoing projects to stop you from making the project worse over time. You add tests that make sure you stop doing the wrong things and forces you to do better in future. This is handy when you don’t have time, energy or resources for these kinds of huge refactoring PRs. &lt;/p&gt;

&lt;p&gt;I also learned that custom hooks are quite cool. They are a really useful way to share code and logic between components. And during this refactoring I've learned when to use useReducer and when to use useState. useState is fine, but if you have more than, say, three useStates and you need to change a few of them at the same time but they're relying on each other, then it's better to use useReducer with one state object and then dispatch actions that update the state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where to learn more about React and React hooks
&lt;/h3&gt;

&lt;p&gt;If you want to learn more about hooks and the rules of hooks, React’s official docs are amazing – they explain the rules and why you have to follow them. If I had read them to start with I wouldn’t have made the mistakes I did! I’d also recommend taking a look at Dan Abramov’s blog, &lt;a href="https://overreacted.io/"&gt;overreacted.io&lt;/a&gt;. &lt;a href="https://overreacted.io/a-complete-guide-to-useeffect/"&gt;A complete guide to useEffect&lt;/a&gt; is interesting, as is &lt;a href="https://overreacted.io/react-as-a-ui-runtime/"&gt;React as a UI Runtime&lt;/a&gt;, and &lt;a href="https://overreacted.io/how-are-function-components-different-from-classes/"&gt;how are function components different from classes&lt;/a&gt; will teach you some important differences. &lt;/p&gt;

&lt;p&gt;This blog was based on one of my &lt;a href="https://www.youtube.com/playlist?list=PL4su8m9nd245Q0PgsJhrbU65BmdhayFKQ"&gt;Tech Weeklies&lt;/a&gt; talks. You can listen to the &lt;a href="https://www.youtube.com/watch?v=VHvqnFU8dPA"&gt;full episode here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>hooks</category>
    </item>
    <item>
      <title>How I handle my notes with symbolic links</title>
      <dc:creator>John Cheng</dc:creator>
      <pubDate>Sun, 21 Feb 2021 17:37:14 +0000</pubDate>
      <link>https://dev.to/futurice/how-i-handle-my-notes-with-symbolic-links-594j</link>
      <guid>https://dev.to/futurice/how-i-handle-my-notes-with-symbolic-links-594j</guid>
      <description>&lt;h1&gt;
  
  
  Background
&lt;/h1&gt;

&lt;p&gt;Handling notes has always been tricky for me. Should I use an app or have markdowns in a folder?&lt;/p&gt;

&lt;p&gt;Lately, I decided to only use markdowns and have them centralised in a folder called &lt;code&gt;notes&lt;/code&gt; while making them accessible in the relevant projects via symbolic links.&lt;/p&gt;

&lt;p&gt;Objectives:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Access only project specific notes in VSCode (or any IDE)&lt;/li&gt;
&lt;li&gt;Keep a folder containing all of my notes&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  How-To
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~
|-- .gitignore_global
|-- Documents/
    |-- notes/
        |-- project_foo/
    |-- project_foo/
        |-- .notes/ (ignore from version control)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Instructions
&lt;/h2&gt;

&lt;p&gt;The first step is to have the version control ignore the notes in each projects. For example, I decided to have my notes in a &lt;code&gt;.notes&lt;/code&gt; folder under each project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create a global gitignore
touch ~/.gitignore_global

# Add the folder that will contain the notes in each project
echo .notes &amp;gt;&amp;gt; ~/.gitignore_global

# Add the global gitignore to the git configurations
git config --global core.excludesfile ~/.gitignore_global
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's create the folder that will contain all the notes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create the folder where all the notes will be centralised
mkdir ~/Documents/notes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, let's say we have a project called &lt;code&gt;project_foo&lt;/code&gt;. We can now create the folder that will contain the notes and link it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create the folder where the project specific notes will be found
mkdir ~/Documents/notes/project_foo

# Link the project specific notes folder into the project
ln -s ~/Documents/notes/project_foo ~/Documents/project_foo/.notes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Folder &lt;code&gt;notes&lt;/code&gt; contains &lt;strong&gt;all&lt;/strong&gt; the notes&lt;/li&gt;
&lt;li&gt;Each project has a &lt;code&gt;.notes&lt;/code&gt; folder with &lt;strong&gt;only related notes&lt;/strong&gt; and ignored by version control&lt;/li&gt;
&lt;li&gt;All the notes are synced between the &lt;code&gt;notes&lt;/code&gt; folder and the &lt;code&gt;.notes&lt;/code&gt; one in each project&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks to this architecture, I am now able to access my project's notes in my IDE directly and avoid using another app for that. To add to that, because they are synced in the &lt;code&gt;notes&lt;/code&gt; folder, I still have the possibility to open all my notes at once if needed.&lt;/p&gt;

&lt;h1&gt;
  
  
  Final words
&lt;/h1&gt;

&lt;p&gt;Thank you for reading my &lt;strong&gt;first ever blog post&lt;/strong&gt; and I hope it helps some of you :)&lt;/p&gt;

&lt;p&gt;Let me know your thoughts and/or improvements!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://unsplash.com/@dtravisphd?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Photo by David Travis&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>notes</category>
      <category>markdown</category>
      <category>git</category>
    </item>
    <item>
      <title>Conventions Don’t Matter – What Matters Is Consistency</title>
      <dc:creator>Olavi Haapala</dc:creator>
      <pubDate>Tue, 02 Feb 2021 09:26:00 +0000</pubDate>
      <link>https://dev.to/futurice/conventions-don-t-matter-what-matters-is-consistency-4lp2</link>
      <guid>https://dev.to/futurice/conventions-don-t-matter-what-matters-is-consistency-4lp2</guid>
      <description>&lt;h2&gt;
  
  
  Consistency Is the Key
&lt;/h2&gt;

&lt;p&gt;When working in a larger development team, it’s important to have clear conventions for various aspects of the project. Some of the conventions could be about the team’s ways of working, such as code review processes, git practices and other topics. Most time consuming debates usually are about code style and coding conventions. I personally think that the conventions really don’t matter. What matters is that everyone follows the agreed conventions consistently.&lt;/p&gt;

&lt;p&gt;This is also why code formatting tools, such as Prettier have become widely adopted and popular. Prettier puts an end to the non-important discussions about coding style, such as using or omitting semicolons or trailing commas and other useless discussions which are quite typical discussion in JavaScript or TypeScript projects. Prettier takes care of formatting the code, and in your code reviews, you can focus on things that matter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Conventions Are Needed
&lt;/h3&gt;

&lt;p&gt;However, there’s a lot more into conventions than code formatting. Especially when using general purpose languages such as JavaScript or TypeScript or libraries such as React. There often are multiple ways of handling different scenarios in the code base. Sometimes developers working simultaneously on different branches implementing different features, but technically speaking solving a similar problem, may end up solving the problem in vastly different ways. Often, it is impossible to say that one of the ways is wrong and the other one not. What matters is that the coding conventions are consistent. This is why the team needs to agree on the conventions and then enforce them and train everyone in the team to follow the agreed conventions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don’t Blindly Copy Best Practises
&lt;/h2&gt;

&lt;p&gt;There are a lot of examples of long form best practices and conventions written up, which you can check out and adopt in your team as it suits your team. Something that works for others, may not work in your cause though. It is always best to discuss together and agree on the conventions that work for your team and project. However, I would argue that the conventions themselves are unimportant. The only thing that matters is that everyone is following the same conventions and doing so consistently. Over time, the code base should remain somewhat uniform to the extent it is possible.&lt;/p&gt;

&lt;p&gt;You may think that is a bad idea, and stops innovation and adopting new trends and technologies. I dare to disagree. New conventions can be agreed on, and when a new convention is agreed on, it should be used in the codebase from that day on. Either by refactoring the whole code base to follow the new convention, which should be doable if the previous convention was followed carefully, or by using tools such as &lt;a href="https://github.com/phenomnomnominal/betterer"&gt;phenomnomnominal/betterer&lt;/a&gt; to incrementally adopt a new convention, and stop anyone from adding new code that does not follow the newly agreed convention. It is equally important to document the agreed conventions and keep the documentation up-to-date over time in addition to making sure everyone on the team hears about and understands the agreed conventions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conventions Should Not Be Carved in Stone
&lt;/h2&gt;

&lt;p&gt;A team’s conventions should be evolving as the team evolves, learns something new, and new members join the team. It is impossible to agree on perfect conventions that would cover all the future aspects taking into account all the things that are going to happen in the project, in the tech field and in the world. A good example of this is how many teams used to work mostly co-located at offices, but suddenly, due to COVID-19, had to switch to working fully remotely. This has forced teams to evolve their ways of working and conventions in order to adapt to the new situation and continue collaborating in an effective manner.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Works for Your Team
&lt;/h2&gt;

&lt;p&gt;How are the conventions agreed on in your team? How do you document your conventions? What has been the most challenging topic to agree on? I would be interested to know that. Comment below or &lt;a href="https://twitter.com/0lpeh/status/1356532110056689665"&gt;comment on this Twitter thread&lt;/a&gt; or if you wish, you can contact me with DM or in any other way that suits you best.&lt;/p&gt;

</description>
      <category>conventions</category>
      <category>teamwork</category>
      <category>practises</category>
    </item>
    <item>
      <title>Becoming a Certified Web Accessibility Specialist</title>
      <dc:creator>Eevis</dc:creator>
      <pubDate>Sun, 17 Jan 2021 14:16:54 +0000</pubDate>
      <link>https://dev.to/futurice/becoming-a-certified-web-accessibility-specialist-349l</link>
      <guid>https://dev.to/futurice/becoming-a-certified-web-accessibility-specialist-349l</guid>
      <description>&lt;p&gt;My second measurable goal in web accessibility for 2020 was to pass the Web Accessibility Specialist-exam. I thought that I would receive the results in 2021. However, I got a Christmas surprise. The message congratulating me on passing the exam was in my inbox on Christmas Day. If you want to read how I felt pretty soon after getting the results, I wrote a blog post about that:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/eevajonnapanula" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F201004%2F0196665f-a91d-4692-a6d6-12e6d68737e2.png" alt="eevajonnapanula"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/eevajonnapanula/i-am-certified-professional-in-web-accessibility-2aan" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;I Am Certified Professional in Web Accessibility! 🎉&lt;/h2&gt;
      &lt;h3&gt;Eevis ・ Dec 26 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#a11y&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#certification&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#html&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;This post is a similar wrap-up-post from the WAS-exam, as I did from the &lt;a href="https://dev.to/futurice/what-can-you-learn-from-getting-certified-in-accessibility-the-cpacc-edition-25m5"&gt;CPACC (Certified Professional in Accessibility Core Competencies)-exam&lt;/a&gt;.  &lt;/p&gt;

&lt;h2&gt;
  
  
  What is WAS?
&lt;/h2&gt;

&lt;p&gt;International Association of Accessibility Professionals (the organization providing the certification) describes WAS with the following words: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Technical-level credential is intended for accessibility professionals who are expected to evaluate the accessibility of existing content or objects according to published technical standards and guidelines, and provide detailed remediation recommendations.&lt;br&gt;&lt;br&gt;
&lt;em&gt;&lt;a href="https://www.accessibilityassociation.org/wascertification" rel="noopener noreferrer"&gt;IAAP WAS Certification&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is a more technical certification, which requires more understanding of &lt;em&gt;how&lt;/em&gt; to build web that is more accessible. It doesn't necessarily require much coding experience, but some HTML, CSS, and JavaScript knowledge is needed. &lt;/p&gt;

&lt;h2&gt;
  
  
  Learnings
&lt;/h2&gt;

&lt;p&gt;Again, as with CPACC, I can say that I learned a lot. I used &lt;a href="https://dequeuniversity.com/curriculum/packages/iaap-was" rel="noopener noreferrer"&gt;Deque's WAS-package for learning&lt;/a&gt;, and I liked it. It contains lots of different courses and took a long time to go through, but it was worth the time. Also, I used the &lt;a href="https://www.accessibilityassociation.org/files/103119_IAAP%20WAS%20BOK.pdf" rel="noopener noreferrer"&gt;WAS BOK (Body of Knowledge)&lt;/a&gt; as a guide for studying. &lt;/p&gt;

&lt;p&gt;WAS, too, consists of three parts: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating Accessible Web Solutions&lt;/li&gt;
&lt;li&gt;Identify Accessibility Issues in Web Solutions&lt;/li&gt;
&lt;li&gt;Remediating Issues in Web Solutions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll go through each category, picking up some points from each. They're all broad themes, and I can barely scratch the surface on this post, but hopefully, you'll get something out of my notes! &lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Accessible Web Solutions
&lt;/h3&gt;

&lt;p&gt;In the first section, the first topic is all the relevant guidelines and techniques for meeting the success criteria. These mean, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WCAG 2.1 (Web Content Accessibility Guidelines)&lt;/li&gt;
&lt;li&gt;WAI-ARIA (the Accessible Rich Internet Applications Suite)&lt;/li&gt;
&lt;li&gt;ATAG (Authoring Tools Accessibility Guidelines)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before studying for WAS, I had some idea about each of them - more about some and less about others. For example, WCAG was somewhat familiar to me, and I knew &lt;em&gt;what&lt;/em&gt; it was, but this was the first time I actually read the whole set of guidelines. It was refreshing and educational. &lt;/p&gt;

&lt;p&gt;Another thing in this section was "Basic knowledge of programming" - I thought I knew a lot about programming accessible interfaces, but oh boy, was I wrong. I learned &lt;em&gt;a lot&lt;/em&gt; about semantic HTML and different techniques for creating a more accessible web. Also, I got to know about &lt;a href="https://www.w3.org/TR/wai-aria-practices-1.1/" rel="noopener noreferrer"&gt;WAI-ARIA Authoring Practices and Design Patterns&lt;/a&gt;, which has been a valuable source of information when creating custom widgets. &lt;/p&gt;

&lt;p&gt;Before studying, I had only a vague idea, how assistive technology can affect websites. For example, when a user uses a screen reader on mobile, it disables all the website's custom gestures. It means that if something is based purely on, for example, swiping content and there is no alternative way to access it, a user can't use that feature or app. &lt;/p&gt;

&lt;p&gt;Another interesting bit of information I acquired from the studying process was how people using assistive tech use the web. For example, navigation with a screen reader happens differently from how a person who sees, navigates through the web page. &lt;/p&gt;

&lt;p&gt;I have to admit that I came across many things that made me realize how ignorant I've been when coding (and still often am, as I am still learning every day). I've created so many inaccessible interfaces, and this feeling of being ashamed pushes me towards reading more.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Identify Accessibility Issues in Web Solutions
&lt;/h3&gt;

&lt;p&gt;This section was an interesting one, and the focus is on finding the accessibility issues from the websites and identifying the relevant guidelines and principles regarding these issues. A big part of this section was the testing methods - be it automatic or manual testing. I'll write some words about the latter.&lt;/p&gt;

&lt;h4&gt;
  
  
  Manual Testing
&lt;/h4&gt;

&lt;p&gt;I took a deep dive into different screen readers. I even turned my old Windows computer on for some JAWS testing. However, I never got there because, well, all the Windows updates took a remarkably long time, and in the end, I didn't have enough space on the computer. 😅 &lt;/p&gt;

&lt;p&gt;I've used VoiceOver on Mac before but going through the material taught me more about the keyboard shortcuts in VoiceOver. I still have to check the shortcuts almost every time I'm testing something with VoiceOver, but I'm getting better! I also learned the basic gestures for Android Talkback and tried VoiceOver on iOS. &lt;/p&gt;

&lt;p&gt;I am adding a comment here before proceeding. I am a sighted person and can't be an expert on how actual screen reader users use the program. However, learning to use a screen reader helps with testing and understanding what needs to be taken into account for screen reader users. Anyway, this should not be the only testing made to an app with screen readers. In the perfect world, actual screen reader users would be included as testers in the quality assurance process. &lt;/p&gt;

&lt;p&gt;One other thing I want to point out: Often when talking about assistive technology on the web, the first (and sometimes only) thing that people think of is the screen readers. That's not the case - for example, Windows High Contrast Mode, ZoomText and MAGic (for screen magnification), and keyboard-emulating assistive technology are widely used, to name a few.&lt;/p&gt;

&lt;h4&gt;
  
  
  Testing with Keyboard
&lt;/h4&gt;

&lt;p&gt;And yes, the keyboard is on the list too. It is maybe the most straightforward testing you can do for a website - in most cases, you already have all the equipment and can start testing. Can you navigate the website without a mouse? Is everything usable? Do you know where the focus currently is? If you open a modal, can you access elements behind it while it's open? Where does the focus go when you close the modal? And so forth. &lt;/p&gt;

&lt;p&gt;Ah, and by the way - if you're navigating on the webpage on a keyboard for the first time: There are some patterns to note about keyboard navigation. In WAI-ARIA Authoring Practices, there is a chapter about &lt;a href="https://www.w3.org/TR/wai-aria-practices/#kbd_generalnav" rel="noopener noreferrer"&gt;Developing a Keyboard Interface&lt;/a&gt;. In short, the keyboard navigation patterns users expect on the web are borrowed from different GUI-applications. For example, that means that tab-key is usually used to get &lt;em&gt;into&lt;/em&gt; the widget, and arrow keys are used for navigation &lt;em&gt;within&lt;/em&gt; that widget. &lt;/p&gt;

&lt;h3&gt;
  
  
  Remediating Issues in Web Solutions
&lt;/h3&gt;

&lt;p&gt;This section has only two subsections - "Level of severity and prioritization of issues" and "recommending strategies and/or techniques for fixing issues." For me, especially the first one was helpful and gave loads of new information. &lt;/p&gt;

&lt;p&gt;Some factors influence the priority of an accessibility bug: The severity of the user impact, how fast developers can fix it, business priority, location of the issue, and how often that same bug appears, to name a few. &lt;/p&gt;

&lt;p&gt;From these examples, what surprised me was "how fast developers can fix it". I mean, it totally makes sense that the low hanging fruits should be picked and fixed, but I just hadn't thought about it. But then again, according to &lt;a href="https://webaim.org/projects/million/#wcag" rel="noopener noreferrer"&gt;WebAIM Million&lt;/a&gt;, there are automatically detectable WCAG-failures in 98.1% of the top 1,000,000 websites' homepages. Here's percentages of most common types of failures:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
    Most common types of WCAG 2 failures (Source: &lt;a href="https://webaim.org/projects/million/#wcag" rel="noopener noreferrer"&gt;WebAIM Million&lt;/a&gt;)
    &lt;tbody&gt;
&lt;tr&gt;
&lt;th&gt;WCAG Failure Type&lt;/th&gt;
&lt;th&gt;% of home pages in February 2020&lt;/th&gt;
&lt;/tr&gt;
    &lt;tr&gt;
&lt;td&gt;Low contrast text&lt;/td&gt;
&lt;td&gt;86.3%&lt;/td&gt;
&lt;/tr&gt;
    &lt;tr&gt;
&lt;td&gt;Missing alternative text for images&lt;/td&gt;
&lt;td&gt;66.0%&lt;/td&gt;
&lt;/tr&gt;
    &lt;tr&gt;
&lt;td&gt;Empty links&lt;/td&gt;
&lt;td&gt;59.9%&lt;/td&gt;
&lt;/tr&gt;
    &lt;tr&gt;
&lt;td&gt;Missing form input labels&lt;/td&gt;
&lt;td&gt;53.8%&lt;/td&gt;
&lt;/tr&gt;
    &lt;tr&gt;
&lt;td&gt;Empty buttons&lt;/td&gt;
&lt;td&gt;28.7%&lt;/td&gt;
&lt;/tr&gt;
    &lt;tr&gt;
&lt;td&gt;Missing document language&lt;/td&gt;
&lt;td&gt;28.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These detectable errors include, for example, missing alt-texts, missing form labels, and empty links, which are relatively easy to fix. It means that when fixing those issues, the accessibility of a website improves a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summing up
&lt;/h2&gt;

&lt;p&gt;Again, I can't stress enough how much I've learned while studying for the Web Accessibility Specialist-exam. It has opened my eyes to new things in accessibility, and I've found many new tools for making a more inclusive web. &lt;/p&gt;

&lt;p&gt;However, I must note that this is only the beginning. Now I have the tools for learning more, but I recognize that the learning must continue. Most of all, I'll need practice, practice, and practice. I've noticed that even if I have all the knowledge, I still keep making those mistakes in code and realize later that I should have known better.&lt;/p&gt;

&lt;p&gt;Are you IAAP certified or studying to take the exam? If so, I'd love to hear your thoughts! Also, I'd love to answer if any questions arise about the topic! 😊&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover photo by &lt;a href="https://unsplash.com/@sigmund" rel="noopener noreferrer"&gt;Sigmund&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/braille" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>inclusion</category>
      <category>html</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
