<?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: Alex Bunardzic</title>
    <description>The latest articles on DEV Community by Alex Bunardzic (@alexbunardzic).</description>
    <link>https://dev.to/alexbunardzic</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F31883%2Ff1cea439-d57d-432e-8e8c-02b72bd7f518.jpeg</url>
      <title>DEV Community: Alex Bunardzic</title>
      <link>https://dev.to/alexbunardzic</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alexbunardzic"/>
    <language>en</language>
    <item>
      <title>Write Code Interactively</title>
      <dc:creator>Alex Bunardzic</dc:creator>
      <pubDate>Thu, 31 Dec 2020 17:54:29 +0000</pubDate>
      <link>https://dev.to/alexbunardzic/write-code-interactively-4mni</link>
      <guid>https://dev.to/alexbunardzic/write-code-interactively-4mni</guid>
      <description>&lt;p&gt;My early induction into the world of computer programming was with Smalltalk (after the obligatory courses in LISP and Fortran at the University). I also remember a brief period I spent with Forth. Those were early days (for me).&lt;/p&gt;

&lt;p&gt;The real world of making a living as a professional programmer demanded different programming discipline (my first paying job was coding COBOL in 1990; later, I progressed to Java). Back then, the prevailing sentiment was that real pros know how to write code on paper. Only amateurs/dilettantes need to check if their code works correctly every time they make a change to it.&lt;/p&gt;

&lt;p&gt;Today I find myself completely flipping that sentiment on its head, and replacing the arrogant, foolish confidence of youth with the humility of mature age. Experience teaches us many things; most important of all is to be humble.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proceed gingerly
&lt;/h2&gt;

&lt;p&gt;I’m noticing how all prominent software engineers who I follow and learn from tend to write code in micro snippets. They tread lightly, and never seem brash, despite decades of their hard-earned experience in the field. They always make minimal changes to the code and then rush to check if everything still works. Experienced software engineers cherish steady state, and are hell bent on keeping their system running at all times (Ron Jeffreys famously said “The trick is to never let the code not be working”).&lt;/p&gt;

&lt;p&gt;That approach is the exact opposite of the approach I was practicing 20 years ago. I remember spending hours making changes to the code without stopping, not even once, to check if the code I changed would compile, if it would build, if it would run, and if it would it produce the expected results. I was too confident at that time and convinced that I know exactly what I’m doing.&lt;/p&gt;

&lt;p&gt;Of course, I was dead wrong, and now when I look back at the code I wrote many moons ago, I cringe in embarrassment.&lt;/p&gt;

&lt;p&gt;So after learning my lesson the hard way, I now prefer to proceed gingerly. I like to write code in short bursts of micro changes. Maybe change one line and then immediately run everything to see if it still works correctly. In short, I now write code interactively.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does it mean to write code interactively?
&lt;/h2&gt;

&lt;p&gt;The technology we are presently using to develop software is called code-as-text. We write instructions to the computers using text, an approach that is meant for producing processing logic that is (hopefully) readable by other humans. But computers do not understand text, and they need code-as-text to be translated into binary instructions. That translation is typically provided by compilers/interpreters.&lt;/p&gt;

&lt;p&gt;Now, the problem with this approach is that, since computers don’t understand text, they have no opinion about the text we write as a set of instructions for them. Computers take that code-as-text and then attempt to execute it. If the first pass is successful (i.e. code-as-text compiles into code as binary machine instructions) the computer will take it and blindly run it. If it encounters something wrong, or not-executable, the machine will merrily crash (or hang, or freeze).&lt;/p&gt;

&lt;p&gt;So we see that it gets fairly easy to author many bugs and defects, because computers never push back on any meaningless instructions. Code-as-text is the culprit here, and it needs to be fixed.&lt;/p&gt;

&lt;p&gt;In the early days, we were using plain text editors to write computer programs (vi, for example). Those editors did not speak programming languages, so it was up to us to ensure proper syntax and semantics of the code we were writing.&lt;/p&gt;

&lt;p&gt;Enter IDEs. Sophisticated tools, such as Visual Studio and VS Code are a far cry from those primitive text editors from the past. Today IDEs speak many programming languages. Many of those IDEs are extremely opinionated and will not let us type incorrect syntax.&lt;/p&gt;

&lt;p&gt;That level of sophistication is extremely beneficial, as it is getting us much closer to the ideal – full blown interactive programming in real time.&lt;/p&gt;

&lt;p&gt;When writing code, it is extremely important to get the feedback as soon as possible. Waiting for the feedback only after we write many lines of code and then wait for it to compile, build, deploy, run, is truly unproductive. Thanks to today’s advanced technology, we get an almost immediate feedback in our code editor regarding not only the correctness of our syntax, but also regarding the quality of our code as well as the security.&lt;/p&gt;

&lt;p&gt;It is therefore important to embrace this new age of interactive programming and take full advantage of all the sophisticated tools we enjoy today – VS Code extended by SonarQube, ReSharper, WhiteSource Advise, and many other useful commodities. Doing that ensures we’ll cut down on bugs and defects while improving the changeability of our code (i.e. lowering the cost of change).&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Software Complexity: Essential, Accidental and Incidental</title>
      <dc:creator>Alex Bunardzic</dc:creator>
      <pubDate>Wed, 16 Dec 2020 19:42:51 +0000</pubDate>
      <link>https://dev.to/alexbunardzic/software-complexity-essential-accidental-and-incidental-3i4d</link>
      <guid>https://dev.to/alexbunardzic/software-complexity-essential-accidental-and-incidental-3i4d</guid>
      <description>&lt;p&gt;Software complexity seems to be getting more and more unmanageable as our field of engineering evolves. In order to gain correct understanding of how to deal with the ever mounting complexity, it is important to discern three basic types of software complexity: &lt;strong&gt;essential&lt;/strong&gt;, &lt;strong&gt;accidental&lt;/strong&gt; and &lt;strong&gt;incidental&lt;/strong&gt; complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Essential complexity
&lt;/h2&gt;

&lt;p&gt;This type of software complexity is related to the complexity of the domain we are trying to model. In more specific terms, we are dealing with business policy rules that govern business processes. When trying to implement and automate the processing of those policy rules, we encounter various levels of complexity.&lt;/p&gt;

&lt;p&gt;This complexity cannot be whittled down, no matter how hard we may try. For example, if the business policy rules which govern the processing of a claim require 15 discrete steps, we cannot simplify the rules by skipping some steps and crunching the processing down to just few basic steps.&lt;/p&gt;

&lt;p&gt;Bottom line, essential complexity is unavoidable, and is basically the real reason why we are gainfully employed as software engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accidental complexity
&lt;/h2&gt;

&lt;p&gt;While essential complexity is worth having (delivers value to the customers and brings competitive advantage to the business, plus offers exciting career opportunities to engineers), accidental complexity is counter-productive. This type of complexity is caused by the lack of proper understanding, education, training, and could also be caused by the poor communication between the business and software engineering.&lt;/p&gt;

&lt;p&gt;Accidental complexity manifests itself in poor architecture, poor design, poor code as well as poor software engineering processes. Because accidental complexity is caused by some or all of the above factors, the only way to get rid of it is by removing its causes.&lt;/p&gt;

&lt;p&gt;The most expedient way to remove the causes of accidental complexity is by education, training, mentoring and coaching. There is always room for improvement, and the more we focus our daily activities on learning, the quicker we’ll be able to minimize accidental complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Incidental complexity
&lt;/h2&gt;

&lt;p&gt;This type of complexity is the toughest one to deal with. And it definitely is the most counter-productive type of complexity.&lt;/p&gt;

&lt;p&gt;When I was at the University I learned that writing software consists of receiving data, manipulating it programmatically, storing it locally, and sending it somewhere. At no point in my education was I expected to learn about load balancers, various data stores (SQL, NoSQL, memcached), containers (Vagrant, Docker Kubernetes) and other tools and technologies that each provide merely one part of the application. Back then, those infrastructure tools were viewed as mere annoying details.&lt;/p&gt;

&lt;p&gt;The underlying cause that brought these annoying details into such prominence lies in the Unix philosophy: “Do only one thing and do it well”. Tools follow incremental evolutionary path; each tool begins its life as a simple utility meant to scratch an itch. Usually that ‘scratching an itch’ consists of solving a few known problems. From that point on the tools evolve by improving on the previous capabilities. And naturally, that improvement is never focused on removing the complexity.&lt;/p&gt;

&lt;p&gt;For example, Git is a better version control tool than Subversion (Git is a subsequent evolution from Subversion), but Subversion is a lot simpler than Git.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to decrease complexity
&lt;/h2&gt;

