Talks

Development with Axioms

wroc_love.rb 2019

00:00:14.750 Hello everyone, my name is Martin. I'm a software developer working in a small team together with my close friend Markus, who will be having his talk right after this one. He'll be going into the details of the tools and techniques we use on a day-to-day basis when working on our project. Markus will be discussing mutation testing, and I hope to set the stage by discussing the core axioms we have identified and that we use to guide our process. We are always on the lookout for new rules that help us minimize time spent on simpler tasks. Thinking about these simple tasks can be monotonous and takes away from the time we could be spending on the actual hard problems we need to solve every day. We believe that by laying down rules everyone can agree upon, we can form a shared set of values, which helps eliminate many questions we typically encounter when programming, especially as a remote team. Our team works across different continents and communicates primarily through written text, as we’ve found that talking or video conferencing often hurts our productivity.
00:02:47.000 With that in mind, I want to discuss the objectives we likely share as software developers. First and foremost is minimizing bugs because clients hate bugs, and we as programmers dislike them as well. When bugs occur, they disrupt our flow, forcing us to address issues that may have arisen months or years ago. Thus, our goal is to minimize these occurrences. As a heads-up for this talk, I hope most of what I say will resonate as universally accepted truths. This is why we use the term 'axioms.' Axioms are statements of universal truth that we can build upon. Another key aspect we aspire to is minimizing downtime. I should add that the project we're working on is a web application that needs to be live all the time. Whenever it’s offline, clients get upset.
00:05:39.000 We also want to ensure that we learn as a team every day while we work. It's not just about solving problems for clients, although that is obviously important; we also want to learn while we do so. Part of being a programmer is having the curiosity to improve your craft. Once you stop improving, things can become tedious. This key concept leads us to constantly question our processes to identify past mistakes or areas for improvement. We strive to find new assumptions we can agree upon, which form the basis for some constraints that can be enforced in our development process. One significant aspect of this is the concept of 'transformation.' Transformation, in this context, refers to any update to system artifacts—such as code changes, infrastructure updates, or data modifications—as we all know these changes primarily happen through code.
00:09:23.000 When we mention transformations, we're essentially discussing commits. Interestingly, there are only a small number of transformations that occur when we write commits. This talk will outline these transformations and their implicit ordering, which prevents us from having to think about them excessively. If there are only a few transformations, we can easily track what the next commit should involve. Another term we frequently encounter is 'regression.' However, we use it in a slightly broader sense than simply referring to a bug. We consider any change that puts the system into a worse state to be a regression. This can include issues not yet known to clients. Our goal is always to minimize regressions by ensuring that every commit leads to an improvement and that they don't compromise code quality.
00:13:57.000 All transformations we apply must be atomic, meaning they should be indivisible. If you are changing a running system, those changes should be handled as minimally as possible. A smaller change is easier to review and has less impact on the running application. This doesn’t mean we shouldn’t aim for substantial progress; however, changing a complex system in tiny steps allows us to manage risks effectively. Additionally, we have a robust system of checks for all code we commit. These checks fall into two categories: automated checks, which we call tests, and manual checks, which we call reviews. Both are equally important. Automated checks minimize the time spent on verifications, allowing for a more efficient process.
00:19:46.000 We typically flag any violations of established rules during reviews. A flag indicates a failed check identified by a human reviewer. Two obvious axioms we can agree on are that clients hate bugs and love progress. Another axiom is that redundant code does not add value. This means if it's redundant, we shouldn't include it in our codebase. This principle is vital to our process. Markus will delve deeper into 'Mutant,' a tool designed for mutation testing, which aids in removing redundant semantics by suggesting simpler alternatives or indicating unnecessary code.
00:23:44.000 Likewise, inconsistency in code presents no value. We discussed whether we should specifically mention inconsistency, as it pertains primarily to style. A well-crafted codebase should reflect a shared style among team members. Human attention fluctuates over time, which is another important factor. Not everyone is in perfect sync mentally at all times; some days are better than others. This fluctuation highlights the necessity for automated checks that provide support when individual cognition may be lacking. If a process is automated, the need for human attention is significantly reduced.
00:28:28.000 It's essential to remember that clients’ required semantics change over time. What clients demand today may change tomorrow, leading us to the need for a well-defined process. A good process significantly enhances a team's performance. Thus, it's vital we develop a process to minimize inconsistencies and questions that need addressing. Automation is preferred over manual reviews where possible, as it streamlines our workflow and reduces time spent on repetitive tasks. Another point of consideration is that it is often impossible to fully understand the semantics required by clients, as they perceive their needs differently than we do. Our mental models of projects can be flawed, shaping the work we do and how we integrate constraints.
00:34:12.000 We should, therefore, embed constraints deeply within our systems instead of applying superficial checks. Keep validations close to the most fundamental levels of the system. It is key to ensure that invalid data is rejected promptly. Review processes should also consider that team members should never self-censor their findings during code reviews. If a colleague’s code contains a flaw, it’s critical to point it out openly. The outcome is usually positive; constructive feedback fosters learning and collaboration.
00:39:23.000 Now we will transition into discussing the transformations relevant to our codebase. We’ve identified five core transformations, which represent the only actions we can take, essentially combining them with atomic principles. These transformations are: removing code, fixing code, refactoring code, and changing or adding new code. When addressing these transformations, we prioritize removal and fixes to limit the scope of changes made. This potential for combining and sequencing changes ensures that we consistently achieve improvement. Therefore, in our commit messages, we indicate the type of transformation being undertaken to maintain clarity and cohesion through the process. It's essential to establish guidelines to ensure consistent improvement along with maintaining a high level of quality in our commits. Introducing this structured approach to transformations has required a lot of discussion and refinement over the years. It necessitates the commitment to the principles we’ve developed.