Jekyll2022-01-28T17:20:17+11:00https://miere.observer/feed.xmlMiere’s Personal ObservationsMiere's Personal ObservationsAnalysis: Prioritizing Technical Debt - Part I2021-04-20T00:00:00+10:002021-04-20T00:00:00+10:00https://miere.observer/engineering/2021/04/20/Prioritizing-Technical-Debt-as-if-Time-and-Money-Matters<header class="briefing"> <div class="video"> <iframe class="video" id="youtube-video" src="https://www.youtube-nocookie.com/embed/fl4aZ2KXBsQ?enablejsapi=1&amp;modestbranding=1" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe></div> <p> This post is the part I of the video analysis in which I'll elaborate on a few points exposed by <a href="https://empear.com/blog/">Adam Tornhill</a> on a talk presented in the 2019 GOTO Conference that happened in Copenhagen. As he addressed several topics, I've decided to tackle it into different fronts.</p> <p> In this initial post I'll cover the first half of the video where he approaches technical debts found within a single code base (or repository if you will). There are several points on his presentation that, I believe, are spot on and deserves to be transcribed and better explained. <i>Technical Debts</i> as a concept is something usually underrated by several (if not most of) big companies. The amount of money and man-hour effort spent fixing problems <a href="https://softwareengineering.stackexchange.com/questions/133824/is-it-significantly-costlier-to-fix-a-bug-at-the-end-of-the-project"> is often pointed</a> as an order of magnitude higher than avoiding it before being released into production.</p> </header> <article class="timeline"> <section> <time>0:37</time> <h2>Lehman Law's</h2> <p>Adam will use <a href="https://en.wikipedia.org/wiki/Lehman%27s_laws_of_software_evolution">Manny Lehman's Laws of Software Evolution</a> as the foundation of his argument during the whole talk. <sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup>:</p> <ul> <li><b>Continuing Change</b>: "a system must be continually adapted or it becomes progressively less satisfactory"</li> <li><b>Increasing Complexity</b>: "as a system evolves, its complexity increases unless work is done to maintain or reduce it"</li> </ul> </section> <section> <time>2:20</time> <h2>One shall focus on the real issue</h2> <p> As he points out, there's an inherent conflict between these two laws. <i>"On one hand, we have to continuously evolve and adapt our system but as we do, its complexity will increase which makes it harder and harder to respond to change"</i>. These are so intertwined that it prevents us to perceive the problems as it is, leading us to tackle <i>"the symptoms more than the root cause"</i>. </p> <p> What he has experienced is somewhat similar to what I've witnessed in the past few years. If we, as technical and business leaders, only monitor the tickets we have in the backlog we might not be able to identify the impact that technical debts impose to our users. Therefore, to actually solve the problem, we need to understand the underlying issue - the root cause of the problem. It might imply on revisiting a software, a component design or even how we approach and process the interaction with the user. </p> <p> It worth mention that Tornhill is not advocating perfectionism. In general, users don't mind living with one or two glitches in the app as long as it doesn't impact their work routine. But as we neglect the existence of those technical debts, the time to release of new features or fix bugs grows bigger (and faster) than the symptoms experienced by the users. </p> <p> The clear challenge for product and engineering teams is finding a balance between mitigating technical debt and ensuring the software still delivers valuable experience to its users. </p> </section> <section> <time>6:55</time> <h2>The perils of quantifying technical debt</h2> <blockquote class="quote"> <p>We really have to consider what kind of behaviour do we reinforce by putting our quantitative goal on technical debt. [...] People like us (developers) will optimise for what we are measured on. That most likely means that we're going to pick not only the simplest task, but we're going to pick tasks that we're comfortable with. [...] That also means that we lack the most important aspect of the technical debt: we lack the business impact.</p> </blockquote> <p>It's safe to say that, at this point in time, Adam addresses the biggest wound in the current state of the software development industry. We've been putting much more effort on the results (having less tickets in the backlog) than on the outcomes (deliver more value, or provide a better experience, to our users). By simply removing those issues from our sight we are neglecting to solve the root cause of the problem, as it doesn't guarantee our software won't behave poorly in the foreseeable future.</p> </section> <section> <time>10:50</time> <h2>Assessing the technical debt</h2> <p>Cyclomatic complexity<sup id="fnref:2"><a href="#fn:2" class="footnote">2</a></sup> is probably the most common tool used to identify whether or not a piece of code needs to be revisited due to its complexity. Adam points out, though, that "code complexity is only a problem when we have to deal with it". There's no point in optimizing a complex source that is unlikely to change in the foreseeable future.</p> <p>We can combine Cyclomatic Complexity with Code Change Frequency<sup id="fnref:3"><a href="#fn:3" class="footnote">3</a></sup> analysis. Together they give us a different perspective on how we've been dealing with the software, as we could use it to list which sections of it has been more frequently changed. This metric alone wouldn't be really useful, after all, why should we optimise something that is not complex at all.</p> <p>To better understand the process, Adam proposes us to use our VCS tool and to list the most frequently changed files over a given period of time. Once you spotted a file which has been constantly changed, one can be submit each of the changes (as taken from the VSC repository) to a complexity analysis. The result would a timed series of data that we can plot into Complexity Trend chart - as illustrated by the picture below.</p> <p class="image"> <img src="https://codescene.io/docs/_images/ComplexityTrendSingleSample.png" /> <small>Picture taken from <a href="https://codescene.io/docs/guides/technical/complexity-trends.html">codescene.io</a></small> </p> </section> <section> <time>16:20</time> <h2>Hotspots X-Ray</h2> <p>Refactoring of a given unit of code can be approached in a multitude of ways. Adam emphasised that we should never start a refactor process without taking into account how the team, as a whole, interact with the identified problematic code.</p> <p>Usually, a big refactor might too impactful to be applied straight into the main branch. It implies that we might need to branch that modifications out. The risk is clear, if the main branch is modified more frequently than the refactor branch, it might never be merged back again.</p> <p>Reducing the refactor scope is key to succeed here. The speaker then suggests us to narrow down our problematic code base analysis to the function/method level. His ingenious suggestion allow us deliver valuable enhancements into our software within days rather than weeks (in case you're refactoring a humungous class) or even years (if we've decided to completely overhaul the system).</p> </section> </article> <div class="footnotes"> <ol> <li id="fn:1"> <p>Manny Lehman wrote a set of articles between in the 1970s. He would wrap these articles later in 1980 in a book titled "On Understanding Laws, Evolution, and Conservation in the Large-Program Life Cycle". <a href="https://doi.org/10.1016%2F0164-1212%2879%2990022-0">doi:10.1016/0164-1212(79)90022-0</a></p> </li> <li id="fn:2"> <p><a href="https://en.wikipedia.org/wiki/Cyclomatic_complexity">Cyclomatic complexity</a> is a software metric used to indicate the complexity of a program. It is a quantitative measure of the number of linearly independent paths through a program's source code. It was developed by Thomas J. McCabe, Sr. in 1976.</p> </li> <li id="fn:3"> <p>Code Change Frequency is a measure to identify files that has been more frequently changed. If you are curious to learn how you can address this, you can check out this <a href="https://github.com/bcarlso/defect-density-heatmap"> really interesting repository</a>.</p> </li> </ol> </div>This post is the part I of the video analysis in which I'll elaborate on a few points exposed by Adam Tornhill on a talk presented in the 2019 GOTO Conference that happened in Copenhagen. As he addressed several topics, I've decided to tackle it into different fronts. In this initial post I'll cover the first half of the video where he approaches technical debts found within a single code base (or repository if you will). There are several points on his presentation that, I believe, are spot on and deserves to be transcribed and better explained. Technical Debts as a concept is something usually underrated by several (if not most of) big companies. The amount of money and man-hour effort spent fixing problems is often pointed as an order of magnitude higher than avoiding it before being released into production.Understanding the Rule of Three2020-06-08T00:00:00+10:002020-06-08T00:00:00+10:00https://miere.observer/engineering/2020/06/08/Understanding-the-Rule-of-Three<p>There is this subconscious understanding that unnecessary complexity is root of all evil in software development. We have been <a href="https://twitter.com/search?q=dependency%20hell&amp;src=typed_query">fiercely ranting about the dreadful experience</a> caused by the dependency hell. We’ve been detracting legacy code as <a href="https://s3.amazonaws.com/systemsandpapers/papers/bigballofmud.pdf">big ball of mud because</a> nobody can honestly understand how it works. Fearlessly, we’ve been <a href="https://twitter.com/kumar_abhirup/status/1267777496524574721">shushing our developer mates</a> arguing that they’ve done the wrong coding choices.</p> <p>It is funny how Machiavellian we can become in name of the simplicity. Surely, we can have better days with less cyclic dependencies, we probably can adopt better design patterns or even avoid syntaxes that ordinary people can’t easily read in our source code. But, to remove complexity from our daily routine, we need a systematic approach that help us to weigh up the benefits of every piece of code we introduce in our software.</p> <h2 id="the-rule-of-three">The rule of three</h2> <p class="image right-panel no-background"> <img src="https://imgs.xkcd.com/comics/automation.png" /> <small>Source: <a href="https://xkcd.com/1319/">xkcd</a></small> </p> <p><strong>Benefit-first</strong> <sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">1</a></sup> is a technique to guide the decisions you made when you develop a software. Basically, before introduce any piece of code on your software you have to list pros and cons of adopting it, and analyse the impact of maintaining it in short and long term. If the benefit of introducing it is bigger than the cost of maintaining it, then it is probably safe to proceed.</p> <p>The first piece of advice I’ve ever read that advocated a similar approach came from Martin Fowler on his iconic book <a href="https://archive.org/details/isbn_9780201485677">Refactoring</a>. According to him, we should adopt the <a href="https://en.wikipedia.org/wiki/Rule_of_three_(computer_programming)">rule of three</a> to drive our refactoring decisions, avoiding overcomplicated strategies that might need to <a href="https://www.sandimetz.com/blog/2016/1/20/the-wrong-abstraction">be rethink again in the future</a>. As the book got notorious and relevant, the Rule of Three has been constantly repeated on the internet with subjective definition and, in some cases, with no clear steps to reproduce this technique in the future.</p> <h2 id="distinguishing-chance-coincidence-and-trend">Distinguishing Chance, Coincidence and Trend</h2> <p>My professor of Statistics once taught me about a similar concept: identifying trend behaviour. Letting all mathematic formulas aside, I would reproduce his reasoning and translate to the Software Development world as follows:</p> <ul> <li><strong>Take a chance and design the most simplistic solution to your problem</strong>. As you have a simple piece of code testing it take less time, and it will be easier to adapt in case your needs change.</li> <li><strong>Treat further changes as a coincidence</strong>. We have this instinct to introduce generic solutions to solve problems that might happen in the future. A premature generalization might require further refactoring, or might even be removed altogether being replaced by a different approach in the future. Sometimes, a simple if/else statement is our best choice.</li> <li><strong>A good hint to identify trend behaviours is the introduction of duplicated pieces of code</strong>. That’s the perfect opportunity to introduce abstractions that not only removes these duplications but also allows developers to extend the current logic without modifying it <sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>.</li> </ul> <p>By looking to these rules it is clear that they focus on the software design, diverging from its original proposal as a technique to help you to refactor your code wisely. <em>By adopting it in the early stages of the development, we enforce simple and evolving code over reactive trial-error-refactor approach</em>, where complex solutions will be introduced only when we need to solve a complex problem.</p> <h2 id="final-thoughts">Final Thoughts</h2> <p>Sometimes the requirements are clear enough so you can jump into the complex solution straightaway, but that is not usually the case. The above mindset was an attempt to narrow down the Rule of Three scope and try to make it more reproducible on a daily-basis. As a bonus hint, I’d like to left here another definition that approaches the Rule of Three as something totally different way. I found it when I was reviewing the references for this article and it has been echoing on my mind for a bit of time already. Hopefully it will be just as enlightening for you as it was for me.</p> <blockquote class="quote"> <p>There are two "rules of three" in [software] reuse:</p> <ul> <li>It is three times as difficult to build reusable components as single use components, and</li> <li>a reusable component should be tried out in three different applications before it will be sufficiently general to accept into a reuse library.</li> </ul> <footer> <cite>- Fact#18 from <a href="https://www.amazon.com/Facts-Fallacies-Software-Engineering-FORGOT-ebook-dp-B001TKD4RG/dp/B001TKD4RG">Facts and Fallacies of Software Engineering</a></cite> </footer> </blockquote> <div class="footnotes" role="doc-endnotes"> <ol> <li id="fn:3" role="doc-endnote"> <p>Benefit-first isn’t a term carved by me. Although I’ve never saw any specific mention to this term on a book or a lecture before, I heard about it a few years ago from my <a href="https://twitter.com/anielson">first mentor</a> and I’ve been using it since then. <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:2" role="doc-endnote"> <p>The <a href="https://stackify.com/solid-design-open-closed-principle/">Open-Closed Principle</a> is the perfect technique for this job as, by definition, it closes out methods or classes for modification by introducing customization points that allow it to be extended from outside. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> </ol> </div>There is this subconscious understanding that unnecessary complexity is root of all evil in software development. We have been fiercely ranting about the dreadful experience caused by the dependency hell. We’ve been detracting legacy code as big ball of mud because nobody can honestly understand how it works. Fearlessly, we’ve been shushing our developer mates arguing that they’ve done the wrong coding choices.Analysis: Thinking Asynchronously2020-06-05T00:00:00+10:002020-06-05T00:00:00+10:00https://miere.observer/engineering/2020/06/05/Analisys-Thinking-Asynchronously<header class="briefing"> <div class="video"> <iframe class="video" id="youtube-video" src="https://www.youtube.com/embed/V_tHVUHKqZQ?enablejsapi=1&amp;modestbranding=1" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe></div> <p>This is an opinionated transcription of <a href="https://twitter.com/edjgeek">Eric Johnson's</a> talk <b>Thinking Asynchronously</b>. He has presented in the 2020 GOTO Conference, online edition because of COVID pandemic. His straightforward presentation approach guides us through steps that take advantage of asynchronous persistence pipelines to provide a better experience to our users. It is a great opportunity for newcomers to understand where AWS want to achieve with serverless from know on. I took the opportunity to elaborate more on a few services used by him on his talk to give more context.</p> </header> <article class="timeline"> <section> <time>2:45</time> <h2>Common Serverless Pattern</h2> <p>Usual serverless application will mimic the typical three-tier architecture. API layer will, as naturally happens, be responsible for Security and Routing, while compute layer will have anything else you need to persist your data into the storage layer. On Eric's perspective this comes with a concerning trade-off: if something goes wrong it will probably fail on your code as it is most vulnerable building block of your architecture.</p> </section> <section> <time>5:24</time> <h2>Thinking Asynchronously</h2> <p>Eric proposes that we persist the data before we apply any computation to that. It brings us a few major benefit from the traditional approach:</p> <ul> <li><b>Greater reliability</b>. In case of failure in our codebase, we have our data persisted already.</li> <li><b>Faster response times</b> in our APIs. By moving the extra computation to a second step, the user already received the feedback in the UI.</li> <li><b>We can do more in less apparent time to the client</b>. As the complex computing is now the last thing to do, our persistence pipeline has bigger room to process data with no apparent impact on user's experience.</li> </ul> <p>One might argue that you can squish bits and bytes of your code to provide a similar result. Perhaps the pillars from Eric's approach lies on how it increases the flexibility by reducing the response time on the API side. After all, it's an old known fact that <a href="https://www.nngroup.com/articles/response-times-3-important-limits/">better response times implies better user experience</a>.</p> </section> <section> <time>10:14</time> <blockquote> <p>Well, we talk about serverless we look at "what is serverless?" and basically I meant serverless is: <b>something happens, we react and do something.</b></p> </blockquote> </section> <section> <time>10:45</time> <h2>Event Driven Patterns</h2> <p>Event Driven Development is the key to make the suggested approach work. AWS-wise, there's a <a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-services.html">multitude of events that can you can listen to</a> with a AWS Lambda function. Of course, you can also take advantage of AWS network services like SNS, SQS and Kinesis to consume asynchronous events on your Docker container or application instance.</p> </section> <section> <time>12:06</time> <h2>Amazon API Gateway</h2> <p>I'd like to draw your attention to this versatile service available in AWS, and the idea behind its conception. API Gateway was first <a href="https://aws.amazon.com/about-aws/whats-new/2015/07/introducing-amazon-api-gateway/">introduced in 2015</a>, it communicates directly with 100+ AWS Services, allowing you to transform requests and response payloads with Apache Velocity templating language (VTL). It's commonly used as serverless Rest API, allowing developers to configure HTTP routes in a higher level abstraction in which you don't have to provision resources to handle the request - matching Eric's personal definition of serverless. Requests received by the API Gateway are translated into events, allowing you to listen it directly to any compatible AWS service, like DynamoDB or Lambda.</p> <p>API Gateway is also <a href="https://microservices.io/patterns/apigateway.html">a well known pattern</a>. A few years ago, Netflix OSS team <a href="https://netflixtechblog.com/embracing-the-differences-inside-the-netflix-api-redesign-15fd8b3dc49d">introduced their own API Gateway solution</a>. It was designed with a few key philosophies in mind, "each of which is", in their words, "instrumental in the design of our new system":</p> <ul> <li>Embrace the Differences of the Devices</li> <li>Separate Content Gathering from Content Formatting/Delivery</li> <li>Redefine the Border Between “Client” and “Server”</li> <li>Distribute Innovation</li> </ul> <p>In fact, the problem it solves is wide known between teams handling large fleet of microservices. GraphQL, for instance, approaches these problems from a different perspective, and <a href="https://en.wikipedia.org/wiki/GraphQL">has been in internal use on Facebook since 2012 as well</a>. Since Netflix blog post, several other approaches have been designed at an alternative for the custom brewed API Gateway solution. <a href="https://www.krakend.io/">Krakend</a> is a fairly popular and feature rich stateless API Gateway - might be a good tool for <a href="https://serverless-training.com/articles/save-money-by-replacing-api-gateway-with-application-load-balancer/">those situations where the cost AWS API Gateway is an issue</a>.</p> </section> <section> <time>12:06</time> <h2>Amazon DynamoDB</h2> <p>DynamoDB is an underrated, fascinating <a href="https://www.techopedia.com/definition/29431/database-as-a-service-dbaas">database service</a>. The description on its website doesn't make justice to its capabilities: <sup><a href="#fn:1" class="footnote">1</a></sup> </p> <ul> <li><b>Key-value data store</b> - It fits perfectly as a persistence layer for tasks that requires intensive write throughput - being especially good for timeseries data or document persistence.</li> <li><b>Expirable entries</b> - You can define a Time To Live (TTL) value to arbitrary expire entries on your tables.</li> <li><b>Global tables</b> - DynamoDB can manage tables accessible (replicated) globally.</li> <li><b>In-memory Acceleration with DAX</b> - It acts as a mix of near cache and table space for ly accessed data. Pricey, but might worth it if you take into account the cost of maintaining such a mechanism by your self.</li> </ul> <p>Surely, DynamoDB's <a href="https://aws.amazon.com/dynamodb/">feature list</a> is more extensive than that. But the ones above mentioned are ingredients for a multitude of scalable recipes for problems you might face on your daily routine. From <i>The Poor Man's <a href="https://microservices.io/patterns/data/event-sourcing.html">Event Sourcing</a> Tool</i> <sup><a href="#fn:2" class="footnote">2</a></sup> to a <i>Globally Distributed Ordered Queue</i>, it is the kind of Swiss Knife you want to have on your toolbox when you have a complex situation to tackle. You can even create <a href="https://medium.com/swlh/scheduling-irregular-aws-lambda-executions-through-dynamodb-ttl-attributes-acd397dfbad9">your ad-hoc scheduling mechanism</a>, allowing you "to schedule an irregular point of time execution of a lambda execution without abusing CloudWatch crons".</p> <p>Inevitably, its simple key-value design introduces trade-offs: indexing is quite limited, you can't join tables and you will probably spend a bit of time trying to fine-tuning it for an optimal cost its read and write provisioning <sup><a href="#fn:3" class="footnote">3</a></sup>. But its flexibility and simple API, along with thoughtfully designed persistence tables, might be an elegant and affordable solution for your company.</p> </section> <section> <time>14:20</time> <h2>Other "storage first" options</h2> <ul> <li><a href="https://aws.amazon.com/kinesis/">Amazon Kinesis</a></li> <li><a href="https://aws.amazon.com/s3/">Amazon Simple Storage Service (S3)</a></li> <li><a href="https://aws.amazon.com/sqs/">Amazon Simple Queue Service (SQS)</a></li> </ul> </section> <section> <time>24:28</time> <h2>Amazon EventBridge</h2> <p>This is another obscure but intriguing service available in the AWS portfolio. EventBridge is more than <a href="https://books.google.com.au/books?id=qR0hDgAAQBAJ&amp;pg=PA54&amp;lpg=PA54&amp;dq=old-fashion+service+bus&amp;source=bl&amp;ots=ngRwK-Xg27&amp;sig=ACfU3U34CuRKeKawirqsgr5YT-pRQwFCnw&amp;hl=en&amp;sa=X&amp;ved=2ahUKEwjam8Sov-_pAhUX4jgGHYhdCKcQ6AEwCXoECAoQAQ#v=onepage&amp;q=old-fashion%20service%20bus&amp;f=false">an old-fashion Service Bus</a>, but a blistering fast <a href="https://en.wikipedia.org/wiki/Decision_tree">decision tree</a> capable to translate inputs into actions. It can connect with, basically, everything from AWS Lambda and AWS Step Functions to AWS Kinesis and AWS SQS. You even use AWS SNS to trigger a further HTTP request to an external service.</p> </section> <section> <time>31:03</time> <h2>Lambda Destinations</h2> <blockquote> <p>With Destinations, you can route asynchronous function results as an execution record to a destination resource without writing additional code. An execution record contains details about the request and response in JSON format including version, timestamp, request context, request payload, response context, and response payload. For each execution status such as Success or Failure you can choose one of four destinations: another Lambda function, SNS, SQS, or EventBridge. Lambda can also be configured to route different execution results to different destinations.</p> <footer> <cite>As we've reached the apex of this talk, Eric was so excited that his explanation was a bit disastrous <sup><a href="#fn:4" class="footnote">4</a></sup>, so I decided to quote an <a href="https://aws.amazon.com/blogs/compute/introducing-aws-lambda-destinations/">AWS Blog post about Destinations</a> instead.</cite> </footer> </blockquote> </section> </article> <div class="footnotes"> <ol> <li id="fn:1"> <p>"A fully managed proprietary NoSQL database service that supports key-value and document data structures. DynamoDB can handle more than 10 trillion requests per day and can support peaks of more than 20 million requests per second" - as was seen in the <a href="https://aws.amazon.com/dynamodb/">Amazon DynamoDB</a> description page - 05/Jun/2020.</p> </li> <li id="fn:2"> <p>Depending on how you design your tables, TTL and stream listeners, it might be cheaper than spinning up and maintaining a Kafka cluster.</p> </li> <li id="fn:3"> <p>The pricing model is not the same pay-as-go that you find on most of AWS services, instead of paying for requests you pay for the provisioned read and write capabilities of your tables. It's true that, a long time ago, Amazon introduced auto-scaling capabilities for table provisioning, but still you have to keep its pricing model in mind otherwise you might run out of budget.</p> </li> <li id="fn:4"> <p>Eric's explanation about Lambda Destination: "There is this really cool thing we announced last Re:Invent called Lambda Destinations. And the way this works is I can run a function and if it is successful than I can just trigger some data into EventBridge, Lambda SNS or SQS. Or if it is on fail, I can then trigger data into the same data."</p> </li> </ol> </div>This is an opinionated transcription of Eric Johnson's talk Thinking Asynchronously. He has presented in the 2020 GOTO Conference, online edition because of COVID pandemic. His straightforward presentation approach guides us through steps that take advantage of asynchronous persistence pipelines to provide a better experience to our users. It is a great opportunity for newcomers to understand where AWS want to achieve with serverless from know on. I took the opportunity to elaborate more on a few services used by him on his talk to give more context.Stuff Internet Says About Software Development #12020-05-22T00:00:00+10:002020-05-22T00:00:00+10:00https://miere.observer/news/2020/05/22/What-Internet-Says-About-Software-Development<p><em>This is my reading list from the past few days. I decided to put them here as it might be helpful to someone else. It was deeply inspired by <a href="http://highscalability.com">HighScalability</a> blog, a source I’ve been consuming for years.</em></p> <hr /> <article class="internet-timeline"> <section> <h2>Microsoft all over the places</h2> <h3>Microsoft keeps its push to become a major player in the Open Source community. Let's take a look at the majestic presence they have at the media recently.</h3> <blockquote class="quote"> <p>At Microsoft, 47,000 developers generate nearly <b>30 thousand bugs a month</b>. These items get stored across over 100 AzureDevOps and GitHub repositories. To better label and prioritize bugs at that scale, we couldn’t just apply more people to the problem.</p> <footer> <cite>- <a href="https://www.microsoft.com/security/blog/2020/04/16/secure-software-development-lifecycle-machine-learning/?itm_source=miere.observer"> Secure the software development lifecycle with machine learning </a></cite> </footer> </blockquote> <blockquote class="quote"> <p>Microsoft was on the wrong side of history when open source exploded at the beginning of the century, and I can say that about me personally.</p> <footer> <cite>- <a href="https://www.infoq.com/news/2020/05/rust-winrt-microsoft/?itm_source=miere.observer"> Rust/WinRT Brings Microsoft Closer to Adopting Rust Internally </a></cite> </footer> </blockquote> <blockquote class="quote"> <p>A case study will be written on how Microsoft allowed Zoom to eat their lunch. They spent millions on subterfuge trying to paint Slack as an inferior enemy when MSFT Teams actually can't do what Slack does and Teams' real competitor was Zoom. Now Zoom has 300M Daily Users. Lol.</p> <footer> <cite>- <a href="https://twitter.com/chamath/status/1254522890373885952?s=12&amp;itm_source=miere.observer"> Chamath Palihapitiya </a></cite> </footer> </blockquote> <blockquote class="quote"> <p>Rust/WinRT lets you call any WinRT API past, present, and future using code generated on the fly directly from the metadata describing the API and right into your Rust package where you can call them as if they were just another Rust module.</p> <footer> <cite>- Microsoft president Brad Smith, taken from <a href="https://www.theverge.com/2020/5/18/21262103/microsoft-open-source-linux-history-wrong-statement?itm_source=miere.observer"> Microsoft: we were wrong about open source </a></cite> </footer> </blockquote> </section> <section> <h2>Rust on the Radar</h2> <h3>As we're talking about Rust, it seems that is not only Microsoft who's investing time and effort on it.</h3> <blockquote class="quote"> <p>There are many benefits a standardized ABI would bring to Rust. A stable ABI enables dynamic linking between Rust crates, which would allow for Rust programs to support dynamically loaded plugins (a feature common in C/C++). Dynamic linking would result in shorter compile-times and lower disk-space use for projects, as multiple projects could link to the same dylib. For example, imagine having multiple CLIs all link to the same core library crate.</p> <footer> <cite>- <a href="https://internals.rust-lang.org/t/a-stable-modular-abi-for-rust/12347?itm_source=miere.observer"> A Stable Modular ABI for Rust </a></cite> </footer> </blockquote> <blockquote class="quote"> <p>Programming is hard.</p> <p>Not because our hardware is complex, but simply because we’re all humans. Our attention span is limited, our memory is volatile — in other words, we tend to make mistakes.</p> <footer> <cite>- <a href="https://medium.com/coding-rust/why-rust-b539d0ea5b65?itm_source=miere.observer"> Why Rust? </a> by Omar Faroque</cite> </footer> </blockquote> <blockquote class="quote"> <p>The deno_core crate is a very bare bones version of Deno. It does not have dependencies on TypeScript nor on Tokio. It simply provides our Op and Resource infrastructure. That is, it provides an organized way of binding Rust futures to JavaScript promises. The CLI is of course built entirely on top of deno_core.</p> <footer> <cite>- <a href="https://deno.land/v1?itm_source=miere.observer"> Deno 1.0 </a> by Ryan Dahl, Bert Belder, and Bartek Iwańczuk</cite> </footer> </blockquote> </section> <section> <h2>Fowler and Friends</h2> <h3>It looks like a busy week for Martin Fowler and his friends. New ThoughtWorks Radar was released, a few blog entries has been updated and the man himself has carved another set terms and added to his legacy to the Software Engineering.</h3> <blockquote class="quote"> <p>This division of development into lines of work that split and merge is central to the workflow of software development teams, and several patterns have evolved to help us keep a handle on all this activity. Like most software patterns, few of them are gold standards that all teams should follow.</p> <footer> <cite>- <a href="https://martinfowler.com/articles/branching-patterns.html?itm_source=miere.observer"> Patterns for Managing Source Code Branches </a> by Martin Fowler</cite> </footer> </blockquote> <blockquote class="quote"> <p>For this Radar, we decided to call out again infrastructure as code as well as pipelines as code, and we also had a number of conversations about infrastructure configurations, ML pipelines and other related areas. We find that the teams who commonly own these areas do not embrace enduring engineering practices such as applying software design principles, automation, continuous integration, testing, and so on.</p> <footer> <cite>- <a href="https://www.thoughtworks.com/radar?itm_source=miere.observer"> ThoughtWorks' Technology Radar </a></cite> </footer> </blockquote> <blockquote class="quote"> <p>Coming to understand the threat model for your system is not simple. There are an unlimited number of threats you can imagine to any system, and many of them could be likely. [...] Cyber threats chain in unexpected, unpredictable and even chaotic ways. Factors to do with culture, process and technology all contribute. This complexity and uncertainty is at the root of the cyber security problem. This is why security requirements are so hard for software development teams to agree upon.</p> <footer> <cite>- <a href="https://martinfowler.com/articles/agile-threat-modelling.html?itm_source=miere.observer"> A Guide to Threat Modelling for Developers </a> by Jim Gumbley</cite> </footer> </blockquote> </section> <section> <h2>Other relevant quotes</h2> <h3>Hum, let me see... What else should be mentioned?</h3> <blockquote class="quote"> <p>Zoom scaled from 20 million to 300 million users&lt;/b&gt; virtually over night. What's incredible is from the outside they've shown little in the way of apparent growing pains, though on the inside it's a good bet a lot of craziness is going on.</p> <footer> <cite>- <a href="http://highscalability.com/blog/2020/5/14/a-short-on-how-zoom-works.html?itm_source=miere.observer"> A Short On How Zoom Works </a></cite> </footer> </blockquote> <blockquote class="quote"> <p>Besides being an interesting approach to a very common problem, their discussion of Piranha also provides some very interesting insights into an organization that's *heavily* invested in feature flagging....</p> <footer> <cite>- Pete Hodgson about <a href="https://twitter.com/ph1/status/1263186192951939072?itm_source=miere.observer"> Uber open-sourcing Piranha </a>, a feature-flagging tool</cite> </footer> </blockquote> <blockquote class="quote"> <p>Deferring integration can increase the risk of merge conflicts, which causes you to move more slowly as you spend more energy addressing those conflicts. Slow change can sometimes be more risky than you expect because of the costs of extra work needed to reconcile conflicts, as well as the technical debt that results from bypassing the normal process to fix critical errors.</p> <footer> <cite>- <a href="https://www.techwell.com/techwell-insights/2020/05/code-integration-when-moving-slowly-actually-has-more-risk?itm_source=miere.observer"> Code Integration: When Moving Slowly Actually Has More Risk </a> by Steve Berczuk</cite> </footer> </blockquote> <blockquote class="quote"> <p>Simply put, testing in production means testing your features in the environment where your features will live. So what if a feature works in staging, that's great, but you should care if the feature works in production, that's what matters.</p> <footer> <cite>- Talia Nassi on<a href="https://kentcdodds.com/chats-with-kent-podcast/seasons/03/episodes/talia-nassi-on-testing-in-production?itm_source=miere.observer"> Testing in Production </a></cite> </footer> </blockquote> <blockquote class="quote"> <p>[...] when I was asked to reduce the resource requirements of a large MongoDB cluster, I reached the conclusion that the most obvious target - attribute names - wouldn’t lead to the kind of impact I wanted.</p> <footer> <cite>- Richard Startin on<a href="https://richardstartin.github.io/posts/shrinking-bson-documents?itm_source=miere.observer"> Shrinking BSON Documents </a></cite> </footer> </blockquote> <blockquote class="quote"> <p>The most considerable impact I see is in regards to velocity. The team can focus on other business-impactful projects, rather than EKS and Kubernetes maintenance -- the undifferentiated heavy lifting is eliminated. The same reason people move from physical data centers to the cloud, or from EC2 to Serverless: offloading that effort to AWS is a very good proposition.</p> <footer> <cite>- <a href="https://www.infoq.com/news/2020/05/container-scaling-fargate/?itm_source=miere.observer"> Q&amp;A on Container Scaling with Fargate </a></cite> </footer> </blockquote> <blockquote class="quote"> <p>Did you know that <a href="http://pypi.org">http://pypi.org</a> serves 800 million requests and delivers 200 million packages totalling 400 terabytes ... a day? No. Exactly. You want it to just work. Every day, rain or shine. To keep it that way: sponsor them</p> <footer> <cite>- <a href="https://twitter.com/betatim/status/1246792203894231042?src=miere.observer"> Tim Head </a></cite> </footer> </blockquote> <blockquote class="quote"> <p>We recently migrated a few small systems to CockroachDB (as a stepping stone). Overall, the experience was positive. The hassle free HA is a huge peace of mind. I know people say this is easy to do in PG. I have recently setup 2ndQuadrant's pglogical for another system. That was also easy (though the documentation was pretty bad). The end result is quite different though and CockroachDB is just simpler to reason about and manage and, I think, more generally applicable.</p> <footer> <cite>- <a href="https://news.ycombinator.com/item?id=23087514?itm_source=miere.observer"> latch </a></cite> </footer> </blockquote> <blockquote class="quote"> <p>Our actual use-case is a little complex to go into in tweets. But suffice to say, the PUT costs alone to S3 if we did 1-to-1 would end up being just under half our total running costs when factoring in DDB, Lambda, SQS, APIG, etc.</p> <footer> <cite>- <a href="https://twitter.com/alexbdebrie/status/1250224930643423234?s=12&amp;src=miere.observer"> Wayne Robinson </a></cite> </footer> </blockquote> <blockquote class="quote"> <p>Need operational analytics in <a href="https://twitter.com/hashtag/NoSQL?src=miere.observer">#NoSQL</a>? Maintain time bound rollups in <a href="https://twitter.com/dynamodb?src=miere.observer">@DynamoDB</a> with Streams/Lambda then query relevant items by date range and aggregate client side for fast reporting on scaled out data. Turn complex ad hoc queries into simple select statements and save $$$</p> <footer> <cite>- <a href="https://twitter.com/houlihan_rick/status/1258024512035176450?s=12&amp;src=miere.observer"> Rick Houlihan </a></cite> </footer> </blockquote> <blockquote class="quote"> <p>Another part of the solution is GPU acceleration using grCUDA — an open-source language binding that allows developers to share data between NVIDIA GPUs and GraalVM languages (R, Python, JavaScript), and also launch GPU kernels. The team implemented the performance critical components in CUDA for the GPU, and used grCUDA from Python to exchange data with the GPU and to invoke the GPU kernels.</p> <footer> <cite>- <a href="https://medium.com/graalvm/optimizing-machine-learning-performance-at-netsuite-with-graalvm-and-nvidia-gpus-d0d40f0b0cf1?itm_source=miere.observer"> Optimizing Machine Learning Performance at Netsuite with GraalVM and NVIDIA GPUs </a></cite> </footer> </blockquote> <blockquote class="quote"> <p>Although event-driven architecture has existed for more than 15 years, only recently has it gained massive popularity, and there is a reason for that. Most companies are going through a “digital transformation” phase, and with that, crazy requirements occur. The complexity of these requirements force engineers to adopt new ways of designing software, ones that incur less coupling between services and lower maintenance overhead. EDA is one solution to these problems but it is not the only one.</p> <footer> <cite>- <a href="https://stackoverflow.blog/2020/03/16/how-event-driven-architecture-solves-modern-web-app-problems/?itm_source=miere.observer"> How event-driven architecture solves modern web app problems </a></cite> </footer> </blockquote> <blockquote class="quote"> <p>So, let's look at the resulting context of moving to microservices with entity services:</p> <ul> <li>Performance analysis and debugging is more difficult. Tracing tools such as Zipkin are necessary.</li> <li>Additional overhead of marshalling and parsing requests and replies consumes some of our precious latency budget.</li> <li>Individual units of code are smaller.</li> <li>Each team can deploy on its own cadence.</li> <li>Semantic coupling requires cross-team negotiation.</li> <li>Features mainly accrue in "nexuses" such as API, aggregator, or UI servers.</li> <li>Entity services are invoked on nearly every request, so they will become heavily loaded.</li> <li>Overall availability is coupled to many different services, even though we expect individual services to be deployed frequently. (A deployment look exactly like an outage to callers!)</li> </ul> <footer> <cite>- <a href="https://stackoverflow.blog/2020/03/16/how-event-driven-architecture-solves-modern-web-app-problems/?itm_source=miere.observer"> The Entity Service Antipattern </a> by Michael T. Nygard</cite> </footer> </blockquote> <blockquote class="quote"> <p>Moving all the “what does the world around me look like?” side effects to the beginning of the program, and all the “change the world around me!” side effects to the end of the program, we achieve maximum testability of program logic. And minimum convolution. And separation of concerns: one module makes the decisions, another one carries them out. Consider this possibility the next time you find yourself in testing pain.</p> <footer> <cite>- <a href="https://jessitron.com/2015/06/06/ultratestable-coding-style/?itm_source=miere.observer"> Ultratestable Coding Style </a> by Jessica Joy Kerr</cite> </footer> </blockquote> </section> </article>This is my reading list from the past few days. I decided to put them here as it might be helpful to someone else. It was deeply inspired by HighScalability blog, a source I’ve been consuming for years.Documenting Your Software Architecture2020-05-22T00:00:00+10:002020-05-22T00:00:00+10:00https://miere.observer/engineering/2020/05/22/Documenting-Your-Software-Architecture<p>In the 2000s we went from documenting every single class of our software to not at all. It was an attempt to increase the delivery pace, keeping the team away from tasks that, eventually, have to be remade once the software changes. As a side effect, scaling the team became a problem. The most notable one is the lack of autonomy from its members. Not only newcomers need special attention to get familiarized with the basics of their software (like building and running it), but they would still ask several questions until they understand how it works and how it solves the problem it was designed for.</p> <p>It is a known fact that designing new software requires meticulous planning, strict alignment between team members and keep them focused on the defined goal. Reducing the scope of your documentation to the software architecture might be a good starting point, as you probably don’t need to document every single class of your software to give them enough direction when they are coding. It relieves teams from frequently asked questions and forcing its members to stick with previous definitions unless a big change is necessary, and will let them focus on the business side of their projects.</p> <p>Unlike the lack of autonomy, lack of accountability plays a non-neglectable indirect impact on team performance. Let us assume that in a Software Development team we are going to face only three types of issues: bugs, business-related issues and architecture issues. While Developers are accountable for solving bugs, and Product Owners for business-related issues, even on teams where there’s a dedicated Software Architect nobody responds for the architectural problems the team faces. On first glance, it seems unfair to blame him for a problem that was introduced collectively by a multitude of reasons that happened together.</p> <p>In reality, once the team starts documenting their learnings and architectural decisions they will become more accountable from their architectural decisions. By being fully aware of the technical decisions made in the past and understanding the expected positive outcome it introduced, teams can be accountable for architecture issues on the software, erasing the grey zone between Architecture Decisions and Business Decisions.</p> <h2 id="documenting-for-your-different-audiences">Documenting for your different audiences</h2> <p>Documentation is a tool to transfer knowledge, to keep the team on the same page regarding <strong>what problem the software solves, how those problems were solved, what were the technical decisions that should be followed widely during the development, and how one can run the software and see it in action</strong>. Having long essays written in an MS Word document or a Wiki page is not enough to efficiently convey the information to the team members.</p> <p>On <a href="https://youtu.be/x2-rSnhpw0g">his talk</a> Visualising The Software Architecture, <a href="https://simonbrown.je/">Simon Brown</a> stressed that “as your software have different audiences with different needs”. He means that you need different tools to cover how the different layers of our software work. Thus, along with his iconic C4Model - which will be discussed later - I have adopted a couple of simple-yet-powerful guidelines that helped me to contextualize whoever is maintaining our source code.</p> <h2 id="the-source-code-guideline">The Source Code Guideline</h2> <p>For the sake of productivity, the documentation should be started with the Source Code Guideline, which covers the basics concepts a developer might need to understand how the project source code is structured. A basic version of this document should answer the following questions a developer might have - although it can be enhanced with more topics whenever needed:</p> <ul> <li>How to run the software locally?</li> <li>How to run all automated tests locally?</li> <li>How to package the software?</li> <li>How to deploy the software?</li> <li>How to edit the software?</li> </ul> <p>Bear in mind that long lists of commands can lead to reproducibility issues. So try to keep it as neat as possible, <a href="https://miere.observer/engineering/2020/04/20/Producing-professional-deliverables.html#going-beyond-kents-simple-design">automating it before documenting it</a>.</p> <blockquote class="note"> <a href="https://gist.github.com/miere/cba07143f3f37c64fc0fa82a8e9179a6">Here</a> you can find a sample document that answers these questions with topics, making them easy to read. </blockquote> <h2 id="the-architecture-decisions-guideline">The Architecture Decisions Guideline</h2> <p>Next comes the Architecture Decisions Guideline, which complies of everything that might affect the daily routine of any contributor to your software. It should be straightforward and concise, not only pointing the exact direction one has to follow to contribute to the software, but also introducing them lessons learnt from the past and decision taken to avoid possible issues. It may contain:</p> <ul> <li>An analytical list of problems, techniques and methodologies that should be avoided on the project.</li> <li>A detailed process of how issues should be fixed and how new features should be introduced in the software. Make sure to state the tools involved in this process - e.g. Git branches.</li> <li>A brief explanation of how new releases are rolled out to production.</li> <li>An explanation of how quality is enforced before a release is closed.</li> <li>What coding principles shall be applied otherwise the proposed modifications might be denied.</li> </ul> <p>When to compose this document is a complex topic. Synergic teams are constantly aligned and might be on the same page right from the conception of the software, which would allow the team to postpone the document creation to a future moment. It’s desirable, though, to have it finished once the first stable version of the software is released. Its existence will be the backbone of any code review that might happen in the future. It will ensure that the quality the code base achieved will last long enough so developers can move to the next project with peace of mind.</p> <blockquote class="note"> <a href="https://gist.github.com/miere/bcd10534a0c26f30b7e6d5234c4e903e">Here</a> you can find a sample document that exemplifies how it can be composed. This one, though, is a bit denser than the previous one as it was based on a previously written document taken from a previous customer. </blockquote> <h2 id="the-c4model">The C4Model</h2> <p>C4Model is probably the most pragmatic documentation model I’ve come across. Simon came with the idea to represent the different layers of software with diagrams. When he conceived it, he wanted us to experience a model that worked like maps: by zooming out you get more context you dive into more details, but when you zoom out to better understand in which context the software is running on. According to the way he conceives it, any software can be described in four main layers, each of which is represented by one diagram:</p> <ul> <li><strong>System Context Diagram</strong> - Shows the software in question in the centre, identifying who works with it and what it depends on.</li> <li><strong>Containers Diagram</strong> - Illustrates the overall shape of the architecture and a few technology choices.</li> <li><strong>Components Diagram</strong> - Explains the logical components and their interactions within the component.</li> <li><strong>Code Diagrams</strong> - Explains component implementations in detail.</li> </ul> <p>The first three diagrams are his creations, all of which adopts simplistic notations to demonstrate how a particular piece of the system is working. Code Diagrams, on the other hand, are basically UML and he discourages us to adopt them as they tend to become outdated quite frequently. It is there in the case you have a specific need where documenting the source code itself is mandatory task.</p> <p>C4Model is <a href="https://c4model.com/">well documented on its website</a>, with several years spent polishing it to reach this level of simplicity and organization. The beauty behind these diagrams lies in the fact we can pick our target audience, allowing us to choose when and who should be involved in the documentation process.</p>In the 2000s we went from documenting every single class of our software to not at all. It was an attempt to increase the delivery pace, keeping the team away from tasks that, eventually, have to be remade once the software changes. As a side effect, scaling the team became a problem. The most notable one is the lack of autonomy from its members. Not only newcomers need special attention to get familiarized with the basics of their software (like building and running it), but they would still ask several questions until they understand how it works and how it solves the problem it was designed for.Re: Ensuring backwards compatibility in distributed systems2020-05-20T00:00:00+10:002020-05-20T00:00:00+10:00https://miere.observer/engineering/2020/05/20/Re-Ensuring-backwards-compatibility-in-distributed-systems<p>A few days ago, I spotted a blog post from StackOverflow that drew my attention: <a href="https://stackoverflow.blog/2020/05/13/ensuring-backwards-compatibility-in-distributed-systems/">Ensuring backwards compatibility in distributed systems</a>. That is the sort of topic I love to consume as it gives me new insights and let me know how people are solving similar problems. The article was engagingly good and kept me focused on reading it until the end.</p> <p>I would like, though, to write a few remarks about a few definitions assumed in the article which, if taken by the book, are not strictly correct. The idea behind the following paragraphs is far from detracting the author or the post itself. StackOverflow has a massive audience and knowing the correct definition might help them to adopt the right technique for the right job.</p> <h2 id="conditions-which-the-suggested-deployment-technique-works">Conditions which the suggested deployment technique works</h2> <p>In the blog post, there is a topic about software deployment that covers a few important techniques that might be useful for developers to ensure backward compatibility between evolving versions of the same software. The author emphasized, though, that they will “only work under two conditions”, one of them is applying it to a “brand new software projects”.</p> <p>Reading the article I couldn’t notice a single technique that could not be applied to old software. I had the opportunity to adopt those techniques myself in 2013 when I was hired by <a href="https://www.ibratan.com.br/">Ibratan</a> to redesign their primary software. It was mainly written in C and COBOL and, by adopting a combination of <a href="https://en.wikipedia.org/wiki/Feature_toggle">Feature Toggle</a> and <a href="https://martinfowler.com/bliki/CanaryRelease.html">Canary Deployment</a>, I was able to fix some undesirable behaviours the software had and introduce a new API layer written in Java 8.</p> <p>Personally, there is no such thing as Old Project, or Legacy Software if you will. There are only Well Written Software and Poorly Written Software, and it is possible to adopt any technique you want in both cases. Arguably, you might see a greater benefit in adopting those techniques in a poorly written software as they usually demand more maintenance.</p> <h2 id="canary-release-vs-bluegreen-deployment">Canary Release vs Blue/Green Deployment</h2> <p>Perhaps this is not directly related to the blog post itself, but to a universal feeling that Canary Deployment and Blue/Green Deployment are the same things. Despite their similarities, it is important to distinguish them apart as they introduce different benefits to our deployment pipeline.</p> <p>The term <strong>Blue/Green Deployment</strong> was first introduced <a href="https://gitlab.com/snippets/1846041">ages ago</a>, having been carved by <a href="http://dannorth.net">Daniel Terhorst-North</a> and <a href="https://www.thoughtworks.com/profiles/jez-humble">Jez Humble</a> by early 2010s. The fundamental idea is to have two easily switchable environments to switch between, allowing the software to be pre-released and tested on a deployment environment similar to the production. Once considered stable, a switch mechanism takes place, redirecting user’s request traffic to the just deployed software.</p> <p>The <a href="https://martinfowler.com/bliki/BlueGreenDeployment.html">switch mechanism may vary</a> depending on the business expectation (e.g. high availability SLAs) or different technical needs (e.g. run smoke tests before release) might you have. One of them is the Canary Release. It “is a technique to reduce the risk of introducing a new software version in production by slowly rolling out the change to a small subset of users before rolling it out to the entire infrastructure and making it available to everybody” <sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>.</p> <p>By introducing the ability to analyse the impact of the just-released software with real data coming from the production request stream, <em>Data Analysts</em> and <em>Software Architects</em> can measure the impact the new release will have, rolling it back if the results are not satisfactory. Blue/Green Deployment, on the other hand, is closely related to the deployment itself, therefore it focuses mostly on the technical side of it - namely high-availability and easy rollback.</p> <h2 id="final-thoughts">Final Thoughts</h2> <p>I’d like to stress that the richness of the blog post content should not be blurred away despite the two topics that I covered. Gather all the information needed to compose such post is no easy task and might take precious ours to compose and wrap it in a way that his audience might enjoy. Perhaps a few links in the original to an external content could be enough to clarify the points I’ve made here, although writing down a few paragraphs helped to keep my understanding of those concepts fresh.</p> <div class="footnotes" role="doc-endnotes"> <ol> <li id="fn:1" role="doc-endnote"> <p><a href="https://martinfowler.com/bliki/CanaryRelease.html">Canary Release</a> by <a href="http://www.dtsato.com/blog/">Danilo Sato</a>. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> </ol> </div>A few days ago, I spotted a blog post from StackOverflow that drew my attention: Ensuring backwards compatibility in distributed systems. That is the sort of topic I love to consume as it gives me new insights and let me know how people are solving similar problems. The article was engagingly good and kept me focused on reading it until the end.Analysis: Decomposing a Monolith2020-05-19T00:00:00+10:002020-05-19T00:00:00+10:00https://miere.observer/engineering/2020/05/19/Analysis-Decomposing-Monolith<header class="briefing"> <div class="video"> <iframe class="video" id="youtube-video" src="https://www.youtube-nocookie.com/embed/9I9GdSQ1bbM?enablejsapi=1&amp;modestbranding=1" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe></div> <p>This an opinionated transcription of a talk that <a href="https://samnewman.io/">Sam Newman</a> has presented in the 2019 GOTO Conference, Berlin edition. There were several points on his presentation that, I think, were spot on and deserves to be transcribed and better explained. There is a bit of a debate about whether or not to start from a Monolith and then move to a Microservice Architecture. Understanding how <i>decomposing monolith</i> might not only shed a light on this but also made us understand the benefits of doing it gradually.</p> </header> <article class="timeline"> <section> <time>2:40</time> <h2>Monolith</h2> <p>Sam emphasises that Monolith Service is not the same as a Legacy System. In practice, they differ substantially and we need to observe them differently so we can deliver a better solution to our managers and customers.</p> </section> <section> <time>4:16</time> <h2>Modular Monolith Deployment</h2> <p>After introducing the basic concept of a Monolith, Newman quickly discusses Modular Monolith deployment. Architecture wise, its components are internally split into modules (depending on the language you use it can simply be packages, namespaces or libraries). These modules are using run on the same process and its persistence layer is usually centralized in a single database instance.</p> <p>He believes <i>this is, in theory, a good scenario to be, as these modules can be easily split into smaller services later</i>, reducing the effort to transition the service into a microservice. "Most people are better of in a modular monolith deployment" than in a microservice architecture - as he will discuss later.</p> </section> <section> <time>7:14</time> <h2>Third-party Monolith</h2> <p>Newman describes a third-party monolith as everything "that is completely out of your control", something you can't change its internal behaviour. It might be your CRM software that your SaaS application relies on or even that old piece of software which you don't have the source code.</p> </section> <section> <time>8:01</time> <h2>Distributed Monolith</h2> <p>Distributed Monolith differs from a simple monolith by having its functionalities are split across different services, using the network to communicate with each other. Because of how we split our system apart, or even due to different reasons, we often end up having pieces of code being changed across module boundaries.</p> <p>It is, arguably, the worst scenario you can be as the team who maintains it will have all the challenges a distributed system has along with the downsides of a monolith. It introduces a high cost to change functionalities, larger-scoped deployments and requires higher co-ordination activities - as you have more things that might go wrong.</p> </section> <section> <time>10:20</time> <blockquote> <p>Fundamentally, you have to accept that monolith isn't necessarily the enemy - it's extremely rare that your goal is to kill the monolith. It sometimes happens but, most of the time, you're in a situation where you're trying to achieve something as a business but your current architecture won't let you achieve that goal.</p> </blockquote> <p>This is an important bit from his presentation and it needs to be transcribed as is. A Monolith Service by itself is not a bad thing and, like any other architectural decision, it has its pros and cons. We should only switch from a monolith to a microservice architecture when its benefits overcome the cost of maintaining a complex distributed system.</p> </section> <section> <time>12:44</time> <blockquote> <p>You won't appreciate the true horror, pain and suffering of microservices until you're running then in production.</p> </blockquote> <p>Perhaps a good start might be extracting one module from your Modular Monolith into an external service. What you learn from observing this new service might give you enough insights to continue with the transition from a monolith to a microservice architecture.</p> </section> <section> <time>15:15</time> <h2>Strangler Fig Pattern</h2> <p>At this point in his presentation, Sam cut the chase and started to present solutions (architectural patterns) that will help us to decompose a monolith service. Strangler Fig is a pattern in which you wrap new functionalities around the existing ones in a way that the existing solution is not changed or is aware of it. In practical terms, he suggests us introduce an HTTP Proxy to intercept calls to the existing service diverting the calls to the new one as well.</p> <p>The <b>Strangler Fit Pattern fits perfectly when we are at the beginning of the transition to a microservice or when dealing with Third-Party Monoliths</b>, as other components of our existing solution still depend on the data managed by the one which will be replaced. The original component tables will still be fed with new data, giving us time to rethink or redesign other components in the future.</p> </section> <section> <time>22:04</time> <h2>Branch By Abstraction</h2> <p>Although his explanation about this pattern was good enough for a presentation in front of a big audience, I reckon his own definition (taken from <a href="https://samnewman.io/patterns/architectural/branch-by-abstraction/">his blog</a>) wraps it up perfectly.</p> <blockquote> <p>When making a significant change to how a piece of functionality is implemented, the challenge is how to work on this reimplementation over a period of time. With branch-by-abstraction, you create a single abstraction point over the functionality to be reimplemented, allowing both the existing functionality and the new implementation to co-exist inside the same running process at the same time.</p> </blockquote> <p>At this point in his presentation, he started to describe the ideal step-by-step to implement this pattern. I've modified it slightly to make it easier to reproduce.</p> <ol> <li><b>Isolate the current implementation</b> - This is the first and most important and delicate step of this pattern, where you isolate the current implementation from the rest of the service. At this step you have to move the logic of the current functionality you intend to replace and move it to a single place (same package, module or folder).</li> <li><b>Create an abstraction point</b> - Create an interface that will behave as the contract to call that given functionality. With the <a href="http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod">Liskov Substitution Principle</a> in mind, you must make sure your software calls a default implementation of this internal, which will call your just isolated functionality.</li> <li><b>Start working on the new service implementation</b> - Once you finish, the new service will be later called by the monolith via HTTP (assuming that you exposed the new functionality through a Web API) and the web client should be wrapped in an alternative implementation of the just created interface.</li> <li><b>Switch over when it is ready to release</b> - </li> <li><b>Clean up</b> - Observe production and gather data to assess the results. A rollback is still possible at this point, allowing you to revisit the implementation until everything is working perfectly. Once everything is working as expected, you can remove the old functionality from your codebase.</li> </ol> </section> <section> <time>26:07</time> <h2>Parallel Run</h2> <p>Being a variation of Branch by Abstraction, Parallel Run allows both implementations to co-exist at the same time. This is particularly useful to check if the behaviour has changed. Although both branches have different implementations it's expected that they to behave the same way, unless otherwise noted. Therefore, when comparing the outcome of both functionalities, it's important to take the original implementation as the source of truth, where any discrepancy in the result comparison between them should be considered a failure in the new service.</p> </section> <section> <time>28:10</time> <h2>Accessing the Data</h2> <p>Entering in the last stage of his talk, Sam finally addresses what he describes as the hardest topic when decomposing a monolith: how to organize and access the data on from/on the just created service. On his conception, on the evolutionary point of view, the data migration should be comprised by the following steps.</p> <ol> <li><b>Temporarily reuse the existing functionality database</b> - Direct communication between the new service and the existing database would be allowed in as a temporary measure to stabilize the new functionality. Treating this as a permanent solution, though, might be the beginning of a new distributed monolith due to how tightly coupled both services became.</li> <li><b>Expose the existing data via API</b> - This solution is intended to reduce, but not remove, the coupling between both services. It gives developers more flexibility to react to possible changes that might happen in the database schema. He encourages us, though, to revisit the way information is consumed or ingested to avoid cyclic dependencies between both services - a common antipattern found in distributed monoliths.</li> <li><b>Move the data to the new service</b> - Turning the new service into the source of truth is the definitive move to finish the migration from monolith to a microservice architecture. It comes with its challenges though. Joins between tables have to be rethought, split tables might be necessary and referential integrity provided by the database layer is completely off the table.</li> </ol> </section> </article> <h2>Takeaways from talk</h2> <p>Newman did a brilliant job outlining the tradeoffs of prematurely adopting Microservice Architecture and I reckon there’s richness on his speech when he describes the dreadful consequences when we mistakenly end up creating a Distributed Monolith. Tackling the issues it introduces leads us to <a href="https://github.com/korfuri/awesome-monorepo">introduce new hacks in our architecture and deployment pipeline</a>, like monorepo or shared modules between services. As Microservices are independently deployable - and generally speaking share no source code between them - our CI/CD is actually simpler. It is a good balance between cost and delivered value to our stakeholders.</p> <p>By reading between the lines we can also notice how much he is concerned about monitoring the runtime environment and tackle unexpected issues at early stages of its deployments. Due to the complexity of distributed systems, handling network and hardware issues before the business requirements make the software complex would save us several hours of development.</p>This an opinionated transcription of a talk that Sam Newman has presented in the 2019 GOTO Conference, Berlin edition. There were several points on his presentation that, I think, were spot on and deserves to be transcribed and better explained. There is a bit of a debate about whether or not to start from a Monolith and then move to a Microservice Architecture. Understanding how decomposing monolith might not only shed a light on this but also made us understand the benefits of doing it gradually.Producing Professional Deliverables2020-04-20T00:00:00+10:002020-04-20T00:00:00+10:00https://miere.observer/engineering/2020/04/20/Producing-professional-deliverables<p>When someone is described as a professional one might see that person as someone who does something for a living. Others might agree with the Cambridge dictionary, seeing professionals as those who have “[…] the type of job that needs a high level of education and training” <sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>. Perhaps we can all agree that the meaning of words evolves as time passes by - having its meaning adapted to suit a more recent context. Maybe “professional” in the modern days might’ve acquired different meaning from what it used to have in the past.</p> <h2 id="the-need-for-consistency">The need for consistency</h2> <p>Let’s take football players <sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> for a moment. They only begun getting paid as professionals since last quarter of the 18th century <sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup> but when we compare the quality of the games back then with nowadays’, and we put nostalgia aside, the gap is huge. Pelé, Maradona, Zidane and Messi are historically regarded as those who took the game to the next level. But so did managers and coaches, “who dreamed up catenaccio and zonal marking and the sweeper system, all of it designed to stop the virtuosos showcasing their talents” <sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup>.</p> <p>The bar was raised to a point where we’ve been scoring less than a hundred years ago <sup id="fnref:4:1" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup>. While only a few players can keep up with their careers for more than 8 years <sup id="fnref:4:2" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup>, most of them tend to retire quite early - especially if compared to a software engineer. In fact, the most successful footballers were those who had more <strong>consistent performance</strong> in their teams.</p> <p><em>Consistency</em> is probably the most desirable skill I look for when I hire someone. Independently on how senior as an engineer you are, delivering consistent results means that I can predict how long it takes for you to finish your tasks, how many issues you might introduce in software and, how much effort should I put for you to reach the ideal performance within the team.</p> <p>The more senior you are the fewer issues you might introduce, the faster you can learn and adopt a new technique and the more adaptable you are to tackle problems you’ve never faced before. But, if you don’t master the techniques you’ve learned before in a way that you produce consistent results, your seniority might be easily replaceable by a junior. Think about it, if you can learn consistently, the more I teach you the more improvement I can see on your deliverables. On the other hand, a non-consistent senior developer might learn something new and put it in practice straight away but may struggle to use it under a different scenario as he hasn’t trained long enough to master his new skill.</p> <h2 id="reproducibility-is-key">Reproducibility is key</h2> <p>If we go a few centuries back, we would see craft workers (such as <a href="https://en.wikipedia.org/wiki/Artisan">Artisans</a>) in action, perhaps the contemporary version of the Software Engineer as we know it <sup id="fnref:7" role="doc-noteref"><a href="#fn:7" class="footnote" rel="footnote">5</a></sup>. A skilled craft worker creates material objects partly or entirely by hand. Artisans were the dominant producers of consumer products before the Industrial Revolution. Once passed through the career chain from apprentice to journeyman, he could be elected to become a master craftsman, enjoying one of the highest social statuses in their communities at the time. <sup id="fnref:6" role="doc-noteref"><a href="#fn:6" class="footnote" rel="footnote">6</a></sup></p> <p>The success of the <a href="https://en.wikipedia.org/wiki/British_Agricultural_Revolution">Agricultural Revolution</a> of the 18th century created a favourable climate for industrialization. With increasing production of food, the British population could be fed at lower prices with less effort than ever before. The surplus of food meant that British families <a href="https://study.com/academy/lesson/causes-of-the-first-industrial-revolution.html">could use the money they saved to purchase manufactured goods</a>. Under given circumstances, it’s easy to understand that craft workers weren’t enough to cope with the higher demand for goods that were needed.</p> <p>Just as the demand for consistent and reliable delivered goods ended up replacing artisans with machines, <span class="highlight">the overwhelming demand for value to be provided by the current software industry will also raise the bar</span> in a way that Software Engineers who lack precision, predictability or measurement won’t make it far in their careers.</p> <p>To better understand this idea, let’s assume a developer was elected by his team to design a microservice from scratch. On his team, there’s no one in charge of the infrastructure or taking macro architectural decisions. A good outcome from this project might be big deal for his reputation, especially if no one else has to worry about bugs if there’s a brief README file explaining how to run the software locally and releasing a new version of it is just a matter of having a Pull Request approved.</p> <p>One might argue that taking care of all of these details consumes valuable time that would be better spent implementing new features. But I dread the days when I had to stop what I was doing to answer questions from my colleagues when they have to maintain a software I’ve previously written without proper documentation. Eventually, I realized that when the README file is good enough I have fewer interruptions. When my unit tests cover most of - if not all - the source code, I have fewer bugs to fix and hence have more time to create something new.</p> <p>A wise engineer, though, may go even further and streamline his knowledge in a way that can be easily reproducible as well. What if a Kotlin developer has <a href="https://github.com/Skullabs/kos-sample-gradle">a small Gradle project</a> on his Github account? Why don’t we create <a href="https://github.com/miere/terraform-aws-fargate-ha-web">a module to deploy our software using Docker</a>? Wouldn’t it be useful if you save that <a href="https://github.com/miere/terraw">small script</a> that automates everything you need to run your terraform scripts? If designing software is the main part of your job, perhaps you should figure out a way to reproduce the boring tasks as quickly as possible when the necessity comes up you will be able to deliver a masterpiece much faster than anyone else.</p> <h2 id="going-beyond-kents-simple-design">Going beyond Kent’s Simple Design</h2> <p>Speaking of masterpieces, in the 1990s Kent Beck introduced The Four Elements of Simple Design, a principle that would be later immortalised in his <a href="https://www.amazon.com/gp/product/0201616416">book Extreme Programming Explained</a>. He states these rules as follows:</p> <ul> <li>Runs all the tests</li> <li>Has no duplicated logic. Be wary of hidden duplication like parallel class hierarchies</li> <li>States every intention important to the programmer</li> <li>Has the fewest possible classes and methods</li> </ul> <p>His rules were written in priority order, where the ones at the top take priority over the following ones. It comes as no surprise that, if you can’t afford the time to have all of it, he would like you to put more effort into tests. Being behind the roots of unit testing frameworks we have nowadays <sup id="fnref:9" role="doc-noteref"><a href="#fn:9" class="footnote" rel="footnote">7</a></sup>, the author of <a href="https://en.wikipedia.org/wiki/SUnit">SUnit</a> and <a href="https://en.wikipedia.org/wiki/Kent_Beck">co-authoring</a> JUnit with Erich Gamma, he’s an avid advocate of testing as feedback tool <sup id="fnref:8" role="doc-noteref"><a href="#fn:8" class="footnote" rel="footnote">8</a></sup>, something you can read from the man itself on his award-winning book <sup id="fnref:10" role="doc-noteref"><a href="#fn:10" class="footnote" rel="footnote">9</a></sup> <a href="https://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530/">Test-Driven Development by Example</a>.</p> <p>Let’s take the popular <a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">MVC pattern</a> to draw a comparison with Beck’s rules. Between the late 2000s and early 2010s, MVC was considered the <em>silver bullet pattern</em> for his adopters <sup id="fnref:11" role="doc-noteref"><a href="#fn:11" class="footnote" rel="footnote">10</a></sup>. In an era where nobody was actually concerned about <a href="https://en.wikipedia.org/wiki/Separation_of_concerns">Separation of Concerns</a> and the front-end was mostly rendered by the backend, it was indeed quite convenient to grow your software by simply placing classes in one of its three buckets. Despite its convenience, not all software designed mostly using MVC (from end-to-end) is easy to maintain, once it grows bigger the need for new features to be included urges us to adopt different approaches - a phenomenon well described by Meir Lehman <a href="https://ieeexplore.ieee.org/document/1456074">in another master piece</a> <sup id="fnref:12" role="doc-noteref"><a href="#fn:12" class="footnote" rel="footnote">11</a></sup>.</p> <p>Kent’s rules, on the other hand, are distinguished from other methodologies by focusing on the <em>outcome you might have</em> instead of <em>how one has to organize his code</em>. It is benefit-driven, encouraging you to adopt whatever strategy you have in your playbook as long as you respect those outcomes. As a result, maintainability and fast feedback on breaking changes will be the benefits those who adopt it will be rewarded with. That’s the actual mindset a professional has that to keeps the <strong>quality</strong> of their deliverables higher than the average.</p> <p>Since it’s been more than 2 decades since these rules have been crafted, if you allow me, I’d like to respectfully include a couple of items that I think should be mandatory for any professional delivery in software.</p> <ol> <li>It should be possible to run all your tests with a single (yet simple) command.</li> <li>It should be possible to run your software with a single (yet simple) command.</li> <li>It should be possible to package your software with a single (yet simple) command.</li> </ol> <p>While these 3 rules I’m introducing might be seen as silly at first glance, it makes perfect sense when you need to handover your deliverable to someone else. Just as Beck’s rules, they’ve been ordered by priority as well, thus, if you can’t afford to have all of them, just make sure one can painlessly run all tests and check for regressions on your software. The last two rules are somewhat related, as you need to package your software to run it locally. Thoroughly reviewing all the dependencies (libraries, tools, and dependent services) your service relies on are <a href="https://dzone.com/articles/learn-how-to-setup-a-cicd-pipeline-from-scratch">the foundation to have a hassle free CI/CD setup process</a>.</p> <h2 id="takeaways">Takeaways</h2> <p>Professionalism is a quite subjective topic, but it worth keeping in mind that we’re living in a different world where the current standards of our industry expect higher delivery pace, and less time spent on bugs or amending poorly developed features. Even complex structures have been shrewdly discouraged. In fact, managers are going one step further in this direction, trying their best to reduce the learning curve when developers jump in to maintain a different microservice, independently from whether the developer is a newcomer or a long-time hero within the company <sup id="fnref:13" role="doc-noteref"><a href="#fn:13" class="footnote" rel="footnote">12</a></sup>.</p> <p>If I could sum up the aforementioned topics, I’d say the Professional Software Engineer from nowadays should be consistently capable of delivering high-quality software in a way that anyone with the source code could maintain it with no hassle.</p> <hr /> <p><em>Special thanks to <a href="https://www.linkedin.com/in/gabrielsjacques/">Gabriel Jacques</a>, Ricardo Baumgartner and <a href="http://vnaik.com">Varun Naik</a> for their contributions.</em></p> <div class="footnotes" role="doc-endnotes"> <ol> <li id="fn:1" role="doc-endnote"> <p><a href="https://dictionary.cambridge.org/dictionary/english/professional">Cambrige dictionary’s definition of the word “professional”</a> <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:2" role="doc-endnote"> <p><a href="https://en.wikipedia.org/wiki/Football_player">Football</a>, also known as soccer for the Americans <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:3" role="doc-endnote"> <p><a href="https://en.wikipedia.org/wiki/Fergus_Suter">Fergus Suter</a> was arguably the first recognised professional footballer. <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:4" role="doc-endnote"> <p>Instead of the consistent and insistent downward trend in goals we have seen over a century and a half of play, in the last 60 years or so there appears to be a levelling off. Goals are not dying. They are plateauing. Scoring has remained essentially stable in the last two decades, perhaps even as far back as the 1970s. See: <a href="https://slate.com/culture/2013/08/the-numbers-game-why-soccer-teams-score-fewer-goals-than-they-did-100-years-ago.html">The Great Leveling</a> <a href="#fnref:4" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:4:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a> <a href="#fnref:4:2" class="reversefootnote" role="doc-backlink">&#8617;<sup>3</sup></a></p> </li> <li id="fn:7" role="doc-endnote"> <p>In fact, there’s a whole movement in which developers describe themselves as Software Craftsman. Perhaps the best description of how Software Engineering became more relevant in the field can be found in <a href="https://en.wikipedia.org/wiki/Software_craftsmanship">this article</a> in Wikipedia. <a href="#fnref:7" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:6" role="doc-endnote"> <p>See <em>History of Western Civilization</em> at Boise State University’s <a href="https://web.archive.org/web/20090107061228/http://history.boisestate.edu/westciv/medsoc/23.shtml">“Document No.23”</a>. Archived from the <a href="http://history.boisestate.edu/westciv/medsoc/23.shtml">original</a> on 2009-01-07. Retrieved 2009-01-08. <a href="#fnref:6" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:9" role="doc-endnote"> <p>Kent Bech is often cast as the mind that leads to the <a href="https://en.wikipedia.org/wiki/XUnit">xUnit</a> frameworks being widely adopted. <a href="#fnref:9" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:8" role="doc-endnote"> <p><a href="https://medium.com/@kentbeck_7670/programmer-test-principles-d01c064d7934">According to Beck</a>, “Programmer tests are an oracle providing feedback coding-decision-by-coding-decision”. <a href="#fnref:8" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:10" role="doc-endnote"> <p>Co-authored by Addison-Wesley, the book is award-winning of the Jolt Productivity Award. <a href="#fnref:10" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:11" role="doc-endnote"> <p><a href="https://twitter.com/miere/status/14496627913924608">Here</a> is a discussion (in PT_BR) back in 2010 I had on Twitter about this very topic, showing how heated a conversation can get when enquiring MVC developers about MVC replacements. At the time, I was under heavy training by <a href="https://twitter.com/anielson">one of my previous mentors</a>, as he noticed my knowledge was mostly focused on hardware and low-level software development neglecting common design patterns. <a href="#fnref:11" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:12" role="doc-endnote"> <p>In 1974, Lehman stated in his book that “as an E-type system evolves, its complexity increases unless work is done to maintain or reduce it”. <a href="#fnref:12" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:13" role="doc-endnote"> <p>It worth read about <a href="https://hbr.org/2014/01/how-netflix-reinvented-hr">how Netflix reinvented the way they manage their teams</a>, what are their expectations and for how long they’ve decided to invest and quality and reproducibility on their teams to avoid rework and spend more time on what will have higher return of investment. <a href="#fnref:13" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> </ol> </div>When someone is described as a professional one might see that person as someone who does something for a living. Others might agree with the Cambridge dictionary, seeing professionals as those who have “[…] the type of job that needs a high level of education and training” 1. Perhaps we can all agree that the meaning of words evolves as time passes by - having its meaning adapted to suit a more recent context. Maybe “professional” in the modern days might’ve acquired different meaning from what it used to have in the past. Cambrige dictionary’s definition of the word “professional” &#8617;