&lt;p&gt;The only way to decrease complexity is to remove things. Instead of continuing on the evolutionary path of building better versions of existing stuff, we must eliminate stuff.&lt;/p&gt;

&lt;p&gt;For example (a really simplified one), we may currently have two tools in our toolbox. We combine those two tools by bundling them up into our workflow, and that arrangement helps us get the job done.&lt;/p&gt;

&lt;p&gt;If we now get rid of these two tools and build one tool that does the two things that each previous tool knew how to do, we eliminate incidental complexity. A single tool not only removes the interface, it also reduces the surface area of both problems that previously we needed two tools to grapple with.&lt;/p&gt;

&lt;p&gt;Imagine the gains in simplicity we get if we were to bring dozens of tools together into a single tool. By doing that, we eliminate huge pile of incidental complexity, as we need not worry about the interfaces and the overlap between tools.&lt;/p&gt;

&lt;p&gt;Presently, the best-of-breed technology that is serious about removing incidental complexity as much as possible is &lt;strong&gt;.Net&lt;/strong&gt;. Its current iteration (&lt;strong&gt;C#-Visual Studio-Azure&lt;/strong&gt;) proposes to eliminate swathes of specialized tools that come with burdensome overhead. Let’s look at some aspects of incidental complexity we’re trying to tame.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code-as-text complexity
&lt;/h2&gt;

&lt;p&gt;We write code as text, and that poses a high risk of introducing syntax errors. When we write some code as text, we ask the compiler to read it, and often times it cannot read the code (the attempt to read the code results in compiler errors). Good editors (for example, Visual Studio and Visual Studio Code) propose to speak the programming language, not just assist mechanically in formatting the text.&lt;/p&gt;

&lt;p&gt;Good tools (editors) minimize incidental complexity by combining various smaller tools into one big tool. Visual Studio understands the programming languages and offers intellisense/autocomplete. Access control and collaboration are also baked into this tool. In addition to that, refactoring is built in, as well as version control, feature flags, function and type versioning.&lt;/p&gt;

&lt;p&gt;Such advanced editors go a long way toward minimizing and even outright eliminating incidental complexity. We are strongly advised to take full advantage of such advanced tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Infrastructure complexity
&lt;/h2&gt;

&lt;p&gt;Everything involved in working with the machines that run our code is called &lt;em&gt;computing infrastructure&lt;/em&gt;. Queues, firewalls, networking, load balancers, scaling, security, monitoring, DBs, sharding, etc. As software engineers focused on delivering value in an uninterrupted stream, we are only interested in working with data, business policy rules processing, and customers. All of the above infrastructure concepts are mere annoying details that do not add any value to the customers. As such, we regard infrastructure as incidental complexity (a necessary evil). Our paying customers couldn’t care less about our queuing, scaling, monitoring etc. policies.&lt;/p&gt;

&lt;p&gt;Best-of-breed technologies such as &lt;strong&gt;Azure&lt;/strong&gt; go a long way toward abstracting many of the above infrastructure concerns, relieving us from a lot of incidental complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment complexity
&lt;/h2&gt;

&lt;p&gt;A finished code (i.e. a release candidate) needs to be synced from one machine to another machine. Conceptually, such operation should be trivial. In practice, it turns out to be a challenge to do this syncing quickly and safely. Why is that? Let us count the ways:&lt;/p&gt;

&lt;p&gt;• Packaging the code (Docker container, tarball, webpack, jars, git checkout…)&lt;br&gt;
• Testing the code (code coverage, mutation testing, browser testing/Selenium)&lt;br&gt;
• Syncing the code (git push, Docker registries, artifact hosting, S3, CDNs)&lt;br&gt;
• Enabling the new code (Kubernetes, reverse proxies, Capistrano, swapping symlinks)&lt;br&gt;
• Rolling out the code (feature flags, launch darkly, quarantine launch, blue-green deploys, DB migrations, API versioning)&lt;/p&gt;

&lt;p&gt;Again, &lt;strong&gt;Azure&lt;/strong&gt; is making some strides toward minimizing incidental complexity when deploying code.&lt;/p&gt;

&lt;h2&gt;
  
  
  API complexity
&lt;/h2&gt;

&lt;p&gt;Ideally, using an API should not be any harder than calling a function. However, that’s almost never the case. Authentication, rate limiting, retries, errors etc. conspire to make those calls incidentally complex.&lt;/p&gt;

&lt;p&gt;Some ways we’re trying to deal with these challenges: SOAP / REST / HTTP+JSON / gRPC/ GraphQL / Protobuf.&lt;/p&gt;

&lt;p&gt;This type of incidental complexity remains to be solved. There is some hope that, as platforms like &lt;strong&gt;Azure&lt;/strong&gt; mature, they will offer tooling to minimize the jungle of options we’re facing when it comes with using APIs.&lt;/p&gt;

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

&lt;p&gt;Complexity is the biggest enemy of shipping quality software. One type of complexity (i.e. essential complexity) is desirable, as it offers competitive advantage to the business and to the customers. Other types of complexity (accidental and incidental) are not desirable, as they add absolutely no value to the paying customers.&lt;/p&gt;

&lt;p&gt;By choosing our technology stack wisely, we can avoid some of the incidental complexity. And by choosing our training/education paths, we can also avoid almost all of the accidental complexity.&lt;/p&gt;

&lt;p&gt;Bottom line, those businesses who manage to minimize/remove a lot of accidental and incidental complexities from their operations will remain competitive and victorious on the market.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Never test the real thing</title>
      <dc:creator>Alex Bunardzic</dc:creator>
      <pubDate>Wed, 09 Dec 2020 19:25:53 +0000</pubDate>
      <link>https://dev.to/alexbunardzic/never-test-the-real-thing-o3i</link>
      <guid>https://dev.to/alexbunardzic/never-test-the-real-thing-o3i</guid>
      <description>&lt;p&gt;Software engineering is the youngest and the most immature of all engineering disciplines. While all other branches of engineering have moved on full tilt into the incredibly productive world of simulation, software seems to remain sluggishly stuck in the early days of pioneering efforts.&lt;/p&gt;

&lt;p&gt;There isn’t a modern development project, be it in civic engineering, pharmaceutical, automobile or aircraft, medical, pharmaceutical, financial etc. that is not 100% based on the discipline of virtualization. New cameras, newly designed smart phones, computers, any hardware, audacious enterprises to fly to Mars etc., understanding the patterns of pandemic, all those endeavors are progressing by simulating the conditions of the products or phenomena that do not exist yet.&lt;/p&gt;

&lt;p&gt;It is only in software that we see raised eyebrows when we recommend that the solution be simulated before we actually build it. In that regard, software is indeed still stuck in the Stone Age.&lt;/p&gt;

&lt;h2&gt;
  
  
  Map and Territory
&lt;/h2&gt;

&lt;p&gt;In the olden days when technology was very primitive, humans were interested in learning more about the concrete world that surrounds us. Many expeditions were sent to explore and measure the territories, and following such brave adventures, the collected measurements were abstracted into geographical maps.&lt;/p&gt;

&lt;p&gt;Today, with technology getting incredibly advances, we are witnessing adventures going in the opposite direction: researchers and engineers are first embarking upon expeditions to invent maps, and only once maps have been drawn in many details would they embark upon building the territory implied by the maps. Which is to say, first we simulate something that does not exist yet, and only then do we materialize that simulation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Software is perfect for simulation
&lt;/h2&gt;

&lt;p&gt;In the days before we had software, we were crafting maps of non-existent territories by either shrinking large real-life objects to much smaller size, or enlarging small real-life objects to larger size.&lt;/p&gt;

&lt;p&gt;For example, architects would construct miniature replicas of the buildings they were proposing to construct. Those miniature replicas were built using material at hand (cardboard, plastic, whathaveyou). And they were constructed BEFORE the actual construction on the site would commence.&lt;/p&gt;

&lt;p&gt;Chemists would also construct replicas of molecules by using material at hand and then enlarging the real size of molecules (which are invisible to the naked eye).&lt;/p&gt;

&lt;p&gt;Today, the simulation has been completely shifted to using software instead of real-life materials. Except, unfortunately, in the world of software engineering.&lt;/p&gt;

&lt;p&gt;It is interesting how we often tend to refuse the opportunity to use software to simulate software products and services. But by doing so, we miss out on a great opportunity to speed up our delivery.&lt;/p&gt;

&lt;p&gt;Software engineering processes such as TDD are an excellent remedy for this impasse. When doing TDD, we adopt the fake-it-till-you-make it approach. In other words, we start our work by first simulating some functionality that is not there. We begin from a broken system (a failed test). We simulate the breakage by fabricating incorrect values.&lt;/p&gt;

&lt;p&gt;This breakage is a strong incentive for us to get the system back into the steady state (a healthy state). We do that by simulating desired functionality. We simulate by crafting interfaces.&lt;/p&gt;

&lt;p&gt;Interfaces are a simulated stand-in for the real thing. By doing that, we are now actually crafting a map before there is any territory.&lt;/p&gt;

&lt;p&gt;Based on such carefully crafted map, we now build the desired territory – that is to say, we implement the functionality that was simulated by the interface.&lt;/p&gt;

&lt;p&gt;In doing that, we keep testing our system every step of the way. But our tests never touch the real thing – they only talk to the simulation (the virtualized thing, or the interface).&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Fake it till you make it</title>
      <dc:creator>Alex Bunardzic</dc:creator>
      <pubDate>Sun, 06 Dec 2020 18:08:01 +0000</pubDate>
      <link>https://dev.to/alexbunardzic/fake-it-till-you-make-it-12bl</link>
      <guid>https://dev.to/alexbunardzic/fake-it-till-you-make-it-12bl</guid>
      <description>&lt;p&gt;Imagine a situation where you've decided to write a service that will create something (a product, for example). As is customary, the first thing you do is describe your expectation in an executable form (i.e. a test). Now, how would you describe that expectation?&lt;/p&gt;

&lt;p&gt;You expect that a service which does not exist yet will do some work for the calling client. So the calling client (i.e. your expectation, your test) is the first customer of your as of yet non existent service. This customer of yours needs to express their expectation.&lt;/p&gt;

&lt;p&gt;Sidebar: (sounds like I'm beating around the bush, but bear with me; we're slowly circling around a very important topic). &lt;/p&gt;

&lt;p&gt;Back to the issue: how will the customer express their expectation, in an executable form, of a service that does not exist yet?&lt;/p&gt;

&lt;p&gt;Kent Beck to the rescue: fake it till you make it!&lt;/p&gt;

&lt;p&gt;The only way at that point in time that the customer (i.e. an executable test) can express their expectation is by fabricating a value (or some values). In other words, you hard-code expected value(s) in your test. You fake it.&lt;/p&gt;

&lt;p&gt;You fake it in such a way to set it up for a fall. Why would you be so mean? Because it is super important to start your work with a broken system. TDD is based on always starting with a broken system.&lt;/p&gt;

&lt;p&gt;So you run your test and watch it fail. Now you roll up your sleeves &amp;amp; fix it.&lt;/p&gt;

&lt;p&gt;How do you fix it? By defining an end-point of your 'create 'product' service. You then teach your test to send a request to that end point.&lt;/p&gt;

&lt;p&gt;What happens next? The end point receives the request, does some work, and --wait for it-- returns VALUE!&lt;/p&gt;

&lt;p&gt;Now imagine if instead of returning some value(s), the endpoint returned VOID. How would your test feel? It would feel deflated, cheated. Your test would have no idea whether the endpoint actually did anything or not.&lt;/p&gt;

&lt;p&gt;Furthermore, you may get worried if the endpoint did something unsavoury. Maybe after receiving your request the endpoint didn't do anything (what a waste), or worse yet, it did something that may cause all kinds of issues &amp;amp; calamities. You have no way of knowing.&lt;/p&gt;

&lt;p&gt;Returning VOID is always bad, and is to be avoided (no pun intended). We should rely on clearly defined values in any of our engineering endeavours, no matter how tiny &amp;amp; insignificant they may feel.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How can we know if someone is doing TDD?</title>
      <dc:creator>Alex Bunardzic</dc:creator>
      <pubDate>Sat, 05 Dec 2020 17:05:00 +0000</pubDate>
      <link>https://dev.to/alexbunardzic/how-can-we-know-if-someone-is-doing-tdd-4efb</link>
      <guid>https://dev.to/alexbunardzic/how-can-we-know-if-someone-is-doing-tdd-4efb</guid>
      <description>&lt;p&gt;I got an interesting question during the TDD Dojo I held two days ago (I love those challenging questions). A student asked how can I know whether someone delivered a solution using TDD? Is there a way to tell? My answer was that there is a certain 'smell' in the repo if it was done by writing code first.&lt;/p&gt;

&lt;p&gt;That certain 'smell' can be detected when examining the tests. Engineers who write code first tend to subsequently write tests that are coupled with the structure of the shipping code. Furthermore, they tend to write larger tests. It's rare to see microtests in code-first repos.&lt;/p&gt;

&lt;p&gt;Because of that (tendency to write larger tests that are tightly coupled to the structure of the already implemented code), code-first repos tend to result in larger percentage of surviving mutants. Doing TDD properly results in code that is loosely coupled.&lt;/p&gt;

&lt;p&gt;When I look at the repo done by teams that follow TDD, the first thing I notice is the simplicity of the tests. You can see that each test took no more than a minute or two to write. And you can see that tests are not interested in the structure of the code they are testing.&lt;/p&gt;

&lt;p&gt;TDD discipline results in simple tests that are single-minded and only care about the values produced by the shipping code under test. Each test only talks to the interface/API, never to the concrete method.&lt;/p&gt;

&lt;p&gt;That's why tests produced with TDD are not brittle &amp;amp; don't impede the development/refactoring. So the only reason we actually use TDD is to enable us to embrace change. We should be able to completely gut our system and experiment with implementation without disturbing our tests.&lt;/p&gt;

&lt;p&gt;My answer to the student was: "At the end of the day it doesn't really matter how you get there, and if you can deliver decoupled system that is easy/risk-free to change without doing TDD, more power to you. But I have yet to see an example of that."&lt;/p&gt;

</description>
    </item>
    <item>
      <title>As software development continues to get more expensive, what strategies can be deployed to reduce this cost?</title>
      <dc:creator>Alex Bunardzic</dc:creator>
      <pubDate>Sat, 07 Nov 2020 18:52:03 +0000</pubDate>
      <link>https://dev.to/alexbunardzic/as-software-development-continues-to-get-more-expensive-what-strategies-can-be-deployed-to-reduce-this-cost-1a53</link>
      <guid>https://dev.to/alexbunardzic/as-software-development-continues-to-get-more-expensive-what-strategies-can-be-deployed-to-reduce-this-cost-1a53</guid>
      <description>&lt;p&gt;Let’s first talk about the phenomenon called “Lump of Coding Fallacy”. People (including software developers/engineers) assume that software development typically consists of people sitting down and spending their work day writing code. Upon closer examination, it becomes obvious that such assumptions could not be more wrong.&lt;/p&gt;

&lt;p&gt;Even doing a little bit of introspection quickly reveals that so-called coders are spending just a fraction of their work hours actually coding.&lt;/p&gt;

&lt;p&gt;So if that’s not the case (gasp!), what are those highly paid coders wasting hours on? Browsing Twitter/social media? No, not really. Most of the time spent in the typical workday of a coder is spent on two activities:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scanning/reading code (other people’s code as well as code written by the programmer who is doing the scanning/reading)&lt;/li&gt;
&lt;li&gt;Geek-at-keyboard activities (GAK)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If a coder is spending hours upon hours scanning/reading code, that time is certainly not productive. They are getting paid to get entangled in opaque code, trying to make some semblance of a sense that is buried inside lines of code. As an employer, I certainly do not want my money to get spent of such non-productive activities.&lt;/p&gt;

&lt;p&gt;How to fix this haemorrhaging? Insist on quality software development principles, processes and practices. We call it clean architecture, clean design, clean code (read up on it, if you need a refresher).&lt;/p&gt;

&lt;p&gt;If the architecture/design/code are clean, there will be no need to spend hours/days scratching one's head trying to figure out what is the code supposed to be doing, and how to modify it without risking breaking some important functionality.&lt;/p&gt;

&lt;p&gt;So we see that clean software practices are one strategy to reduce the snowballing cost.&lt;/p&gt;

&lt;p&gt;What’s the other strategy? Minimize GAK activities (the other wasteful software practice).&lt;/p&gt;

&lt;p&gt;What are GAK activities?&lt;/p&gt;

&lt;p&gt;GAK activities relate to time wasted at the keyboard (actually typing) that does not produce any code. Again, as an employer, I don’t want my money to go toward financing such wasteful activities.&lt;/p&gt;

&lt;p&gt;When are coders using the keyboard to type and not produce code? There are several such situations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Debugging&lt;/li&gt;
&lt;li&gt;Entering test data&lt;/li&gt;
&lt;li&gt;Playing with the environment/configuration&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of the above three activities produces code. People can spend hours/days/weeks in such unproductive state. I’ve witnessed developers waste entire workday on some frantic debugging. No one should be expected to get paid by wasting hours debugging. Why? Because if you need to debug the code you wrote, that is a clear evidence that you don’t know how to write code in the first place.&lt;/p&gt;

&lt;p&gt;What about the situation where a coder has to debug other people’s code?&lt;/p&gt;

&lt;p&gt;If some code other people wrote is so opaque that it cannot be understood without starting a debugger and stepping through it line by line, it is unsalvageable. At that point, coders should cut their losses and ditch that code and write the needed functionality properly.&lt;/p&gt;

&lt;p&gt;What’s the problem with entering test data? This type of activity is non-productive. Making changes to the code and then re-entering some data in order to test it is one of the worst ways to waste other people’s money. Such activities must be banned from the software development teams.&lt;/p&gt;

&lt;p&gt;What about spending time configuring the environment? Again, it is wasteful and should be banned from the teams. Dependence on environments and infrastructure is a surefire sign of dirty architecture, dirty design and dirty code (read up on Alistairs Cockburn's Hexagonal Architecture).&lt;/p&gt;

&lt;p&gt;How to avoid slipping into GAK activities? Two-pronged solution:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;TDD&lt;/li&gt;
&lt;li&gt;Service Virtualization&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In summary, the best way to minimize the cost of software development is to engage mature teams who are well versed in producing clean software. At the same time, instigate strict policies that ban any GAK activities during work hours on the project.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Yogi Berra Explains Agile</title>
      <dc:creator>Alex Bunardzic</dc:creator>
      <pubDate>Thu, 05 Nov 2020 15:52:09 +0000</pubDate>
      <link>https://dev.to/alexbunardzic/yogi-berra-explains-agile-139b</link>
      <guid>https://dev.to/alexbunardzic/yogi-berra-explains-agile-139b</guid>
      <description>&lt;p&gt;Interviewer: Can you explain Agile?&lt;/p&gt;

&lt;p&gt;Yogi: I can't, but I will. 90% of all Agile is half improvisation. The other half is the part people work on while others are working on something they never worked on with anyone who worked on that team. So if you work on the wrong part, it's right. If you work on the right part, it might be right if you work on it wrong enough. But if you work on it too right, it's wrong.&lt;/p&gt;

&lt;p&gt;Interviewer: I don't understand.&lt;/p&gt;

&lt;p&gt;Yogi: Anyone who understands Agile knows that you can't understand it. It's too complicated. That's what's so simple about it.&lt;/p&gt;

&lt;p&gt;Interviewer: Do you understand it?&lt;/p&gt;

&lt;p&gt;Yogi: No. That's why I can explain it. If I understood it, I wouldn't know anything about it.&lt;/p&gt;

&lt;p&gt;Interviewer: Are there any great Agilists working today?&lt;/p&gt;

&lt;p&gt;Yogi: No. All the great Agilists working today are retired. Except for the ones that are still working. But so many of them are retired, that the ones that are still working are retiring to be like the ones that are retired. Some would kill for it.&lt;/p&gt;

&lt;p&gt;Interviewer: What is TDD?&lt;/p&gt;

&lt;p&gt;Yogi: That's when the test that you should run now happens either before or after you actually run it. In Agile, you don't run tests when they happen because that would be some other type of development. Other types of development can be Agile, but only if they're the same as something different from those other kinds.&lt;/p&gt;

&lt;p&gt;Interviewer: Now I really don't understand.&lt;/p&gt;

&lt;p&gt;Yogi: I haven't taught you enough for you to not understand Agile that well.&lt;/p&gt;

</description>
      <category>agile</category>
    </item>
    <item>
      <title>Code-as-text</title>
      <dc:creator>Alex Bunardzic</dc:creator>
      <pubDate>Sun, 01 Nov 2020 03:09:18 +0000</pubDate>
      <link>https://dev.to/alexbunardzic/code-as-text-5ho</link>
      <guid>https://dev.to/alexbunardzic/code-as-text-5ho</guid>
      <description>&lt;p&gt;It's been more than 70 years since we, the community of software engineers/developers, have been programming computers by writing code as text. Many interesting programming languages have been invented, and many methodologies around those programming languages have been introduced. Still, after all these decades of focused and concentrated programming by writing code the way we write any other text, typical results are disappointing (to say the least).&lt;/p&gt;

&lt;h1&gt;
  
  
  Flimsy software
&lt;/h1&gt;

&lt;p&gt;I don't want to sound gloomy, but ever since I started software development (back in 1990), I've been involved in, or seen too many software development projects that were seriously substandard. And I'm choosing my words carefully here, because I am tempted to use much stronger, more colourful language when assessing the state of typical software projects.&lt;/p&gt;

&lt;p&gt;Of course, I hasten to add that I myself am not immune to this shameful score. When I go back and look into some code I've written 30, or 20, or even 10 - 5 years ago, I cringe.&lt;/p&gt;

&lt;p&gt;I also cringe when I peruse countless other repos (some publicly available on GitHub, some of proprietary nature, reserved for privileged eyes only).&lt;/p&gt;

&lt;p&gt;Overall, not a pretty picture. Poorly written code, buggy and super difficult to scan, difficult to read, to reason about, to refactor and to fix, seems to be plaguing our industry. This flimsy software that is so prevalent in many places is causing serious reasons for concern. Yes, some of those apps are frivolous, they may help people upload an image of their cat or create a meme or some other inane social media gimmick, but many other products deal with more serious matters.&lt;/p&gt;

&lt;p&gt;I spent some time working on projects for health care institutions. I was appalled at the shockingly bad state of the software code one sees in those half-baked repositories. Same thing after spending a decade in the fintech sector. We are talking about software that automates processes that seriously impact patients, their health and well being, as well as citizens and their financial stability.&lt;/p&gt;

&lt;p&gt;What is causing such poor state of affairs?&lt;/p&gt;

&lt;h1&gt;
  
  
  There is no lack of expertise
&lt;/h1&gt;

&lt;p&gt;I cannot with a straight face sit here and claim that our profession is a young one, a baby, an infant that is yet to learn its ways. We've been at it for several generations already. Plus, the high quality of many easily accessible resources, where top experts offer amazing guidance on how to do software properly, has been available for decades.&lt;/p&gt;

&lt;p&gt;Experts of the likes of &lt;a href="https://en.wikipedia.org/wiki/Kent_Beck"&gt;Kent Beck&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Ron_Jeffries"&gt;Ron Jeffries&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Robert_C._Martin"&gt;Uncle Bob&lt;/a&gt; and many many others, have generously offered copious resources, teaching us how to do software the right way.&lt;/p&gt;

&lt;p&gt;Seemingly to no avail.&lt;/p&gt;

&lt;p&gt;So we cannot blame the lack of readily available expert guidance for the appalling state of software development profession. After 70 years at it, and after seeing so many products and repos ending up a cesspool of terrible code, it's time to take stock of the situation: what's going on here?&lt;/p&gt;

&lt;h1&gt;
  
  
  Coding is an exercise of frustrating indirection
&lt;/h1&gt;

&lt;p&gt;The reason we write software code is simple: we want to automate data processing. We write computer programs and in the process we are hoping to instruct computers on how to process/transform data.&lt;/p&gt;

&lt;p&gt;But we don't know how to talk to computers. Those machines are opaque to us. In the early days, computers were a bit more approachable, as early engineers were manipulating them in a physical fashion -- rewiring their circuitry.&lt;/p&gt;

&lt;p&gt;That was quickly proven unwieldy, so scientists invented symbols to stand in for those physical rewiring. Those symbols (i.e. computer code) were entered by programmers in the form of text.&lt;/p&gt;

&lt;p&gt;Entering some text and hoping that computers will understand it was a fool's errand. Nothing like that was possible back then (nor does it seem possible even today), so it was necessary to introduce a level of indirection. That's when compilers were born (and later on interpreters). The job of a compiler/interpreter is to process the text entered by programmers and try to translate it into a set of machine instructions.&lt;/p&gt;

&lt;p&gt;That approach created a lot of frustrations, to the point where the community came up with a slogan (obviously written in utter exasperation): "Computer, do what I meant, not what I told you!"&lt;/p&gt;

&lt;p&gt;Of course, computers are dumb lifeless mechanical/electronic contraptions, so they remain impervious to our pleas.&lt;/p&gt;

&lt;p&gt;But the fact remains that indirections are always frustrating. If I know what I want, and instead of doing it myself I have to try to explain it to some dumb machinery, in the best of cases that would end up being quite awkward. In the not so optimistic cases, such indirection becomes exasperating, leading some to the verge of desperation.&lt;/p&gt;

&lt;p&gt;For example, if I want to position my subtitle on the web page to a certain area on the rendered screen, I cannot directly manipulate its position in the browser. Instead, I need to find and open the appropriate cascading stylesheet file (CSS), and try to understand where in the almost always large text file is the text that talks about position the subtitle (or any other visible element).&lt;/p&gt;

&lt;p&gt;Once I locate that snippet of text, I need to modify it in such a way that it can then instruct some mechanical machinery (in this case, a web browser), where on the screen to position that visible element.&lt;/p&gt;

&lt;p&gt;I can't begin to tell you how many times I went through the frustrating exercise of making a change in the CSS file, reloading the page, and seeing either a completely wrong position of that element, or, worse yet, seeing NO CHANGE on the page!&lt;/p&gt;

&lt;p&gt;Extremely frustrating. Why? One word -- indirection.&lt;/p&gt;

&lt;h1&gt;
  
  
  Instead of manipulating code, manipulate the data
&lt;/h1&gt;

&lt;p&gt;To avoid this problem with indirection (skip the middle man), it would make much more sense to bypass all that charade and directly manipulate the data.&lt;/p&gt;

&lt;p&gt;For example, instead of second-guessing what some modified text in the CSS file may change on the rendered page, it would make much more sense to me to simply go and directly position some visible element on the page, and then let that direct manipulation of data reverse engineer the CSS file and persist the change.&lt;/p&gt;

&lt;p&gt;Similar to that, any other data processing (usually governed by the business policy rules) tends to get very convoluted very quickly if we are trying to implement it by following the indirect model (i.e. write some text and then hoping that everything gets translated properly so that machines could execute the policy rule the way we intended it). It would be much better, less frustrating, less risky, more productive, to simply directly manipulate the data and let the machinery observe what's going on and then reverse engineer our actions and produce the text, or machine code, that will correctly implement desired rule.&lt;/p&gt;

&lt;h1&gt;
  
  
  Need for innovation
&lt;/h1&gt;

&lt;p&gt;As I've mentioned, after 70+ years spent in the land of code-as-text, and after not being able to make any progress (still suffering from incredibly unreliable, buggy and crash prone apps), it is high time to slow down, assess the situation, and start cutting our losses.&lt;/p&gt;

&lt;p&gt;Yes, countless engineers have been rigorously trained to only think in terms of code-as-text, but look where it has gotten us. Isn't it time we start entertaining other possibilities? Obviously, current strategy is not helpful. We are stuck in some dogmatic dream revolving around text that is somehow supposed to become clearly understandable to machines. The innovators among us must now wake up from that dogmatic slumber and invent new, more reliable, less frustrating ways of building software apps.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>software</category>
      <category>futureprogramming</category>
    </item>
    <item>
      <title>Vague software development</title>
      <dc:creator>Alex Bunardzic</dc:creator>
      <pubDate>Fri, 30 Oct 2020 23:36:10 +0000</pubDate>
      <link>https://dev.to/alexbunardzic/vague-software-development-3h0h</link>
      <guid>https://dev.to/alexbunardzic/vague-software-development-3h0h</guid>
      <description>&lt;h1&gt;
  
  
  Uncertainty
&lt;/h1&gt;

&lt;p&gt;We live in the world marked by four characteristics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Uncertainty&lt;/li&gt;
&lt;li&gt;Ambiguity&lt;/li&gt;
&lt;li&gt;Incompleteness&lt;/li&gt;
&lt;li&gt;Confusion &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;From the scientific/philosophical point of view, these traits are well documented and supported by &lt;a href="https://en.wikipedia.org/wiki/Uncertainty_principle"&gt;Heisenberg's Uncertainty Principle&lt;/a&gt; (covering the uncertainty part), &lt;a href="https://en.wikipedia.org/wiki/Tractatus_Logico-Philosophicus"&gt;Wittgenstein's Tractatus Logico-Philosophicus&lt;/a&gt; (the ambiguity part), &lt;a href="https://en.wikipedia.org/wiki/G%C3%B6del%27s_incompleteness_theorems"&gt;Gödel's incompleteness theorems&lt;/a&gt; (the incompleteness aspect), and the &lt;a href="https://en.wikipedia.org/wiki/Second_law_of_thermodynamics"&gt;Second Law of Thermodynamics&lt;/a&gt; (the confusion caused by relentless entropy).&lt;/p&gt;

&lt;p&gt;In this article, I am going to focus on uncertainty. To begin, we must realize that not everything in our world is at the same level of uncertainty (as the inverted pyramid depicted below illustrates):&lt;/p&gt;

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

&lt;p&gt;The inverted pyramid of uncertainty is roughly split into 5 levels: from complete certainty (in the realm of mathematics) all the way up to completely irreducible uncertainty (in the realm of religion, spirituality and philosophy).&lt;/p&gt;

&lt;p&gt;The remaining three levels in-between stretch the notion of risk by attempting to reduce uncertainty onto something that would be, to a lesser or larger degree, predictable and controllable.&lt;/p&gt;

&lt;p&gt;We see that uncertainty increases as we move from physics to chemistry to biology, and then to social constructs such as economics, history, psychology, etc. With uncertainty the risk also increases.&lt;/p&gt;

&lt;p&gt;Traditional fields of engineering could be placed somewhere between mathematics and chemistry. As such, engineering is leaning more toward lower areas of uncertainty.&lt;/p&gt;

&lt;h1&gt;
  
  
  Uncertainty in software
&lt;/h1&gt;

&lt;p&gt;One unfortunate mistake that was made back in the early days of nascent software engineering was to bundle it together with traditional branches of engineering. Moving from that position, it was assumed that software engineering also tends to reside in the lower uncertainty regions. And the same methodology used for building bridges, cars etc. was knee-jerk applied to software engineering.&lt;/p&gt;

&lt;p&gt;Today, almost 70 years later, as we've accumulated a lot of knowledge and experience in software development, we see that software engineering is a different beast. In terms of uncertainty, software engineering is more akin to the levels of uncertainty found in biology, economics and other social constructs:&lt;/p&gt;

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

&lt;p&gt;It is obvious, then, that blindly applying time-tested principles, processes and practices that are prevalent in traditional branches of engineering, is detrimental to the success of software development. Those traditional methodologies are absolutely not applicable to the issues software development teams are faced with while working. Many aspects of not-yet-built products in traditional engineering are completely absent from the software products. It is therefore necessary to invent a different approach to building software.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to deal with uncertainty in software engineering?
&lt;/h1&gt;

&lt;p&gt;Since we have established that Big Plan Upfront (i.e. envisioning the 'end state') does not result in reliable software delivery, we must adjust our sights. While in traditional engineering (such as civic engineering) it makes perfect sense to first envision 'end state' in as many details as possible, such approach in software engineering is not reliable.&lt;/p&gt;

&lt;p&gt;Engineering crews can quite easily envision a bridge that connects one river bank to the opposite river bank. It is relatively straightforward to then produce a phenomenally detailed blueprint of that bridge, which will also include very accurate estimates of the time and cost needed to build it. The level of uncertainty at that point is quite low/manageable.&lt;/p&gt;

&lt;p&gt;No such thing is possible in the world of building software functionality that will automate some business process. There are simply too many unknowns upfront (high levels of uncertainty).&lt;/p&gt;

&lt;p&gt;The only way to reliably proceed with building software products is to keep things relatively vague. Instead of jumping in head first and doing the precision work, teams are advised to first spend some time doing a bit of approximation work.&lt;/p&gt;

&lt;p&gt;That approximation is, and for the most part remains, quite vague. Remaining vague makes sense because we are anticipating bumps in the road and must be prepared to turn on a dime. Expectations change, markets shift, government regulations change, there are crises looming (pandemic etc.) Charging ahead with detailed projections and hardening them into highly precise shipping code is a recipe for disaster.&lt;/p&gt;

&lt;p&gt;The above shift in the approach tends to be quite confusing to many software development teams. Most of the developers have been educated and trained with the traditional engineering mindset as a guiding principle, and this vagueness and ambiguity truly go against every fibre in their being. It takes a lot of re-orientation before the culture shift becomes the norm; we find ourselves at this time right in the middle of this tectonic shift.&lt;/p&gt;

&lt;p&gt;One way to illustrate this shift is to use a metaphor (while keeping in mind that all metaphors tend to stretch thin very quickly, and also tend to require a lot of suspension of disbelief). But hey, it's worth a try. On with the analogy:&lt;/p&gt;

&lt;p&gt;Suppose, then, that we have a customer whose burning ambition is to become a musician. They have no musical training, they don't know anything about music, but for some reason would really love to take the plunge and see if they can become a good musician.&lt;/p&gt;

&lt;p&gt;They hire us to help them achieve that goal.&lt;/p&gt;

&lt;p&gt;If we've been trained to start the project from the envisioned 'end state', we may suggest to our client that the first thing they should do is go and purchase a musical instrument. Usually the first thing that comes to mind is a piano, or maybe a guitar etc.&lt;/p&gt;

&lt;p&gt;We consult with our client, and learn that they have no preferences. They just want to start on something that would be easy for them, although they have no idea what instrument could that be.&lt;/p&gt;

&lt;p&gt;The onus is now on us, the consulting agency, to guide them. A misguided move would be to advise them to splurge on a quality piano. Why would that be misguided? Because of the looming uncertainty. Our client may or may not end up liking the career of a piano player. And they may not be certain about that until significant time and energy has already been spent.&lt;/p&gt;

&lt;p&gt;A better approach (which takes into consideration the inherent uncertainty of our client's situation), would be to advise them to start with something super modest. Perhaps something like...&lt;/p&gt;

&lt;h3&gt;
  
  
  One string cigar box guitar (super cheap!)
&lt;/h3&gt;

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

&lt;p&gt;A one string cigar box guitar is a &lt;em&gt;Very Small Thing&lt;/em&gt; (&lt;em&gt;VST&lt;/em&gt; -- courtesy of &lt;a href="https://ronjeffries.com/"&gt;Ron Jeffries&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;"Haha!", I can only hear some engineers. "You can't be serious?!?"&lt;/p&gt;

&lt;p&gt;Yes, I am very serious. With a bare bones minimum of investment in time and money (an empty cigar box, a stick and a piece of string), we could 'build' a lowly musical instrument in no time flat. So at the very least, our client is not out a considerable sum of money, before they even know in which direction they are going.&lt;/p&gt;

&lt;p&gt;Furthermore, without having to wait for more than an hour or so, our client can now take a plunge and pluck that musical instrument. Get their feet wet, see how it feels for size, get some instant gratification.&lt;/p&gt;

&lt;p&gt;The moment we get there (and it didn't really take long) we solicit feedback from our client. Do they like it? How does it feel? Getting excited? Or they hate it?&lt;/p&gt;

&lt;p&gt;Suppose they like it a bit, and are intrigued. But now they feel like they'd like to try an electric guitar. They happen to have some old fashioned radio box which could be used as an amplifier, so they are itching to hear how would that sound.&lt;/p&gt;

&lt;p&gt;Do we accommodate their request by suggesting they go out and buy electric guitar? Not if we care about our client, and if our job is to minimize their risk of getting into some uncertain transaction. Electric guitars are quite expensive, and who knows, our client may in the end decide they dislike the instrument.&lt;/p&gt;

&lt;p&gt;Instead, we engage in yet another &lt;em&gt;VST&lt;/em&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  One string electric guitar (home made, super cheap!)
&lt;/h3&gt;

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

&lt;p&gt;This time we stretch the budget a bit and go for a simple electric guitar pickup. We screw it into a plank of wood, stretch the string over it, plug it into the old radio, and voila! our client can now have a foretaste of an electric guitar.&lt;/p&gt;

&lt;p&gt;Suppose they don't like the buzzing experience of the electric guitar and would prefer to go into learning how to play acoustic guitar. What do we do next? We find them an inexpensive beat up acoustic guitar and put only one string on it:&lt;/p&gt;

&lt;h3&gt;
  
  
  One string guitar (finally a real guitar!)
&lt;/h3&gt;

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

&lt;p&gt;Why only one string? Again, we like to stick with the &lt;em&gt;VST&lt;/em&gt; philosophy. Keep things small (very small), keep them simple, and if there is any indication that it is safe to proceed, make the next step -- only be sure that the next step is also very small.&lt;/p&gt;

&lt;p&gt;That's the way we deal with uncertainty. Neither we, nor our client, know exactly how will their pursuit of music career play out. It is important not to overwhelm the process, and that's why we prefer to keep things modest and small.&lt;/p&gt;

&lt;p&gt;Our client may begin to like the feeling of pressing that sole string with their fingers and plucking it with another hand. They may even learn a few simple melodies while messing around. So the natural progression will then be to add one more string, let them play around with that. Then if they don't feel lost, add more strings. Get them into playing not only single note melodies, but also double stops, chords, strumming etc.&lt;/p&gt;

&lt;p&gt;There eventually comes a point where the client can see much more clearly where would they actually want to go. They may decide to stay on the course of mastering the 6 string guitar, or who knows -- they may realize that they'd much rather focus on trying to master bass guitar. Or maybe some other string instrument. Or maybe stretch into keyboard instruments, or into percussion?&lt;/p&gt;

&lt;p&gt;It is great if we can guide our client on that journey in such a way not to stress them out, and not to stretch their wallet either. If we do it like that, our client will appreciate our guidance, will call us again, and will recommend our services to others.&lt;/p&gt;

&lt;h1&gt;
  
  
  So what about vague software development?
&lt;/h1&gt;

&lt;p&gt;Same as how we deal with uncertainty in the above hypothetical (and admittedly very contrived) example, when doing software development it is much more respectful to our paying clients to approach it with a healthy dose of modesty. Sticking to the &lt;em&gt;VST&lt;/em&gt; (&lt;em&gt;Very Small Thing&lt;/em&gt;) philosophy will never hurt, and will actually only help a lot.&lt;/p&gt;

&lt;p&gt;In software development, it is very advisable to eschew grandiose 'end state'. We could try it (and many have indeed tried it), but in the end we often come out of it looking arrogant and even clueless.&lt;/p&gt;

&lt;p&gt;Humility is a virtue, and taking our paying clients on a journey with us, small step by small step, while watching the bottom line expenditures very carefully, will demonstrate sincerity and respect to our clients. They will not end up being frustrated, and will gladly call us again and also recommend us to others.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Code comments are a sign that something's off</title>
      <dc:creator>Alex Bunardzic</dc:creator>
      <pubDate>Thu, 29 Oct 2020 01:06:20 +0000</pubDate>
      <link>https://dev.to/alexbunardzic/code-comments-are-a-sign-that-something-s-off-19e1</link>
      <guid>https://dev.to/alexbunardzic/code-comments-are-a-sign-that-something-s-off-19e1</guid>
      <description>&lt;p&gt;Often when we write a block of code, we feel the need to supply an accompanying comment. Some teams value code comments, and insist on leaving as many detailed comments as possible.&lt;/p&gt;

&lt;p&gt;Some other teams may perceive code comments as a sign that the code is actually not finished yet. The code is left in a half-baked state, and the accompanying comment is a reminder to go back and finish ‘baking’ the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Value of code comments depends on the software development philosophy
&lt;/h2&gt;

&lt;p&gt;You may have guessed that those teams who consider comments as a reminder that the code is not finished typically subscribe to the Extreme Programming (XP) software development philosophy.&lt;/p&gt;

&lt;p&gt;The opposite of XP philosophy are teams who value zero-tolerance-for-rework. Such approach is focused on the process of building; there is an envisioned ‘end state’ and there is a perceived gap between ‘here’ and that desired ‘end state’. Software development efforts are therefore focused on bridging the gap from ‘here’ to the ‘end state’ as soon as possible. Stopping on that trajectory in order to change the code that is already written is therefore perceived as a waste of time.&lt;/p&gt;

&lt;p&gt;In contrast, teams practicing XP are focused on the process of changing the code. Instead of practicing gap thinking, they practice present thinking. Such approach may be confusing to the ‘end state’ software development philosophy. How can we keep developing software if there is no clearly defined ‘end state’?&lt;/p&gt;

&lt;p&gt;So a team doing software development without setting their sights firmly on the planned ‘end state’ is prone to doing a lot of rework. As they write micro tests, XP teams let those micro tests evolve the shipping code. During the process of evolution, guided by micro tests, the code that’s already written gets revisited (often more than once). Revisiting the already written code is part and parcel of the discipline we call refactoring.&lt;/p&gt;

&lt;p&gt;Doing development by following such philosophy typically means that any open-ended block of code could drag with it some kind of a code comment. And as we’ve already mentioned, the comment does not necessarily serve to explain to the human reader what the meaning of the code might be; rather, it serves the purpose of enticing developers to finish up the code, to refactor it properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Teamness and oral tradition
&lt;/h2&gt;

&lt;p&gt;High performing teams tend to exhibit strong oral tradition. This strong oral tradition is the cohesive force that keeps team members together, establishes firm trust among colleagues, and cements loyalty to the team. It’s of no surprise that such teams tend to outperform majority of average teams.&lt;/p&gt;

&lt;p&gt;When working under the safety umbrella of strong oral tradition, team members feel less prone to spend precious time on writing detailed documentation. If any time is spent on writing comments, it is only to ensure that no incomplete block of code falls through the cracks and does not get revisited.&lt;/p&gt;

&lt;p&gt;The property of highly cohesive teams is that there are few permanent artifacts outside of the code. On the other hand, teams with low cohesion (i.e. those ‘revolving door teams’ with high staff turnover) depend on copious artifacts that are persisted outside of the code. Oral tradition in such teams is weak/non-existent, and the only way for newcomers to pick up the pieces is by pouring over the documentation/code comments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make transition from communication to collaboration
&lt;/h2&gt;

&lt;p&gt;How can we turn low cohesive, drowning in documentation/comments teams into highly cohesive teams with strong oral tradition? One very effective way is to favour collaboration over communication.&lt;/p&gt;

&lt;p&gt;Teams communicate via emails, sharing documents/diagrams, opening Jira/AzDo tickets, attending meetings and observing rituals and ceremonies.&lt;/p&gt;

&lt;p&gt;None of those activities are necessary for teams that focus on collaboration. The difference is that while communication is mostly asynchronous or scheduled ahead of time, collaboration is always synchronous, in real time, and ad hoc. If a team spends most of the productive time collaborating on solving the problem at hand, when the problem is solved, there seems to be very little need on spending extra time documenting what transpired during the collaboration session. The problem is solved, and the team moves on to solving the next high priority problem.&lt;/p&gt;

&lt;p&gt;Such approach to working is the least wasteful one. Naturally, as teams collaborate and share insights and knowledge in real time, face-to-face, there seems to also be very little need for rolling up their sleeves and writing code comments. The shipping code is implemented, it is expressive, everyone on the team has full grasp and full understanding of what the code does and how it does it. Oral tradition gets strengthened with every collaborative session. There isn’t any need for further communication at that point.&lt;/p&gt;

&lt;h2&gt;
  
  
  What if collaboration is difficult to achieve?
&lt;/h2&gt;

&lt;p&gt;Due to various constraints (organization policies, temporary instability such as pandemic, etc.) sometimes it is not possible to achieve such high performing levels by implementing full blown collaboration. Teams need to fall back on the asynchronous and scheduled modes of communication. In such cases, code comments seem inevitable, no?&lt;/p&gt;

&lt;p&gt;There still may be a better way. But first, let’s take a closer look at why are code comments, as a vehicle of communication, undesirable:&lt;/p&gt;

&lt;p&gt;As the saying goes, code comments are actually lies waiting to &lt;br&gt;
happen. At the time when we write the comment describing what our block of code does, the comment is truthful and accurate. However, as the time progresses, various pressures may cause the block of code to be modified. And at that point there are no guarantees that, with altering the code, the team will also make sure to alter the comment to reflect new, unplanned changes. So now we may introduce the risk of relying on incorrect code comments. More harm than good, when it comes to the accuracy of communication (in the absence of oral tradition).&lt;/p&gt;

&lt;p&gt;The better way in the absence of oral tradition? Practice TDD. With TDD, we evolve the shipping code by writing one micro test at a time. That micro test drives only one change to the shipping code. After that change passes the test, we write another micro test, and so on.&lt;/p&gt;

&lt;p&gt;In the end, or at any point in time during that process, if we examine the tests, we can understand the intention and the meaning of the shipping code. The upside is that we know that the story, as told by tests, is 100% accurate, because tests are executable and represent a healthy state of the shipping app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why are zero-tolerance-for-rework teams bothering with code comments?
&lt;/h2&gt;

&lt;p&gt;One mystery remains unsolved: if zero-tolerance-for-rework teams consider reworking the shipping code an utter waste of time, what's the point in bothering to waste any time writing code comments?&lt;/p&gt;

&lt;p&gt;In other words, since such teams are practising gap thinking and are only focused on bridging the gap from 'here' to the 'end state', isn't the real value they are bringing to the table the discipline of 'doing it once and only once'?&lt;/p&gt;

&lt;p&gt;The gap thinking teams' value proposition is that the only focus that makes sense is to define the 'end state' clearly, then rally all forces and sprint in straight line toward achieving that desired 'end state'. Once we are very clear on how the 'end state' should look like, we analyze it, decompose it, plan and estimate it, and once that gets signed off, we jump in and just build it. The emphasis is on the process of building.&lt;/p&gt;

&lt;p&gt;And since at that point they know exactly what they're building, and they intensely frown upon doing any rework (such a waste of precious time), code comments seem completely redundant.&lt;/p&gt;

&lt;p&gt;Still, we see that gap thinking teams who emphasize the process of building are consistently practising articulate and detailed commenting of the code. What could be the reasoning behind that stringent practice?&lt;/p&gt;

&lt;p&gt;The fact is, while gap reasoning teams are practising zero-tolerance-for-rework, they remain fully open to retries. They are fully tolerant to retrying.&lt;/p&gt;

&lt;p&gt;Which is odd, considering their conviction that they only start building once they obtain clear understanding of the 'end state'. If that's the case, what is the need for retries?&lt;/p&gt;

&lt;p&gt;Experience teaches that almost any time the gap thinking teams deliver the desired 'end state', it turns out to be buggy and needs fixing. That's where the culture and the discipline of retries comes in. And that's where detailed code comments are often life savers.&lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
      <category>codecomments</category>
      <category>communication</category>
      <category>collaboration</category>
    </item>
    <item>
      <title>Software engineering malpractice</title>
      <dc:creator>Alex Bunardzic</dc:creator>
      <pubDate>Sat, 03 Oct 2020 18:03:15 +0000</pubDate>
      <link>https://dev.to/alexbunardzic/software-engineering-malpractice-106a</link>
      <guid>https://dev.to/alexbunardzic/software-engineering-malpractice-106a</guid>
      <description>&lt;p&gt;I recently (let's say couple of years ago) worked on a project where multiple teams were delivering features by attempting to follow Agile DevOps model. At a fairly low level of maturity (seemed like it was their first exposure to DevOps mindset), teams ended up delivering mostly half-baked increments (I was very careful here not to mistype it as 'excrements'). &lt;/p&gt;

&lt;p&gt;That in itself is not surprising (cannot realistically expect high quality delivery from low grade skills), however one thing caught my eye -- no matter how botched the delivered increment was, no one seemed accountable for the defects. The way stakeholders reacted to critical 'severity one' bugs in production was uncanny. They merely shrugged and asked the teams if they could please give it another try!&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with unlimited retries
&lt;/h2&gt;

&lt;p&gt;It seems like many software engineering efforts are being conducted under the arrangement (tacit, of course) that there will not be any limits on how many times they are allowed to retry. What's even more shocking, the unlimited retries clause applied even to re-entrant bugs! When the bug gets discovered in production, teams are assigned to fix it. The fix then goes in, everything looks okay, problem solved. But the real mind-boggling situation occurs when, after a few increments, the exact same bug makes its way back into production.&lt;/p&gt;

&lt;p&gt;No matter how we look at it, re-entrant bugs are a very clear sign that the team working on the product lacks competence to engineer the product properly. And the clincher is that, instead of addressing that lack of competence, stakeholders seem content with merely asking the team to try again.&lt;/p&gt;

&lt;h2&gt;
  
  
  What other professions enjoy the unlimited retries privileges?
&lt;/h2&gt;

&lt;p&gt;I'm trying to think hard here; is there any other profession where you keep delivering botched product/service, and yet suffer no consequences (other than being asked politely to please try again)? Nothing comes to mind. Seems like software engineering is the only such profession. As such, it is the most relaxed, no consequences, no repercussions profession in the world.&lt;/p&gt;

&lt;p&gt;Unlike medical, engineering, education, legal, politics, etc. professions, where one can easily get sued for malpractice, software engineering is blissfully unburdened by any malpractice concerns.&lt;/p&gt;

&lt;p&gt;I can already hear people retorting: "That's not true. If a software engineer continues with delivering botched products, they will get fired."&lt;/p&gt;

&lt;p&gt;Yes, perhaps they will get fired. But that's the only negative consequence of their incompetent actions. And it's a minor one, because that same incompetent software engineer will just walk across the street and get another job. And continue with their malpractice, without anyone being able to do anything about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Software engineering industry is unregulated
&lt;/h2&gt;

&lt;p&gt;To my knowledge, all other industries and professions are, to a larger or lesser degree, regulated. There is a codified set of expectations for any professional activity. Except for software engineering. In the world of software, anything goes.&lt;/p&gt;

&lt;p&gt;We can cobble up any dinky, wobbly app and put it on the market without having to satisfy any regulatory code. The only possible negative repercussions our app may suffer in case of malfunctioning is bad press. Even then, no one can revoke our license to make more of such shoddy, harmful software products.&lt;/p&gt;

&lt;p&gt;Maybe it's high time for our society to start regulating software engineering? Share your thoughts on this issue in the comments. I'll be reading them and will try to reply.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why extract methods when modifying legacy code?</title>
      <dc:creator>Alex Bunardzic</dc:creator>
      <pubDate>Sat, 26 Sep 2020 00:15:01 +0000</pubDate>
      <link>https://dev.to/alexbunardzic/why-extract-methods-when-modifying-legacy-code-e21</link>
      <guid>https://dev.to/alexbunardzic/why-extract-methods-when-modifying-legacy-code-e21</guid>
      <description>&lt;p&gt;Allow me a bit of introspection. I’ve been in Software Engineering field for 30 years. During those 30 years I modified a lot of legacy software. Here is how I would typically do it:&lt;/p&gt;

&lt;p&gt;Over the years I have formed certain habits when working with legacy code. Because on most projects I get paid to deliver working software that is easy to maintain, I cannot afford the luxury of taking my sweet time trying to fully understand the legacy code I am about to modify. So I tend to skim. Skimming the code helps me quickly identify relevant portions in the repo. It is a race with time, and I don’t have cycles at my disposal to dwell on less relevant minutia. I’m always going for the most relevant area in the code. Once I find it, I slow down and start analyzing it.&lt;/p&gt;

&lt;p&gt;I rely heavily on IDEs (power tools). Doesn’t matter which power tool, these days they’re all pretty much capable of doing the same thing. What’s important to me is the ability to quickly find where functions are called and where variables are used.&lt;/p&gt;

&lt;p&gt;Sooner or later, after I’m done skimming the code and analyzing the code segment I’m intending to change, I identify a place where I want to insert some code. Now that I understand the meaning of the classes, components, objects involved in performing the function, I first write a test.&lt;/p&gt;

&lt;p&gt;Following that, I write code to make the test pass. I type the name of the object I intend to use, and then press the period (dot, or “.”) key. Immediately, IDE responds with giving me a full list of methods defined for that object. All those methods are callable from the location where my cursor is.&lt;/p&gt;

&lt;p&gt;I then pick the method that makes sense to me. I fill in the blanks (i.e. supply values for the expected arguments/parameters), save the change, and run the test. If the test passes, I’m done with that micro change.&lt;/p&gt;

&lt;p&gt;The above activity typically gets repeated many times per hour. Throughout the workday, it is not unusual to see the above activity repeated dozens, even hundreds of times.&lt;/p&gt;

&lt;p&gt;I believe the above description of the way I modify software is not unique to the way I formed my work habits. I believe it describes a typical flow that many (I’d even say most) software engineers adhere to.&lt;/p&gt;

&lt;h2&gt;
  
  
  A few observations
&lt;/h2&gt;

&lt;p&gt;The first thing that is apparent after observing the above described way of modifying legacy software is the absence of any work on documentation. Experience has shown that software developers very rarely spend time reaching out for documentation. Time spent preparing the documentation and generating it to produce HTML-style online documents is time wasted.&lt;/p&gt;

&lt;p&gt;Instead, most developers rely solely upon power tools (IDEs). And rightly so (IDEs never lie, as they always offer the real-time picture of the system we are modifying; documentation is more often than not stale).&lt;/p&gt;

&lt;p&gt;Another thing worth noticing is that developers don’t read the source code the way it was written. When writing code from scratch (first pass), many developers tend to write in long functions. Source code tends to bunch up. Bunching code up makes it easier to read and reason about on the first pass, and also makes it easier to debug. But after the first pass is finished, people rarely, if ever, consume the code the way it was written. If we catch ourselves reading a whole function from beginning to end, it is most likely due to the fact that we have exhausted all other options and have no choice but to slow down and read the code in a pedestrian way. However, in my experience, that slow and orderly reading of the code seldom happens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problems caused by the bunched up code
&lt;/h2&gt;

&lt;p&gt;If we were to leave the code as it was written during the first pass (i.e. long functions, a lot of bunched up code to enable easy initial understanding and debugging), it would render IDEs powerless. If we cram all capabilities an object can offer in a single giant function, later on when trying to utilize that object, IDEs will be of no help. IDEs will only show the existence of one method (which will probably contain a large list of parameters providing values that enforce the branching logic inside that method). So we won’t know how to really use that object unless we open its source code and read its processing logic very carefully. And even then, our heads will probably hurt.&lt;/p&gt;

&lt;p&gt;Another problem with hastily cobbled up, ‘bunched up’ code is that its processing logic is not testable. While we can still write an end-to-end test for that code (input values and the expected output values), we have no way of knowing if the bunched up code is doing any other potentially risky processing. Also, we have no way of testing for edge cases, unusual scenarios, difficult-to-reproduce scenarios etc. That renders our code untestable. Which is a very bad thing to live with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Break up bunched up code by extracting methods
&lt;/h2&gt;

&lt;p&gt;Long functions/methods are always a sign of muddled thinking. When a block of code contains numerous statements, it usually means that it is doing way too much processing. Cramming a lot of processing in one place typically means we haven’t carefully thought things through.&lt;/p&gt;

&lt;p&gt;One need not look further than into how companies are typically organized. Instead of having hundreds of employees working in a single department, companies tend to break up into numerous smaller departments. That way, it is much clearer where responsibilities lie.&lt;/p&gt;

&lt;p&gt;Software code is no different. An application exists in order to automate a lot of intricate processing. Processing gets broken into a number of smaller steps, so each step must be mapped onto a separate, isolated block of code. We create such separate, isolated and autonomous block of code by extracting methods. We take a long, bulky block of code and break it up by extracting responsibilities into separate blocks of code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extracted methods enable better naming
&lt;/h2&gt;

&lt;p&gt;Software code is written by developers, but in actuality it is much more often consumed (i.e. read) by developers than it is written.&lt;/p&gt;

&lt;p&gt;When consuming software code, it helps if the code is expressive. Expressiveness boils down to proper structure and proper naming. Consider the following statement:&lt;br&gt;
&lt;code&gt;if((x &amp;amp;&amp;amp; !y) &amp;amp;&amp;amp; !b) || (b &amp;amp;&amp;amp; y) &amp;amp;&amp;amp; !(z &amp;gt;= 65))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It would be literally impossible to understand the meaning and the intention of the above statement without actually running the code and stepping through it with a debugger. Such activity is what we call GAK (Geek at Keyboard). It is 100% unproductive, and is quite wasteful.&lt;/p&gt;

&lt;p&gt;Here is where extract method and naming come to the rescue. Take the complex statement contained within the &lt;code&gt;if&lt;/code&gt; statement, extract it into its own method, and give that method a meaningful name. For example:&lt;br&gt;
&lt;code&gt;public bool IsEligible(bool b, bool x, bool y, int z) {&lt;/code&gt;&lt;br&gt;
   &lt;code&gt;return ((x &amp;amp;&amp;amp; !y) &amp;amp;&amp;amp; !b) || (b &amp;amp;&amp;amp; y) &amp;amp;&amp;amp; !(z &amp;gt;= 65);&lt;/code&gt;&lt;br&gt;
&lt;code&gt;}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now replace the ugly if statement with a more readable statement:&lt;br&gt;
&lt;code&gt;if(IsEligible(b, x, y, z))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Of course, we should also replace dumb one character variable names with more meaningful names to improve readability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reuse in legacy code
&lt;/h2&gt;

&lt;p&gt;Experience shows that any functionality that is not extracted and properly named and moved to the most reasonable class will never be reused. Extract method fosters frequent reuse, which goes a long way toward improving code quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the legacy code
&lt;/h2&gt;

&lt;p&gt;Writing tests for the existing code is hard and feels less rewarding than doing TDD. Even after we identify that there should be several tests that ensure production code works as expected, when we realize that production code has to be changed to enable testing, we often decide to skip writing tests. Our goals to deliver testable code slowly but surely keep diminishing.&lt;/p&gt;

&lt;p&gt;Writing tests for the legacy code is tedious because it often requires to spend a lot of time and code to set up the preconditions. That’s the opposite of how we write tests when doing TDD, where time spent on writing preconditions is minimal.&lt;/p&gt;

&lt;p&gt;Best way to make legacy code testable is to practice the extract method approach. Locating a block of code nested in loops and conditionals and extracting it will enable us to write small precise tests. Such tests on extracted functions improve not only the testability of the code, but also the understandability. If legacy code now becomes more understandable thanks to extracting methods and writing legible tests, chances of introducing any defects are drastically reduced.&lt;/p&gt;

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

&lt;p&gt;Most of the discussion pertaining to extracting methods would not be necessary when we’re doing TDD. Writing one test first and then making the test pass, then scanning that code for more insights into how the code should be structured and improved, making improvements, and finally making changes part of the code base will guarantee that there will be no need to worry about extracting methods. Since legacy code usually means code that was not crafted following TDD methodology, we are forced to adopt a different approach. In my experience, extract methods gives us the biggest bang for the buck when it comes to modifying legacy code while avoiding risks of breaking the functionality.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
