<?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: João Guimarães</title>
    <description>The latest articles on DEV Community by João Guimarães (@jccguimaraes).</description>
    <link>https://dev.to/jccguimaraes</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%2F13671%2Fe09adffb-7fb7-4619-ab5f-bffad33fcc78.jpeg</url>
      <title>DEV Community: João Guimarães</title>
      <link>https://dev.to/jccguimaraes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jccguimaraes"/>
    <language>en</language>
    <item>
      <title>Performance Development</title>
      <dc:creator>João Guimarães</dc:creator>
      <pubDate>Tue, 09 Jun 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/jccguimaraes/performance-development-1k39</link>
      <guid>https://dev.to/jccguimaraes/performance-development-1k39</guid>
      <description>&lt;h1&gt;
  
  
  Abstract &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Carefully planning all stages of development can ease our expectations in terms of architectural decisions, roadmaps, costs, technical dept, among other aspects.&lt;/p&gt;

&lt;p&gt;Opening and keeping a communication channel between the engineering and product teams is an import part of the process and should be taken seriously.&lt;/p&gt;

&lt;p&gt;The concepts of load testing and stress testing add valuable information about the performance of your application and how you can act to mitigate degradation of service you provide to the users.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Opinions are my own and not of my employer&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  The concept &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt; has become an important piece in development as it provides historical and real-time value on how an application (ex: a micro-service) reacts to different demands. With this data, we can also tailor our infrastructure to be optimised to those demands.&lt;/p&gt;

&lt;p&gt;Performance development is thinking through every step in our development and it should be considered as a daily practice.&lt;/p&gt;

&lt;p&gt;Considering that we as developers take advantage of many tools to help us comply with code standards (ex: &lt;a href="https://eslint.org"&gt;ESLint&lt;/a&gt; or &lt;a href="https://commitlint.js.org"&gt;Commitlint&lt;/a&gt;), so why can't we use tools that will enable us to comply with performance as well?&lt;/p&gt;

&lt;p&gt;So how can we track performance?&lt;/p&gt;

&lt;h1&gt;
  
  
  Tracking performance &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Performance can be impacted by &lt;em&gt;two&lt;/em&gt; factors, the &lt;strong&gt;codebase&lt;/strong&gt; and the provisioned &lt;strong&gt;infrastructure&lt;/strong&gt;. &lt;strong&gt;Monitoring&lt;/strong&gt;/&lt;strong&gt;Observability&lt;/strong&gt; is implied in both.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;codebase&lt;/strong&gt; can have poor architectural decisions that will affect in many ways its performance such as maintainability, memory and CPU consumption, among others.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;infrastructure&lt;/strong&gt; can also have a huge impact in performance, mainly if it's under dimensioned which can crash the application for no apparent reason or by making poor decisions that lead to vertically scaling the infrastructure.&lt;/p&gt;

&lt;p&gt;Both factors are strongly connected in the early stages as you need to provisioning infrastructure to deploy the &lt;strong&gt;codebase&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monitoring&lt;/strong&gt; can impact the &lt;strong&gt;codebase&lt;/strong&gt; hard, but it definitely can provide valuable insights on the performance of the &lt;strong&gt;codebase&lt;/strong&gt; and &lt;strong&gt;infrastructure&lt;/strong&gt; with a well thought &lt;em&gt;observable system&lt;/em&gt; implementation.&lt;/p&gt;

&lt;p&gt;If you are interested in Monitoring, please read my &lt;a href="https://www.yld.io/blog/modern-monitoring/"&gt;Modern Monitoring&lt;/a&gt; post for a more in-depth analysis.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Monitoring incurs additional costs. Logs can drastically affect performance (ex: throughput of a micro-service). Infrastructure monitoring also incurs costs with your cloud provider.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you rely on a cloud provider to manage and deploy, consider starting first with a small compute engine machine, or low impact image when using container orchestrators such as &lt;a href="https://kubernetes.io"&gt;Kubernetes&lt;/a&gt;. These are also valid for &lt;em&gt;on-prems&lt;/em&gt; solutions.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;serverless&lt;/strong&gt; solutions, the scenario is slightly different since the infrastructure is mainly managed by the provider itself. But apart from this difference, the rest should also apply.&lt;/p&gt;

&lt;p&gt;As new features are developed, chances are your application will get more "greedy" and demanding or perhaps the user demand itself changed. Running the load tests against these new scenarios will detect new issues.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Now we can act upon that!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We can review/refactor the &lt;strong&gt;codebase&lt;/strong&gt; and/or apply changes to the provisioned &lt;strong&gt;infrastructure&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Development process &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;As mentioned above, starting a new project often involves setting up code analysis tooling and that gets defined somewhere or by someone, normally a company or a team policy.&lt;/p&gt;

&lt;p&gt;With this common ground in mind, we also need "&lt;em&gt;policies&lt;/em&gt;" for what we are targeting in terms of business value. This &lt;em&gt;somewhere&lt;/em&gt; or someone is the &lt;strong&gt;stakeholders&lt;/strong&gt;/&lt;strong&gt;product&lt;/strong&gt; team. These "&lt;em&gt;policies&lt;/em&gt;" can be defined as &lt;strong&gt;SLA&lt;/strong&gt;s but we will discuss more about this later on.&lt;/p&gt;

&lt;p&gt;This means we need numbers to track performance and develop our process of measuring it.&lt;/p&gt;

&lt;p&gt;Continuing with a micro-service example, what's the excepted maximum number of simultaneous requests hitting it? And how can we guarantee that our &lt;strong&gt;codebase&lt;/strong&gt; is up to that challenge and our infrastructure is well provisioned to withstand that demand? The answer is &lt;strong&gt;load testing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;stakeholders&lt;/strong&gt;/&lt;strong&gt;product&lt;/strong&gt; expectations define our threshold to work with.&lt;/p&gt;

&lt;p&gt;With this threshold in mind, a well-implemented &lt;strong&gt;load testing&lt;/strong&gt; step ensures us that any modification on the &lt;strong&gt;codebase&lt;/strong&gt; or &lt;strong&gt;infrastructure&lt;/strong&gt; never falls below the threshold. And if it comes to that, we can immediately take action and make amends or changes to surpass it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't run &lt;strong&gt;load testing&lt;/strong&gt; blindly! Your consumers are your own. Act accordingly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If &lt;strong&gt;stakeholders&lt;/strong&gt;/&lt;strong&gt;product&lt;/strong&gt; fails to provide solid and reliable load scenarios then the architecture/development is crippled. Same goes the other way around, If the designed and implemented architecture is not optimised and maintainable then most likely you will fail delivering your service below stipulated &lt;strong&gt;SLA&lt;/strong&gt;s.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Load testing&lt;/strong&gt; can be effective to identify real markers such as latency, 3rd parties response timeouts, or any other particular dependency your application has.&lt;/p&gt;

&lt;p&gt;How can we identify all of these?&lt;/p&gt;

&lt;p&gt;In order to gather, digest, correlate and analyse all these markers we need an &lt;em&gt;observable system&lt;/em&gt;, as mentioned above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring &amp;amp; Observability &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Observability describes the ability of how accurate we can observe the characteristics of an external output of a system and infer it as a measure of its internal state.&lt;/p&gt;

&lt;p&gt;A system should have &lt;em&gt;health checks&lt;/em&gt;, &lt;em&gt;metrics&lt;/em&gt;, &lt;em&gt;log entries&lt;/em&gt; and &lt;em&gt;end-to-end tracing&lt;/em&gt; in order to be considered observable.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Observability&lt;/em&gt; is not &lt;em&gt;Monitoring&lt;/em&gt;!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To make &lt;strong&gt;performance development&lt;/strong&gt; possible it requires a good &lt;em&gt;monitoring&lt;/em&gt; &amp;amp; &lt;em&gt;observability&lt;/em&gt; system capable or retrieving valuable information from your &lt;strong&gt;codebase&lt;/strong&gt; and &lt;strong&gt;infrastructure&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Every action depends on the accuracy and reliability of all those data types a system provides. Choose your service wisely and most of all that it provides most of the tools you need. Different services are harder to maintain and sync data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load Testing &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;As we have been discussing, &lt;strong&gt;load testing&lt;/strong&gt; evaluates the performance of an application allowing us to detect issues with the current &lt;strong&gt;infrastructure&lt;/strong&gt; and &lt;strong&gt;codebase&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But how can we add this step to our development process?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run against the &lt;strong&gt;production&lt;/strong&gt; environment;&lt;/li&gt;
&lt;li&gt;Provision an environment that &lt;strong&gt;mirrors&lt;/strong&gt; production.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Please read &lt;a href="https://www.yld.io/blog/load-testing-micro-services/"&gt;Load testing micro-services&lt;/a&gt; by &lt;a href="https://twitter.com/Johnytiago"&gt;João Tiago&lt;/a&gt; for a deep dive on a real example of the first approach.&lt;/p&gt;

&lt;p&gt;The approach you choose to take depends on how much value it adds to the application. The reason I choose the second approach lays the foundation for &lt;strong&gt;stress testing&lt;/strong&gt;, which is described in the next section.&lt;/p&gt;

&lt;p&gt;If your application depends on 3rd party APIs you may need to contact your liaison to understand what impact running the tests will have on their servers. Solutions to this problem are for them to provisioning a sandbox or for you to mock their API.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There's a chance the 3rd party starts blocking requests from your load tests if you don't contact them for clarification on their limitations if any.&lt;/p&gt;

&lt;p&gt;If you mock their API take special attention to mock their limitations as well, such as maximum timeouts, throttling, etc.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The infrastructure provisioned &lt;strong&gt;MUST&lt;/strong&gt; be identical to production but with the difference that it will be an &lt;strong&gt;ephemeral&lt;/strong&gt; environment.&lt;/p&gt;

&lt;p&gt;Consider using the CI/CD pipeline workflow to trigger the &lt;strong&gt;load testing&lt;/strong&gt; step before the application is deployed to &lt;strong&gt;production&lt;/strong&gt;, although it can also be a parallel step which won't affect the deployment to &lt;strong&gt;production&lt;/strong&gt;. The key takeaway is that it's a really important step to keep taps on the performance of your application, and should be part of the pipeline workflow.&lt;/p&gt;

&lt;p&gt;One important thing to take into account is where you're making the requests to your application. If you're targeting people all over the world and you have a multi-region deployment, consider adding this geographic constrains as well as it influences latency your consumers might experience.&lt;/p&gt;

&lt;p&gt;Here's a simple example of an application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa8y1ai6m7dcvybdxcchz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa8y1ai6m7dcvybdxcchz.png" alt="Alt Text" width="800" height="239"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1an9dn1932jxrcvmbc02.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1an9dn1932jxrcvmbc02.jpg" alt="Alt Text" width="800" height="212"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhmg9qz01divum8atni5a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhmg9qz01divum8atni5a.png" alt="Alt Text" width="800" height="276"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fann1ui6b9zucrrn3fxwb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fann1ui6b9zucrrn3fxwb.png" alt="Alt Text" width="800" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After running a &lt;strong&gt;load test&lt;/strong&gt; we detect that this machine type has a low CPU and a high memory for its usage, so it's easy to figure out that we may need to change the provisioned type to one with higher CPU and lower memory.&lt;/p&gt;

&lt;p&gt;The next step, &lt;strong&gt;stress testing&lt;/strong&gt;, is an additional step to &lt;strong&gt;load testing&lt;/strong&gt; due to its unique purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stress Testing &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A particularly interesting step of &lt;strong&gt;performance development&lt;/strong&gt; is &lt;strong&gt;stress testing&lt;/strong&gt;, which simulates scenarios of abnormal peaks until the application crashes, providing awareness and predictability of the application.&lt;/p&gt;

&lt;p&gt;By knowing the hard limitations of the infrastructure, we can start thinking about ways to mitigate the loss of QoS - Quality Of Service (ex: scalability).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The purpose of any &lt;strong&gt;stress testing&lt;/strong&gt; is to crash something  -  &lt;strong&gt;always&lt;/strong&gt;!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, we need to understand the importance of SLI, SLO and &lt;strong&gt;SLA&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SLI&lt;/strong&gt; (Service Level Indicators) "...&lt;em&gt;are well-defined metrics that describe the behaviour of the system&lt;/em&gt;";&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SLO&lt;/strong&gt; (Service Level Objectives) "...&lt;em&gt;are specific targets for those SLI&lt;/em&gt;";&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SLA&lt;/strong&gt; (Service Level Agreement) "...&lt;em&gt;lists SLO that define the performance guarantees to customers and its consequences if they are not met&lt;/em&gt;".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Stress testing&lt;/strong&gt; is extremely important to profile your infrastructure and identify signs of degradation in our application.&lt;/p&gt;

&lt;p&gt;By &lt;strong&gt;monitoring&lt;/strong&gt; &amp;amp; &lt;strong&gt;observability&lt;/strong&gt;, we can define, for example, when our infrastructure needs to scale up.&lt;/p&gt;

&lt;p&gt;There are some interesting and most common ways of scaling your application.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Proactive cyclic&lt;/strong&gt; is defined by a periodic scaling that occurs at a fixed interval (daily, weekly, monthly, quarterly);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proactive event-based&lt;/strong&gt; scales just when we expect a big surge of traffic due to a scheduled business event (new product launch, marketing campaigns);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-scaling based on demand&lt;/strong&gt; requires a monitoring service so the system can send triggers to take appropriate actions such as scaling up or down based on metrics (utilisation of the servers or network i/o, for instance).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another "side effect" of running this step is that we can see similarities with a (D)DoS - &lt;em&gt;Distributed Denial of Service&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;There is a distorted relation between what a &lt;em&gt;DoS infrastructure layer&lt;/em&gt; attack will havoc, and a &lt;strong&gt;stress testing&lt;/strong&gt; tries to accomplish as both are meant to damage the availability of your service to the point of collapsing.&lt;/p&gt;

&lt;p&gt;This is a perfect step to validate all the mechanisms in place to stop a (D)DoS attack, for example, throttling requests, and so on.&lt;/p&gt;

&lt;p&gt;This is all great, but there are a lot of nuances here. When running a &lt;strong&gt;stress testing&lt;/strong&gt; you don't want those mechanisms to act because it can be a legitimate scenario of abnormal peak usage. This can be tricky to configure or provision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Costs &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Everything discussed so far comes with a price, and that price often is a steep one at the end of the month.&lt;/p&gt;

&lt;p&gt;The key takeaway from all of this is that there will be a tradeoff between costs and the confidence developers will have deploying.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusions &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Although a bit extensive, the purpose of this post was not to be in-depth on each step. There are many approaches to each one and honestly, it may be different in your situation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I hope you can identify yourself with all of the above. 😊&lt;/p&gt;

&lt;p&gt;Please share positive feedback about this topic. 🙏&lt;/p&gt;

&lt;p&gt;Thank you! ❤️&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Links &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.yld.io/blog/load-testing-micro-services/"&gt;Load testing micro-services&lt;/a&gt; by &lt;a href="https://twitter.com/Johnytiago"&gt;João Tiago&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.yld.io/blog/modern-monitoring/"&gt;Modern Monitoring&lt;/a&gt; by &lt;a href="https://twitter.com/jccguimaraes"&gt;João Guimarães&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>performance</category>
      <category>development</category>
      <category>microservices</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Designing an API</title>
      <dc:creator>João Guimarães</dc:creator>
      <pubDate>Thu, 22 Aug 2019 13:15:58 +0000</pubDate>
      <link>https://dev.to/jccguimaraes/designing-an-api-1e3d</link>
      <guid>https://dev.to/jccguimaraes/designing-an-api-1e3d</guid>
      <description>&lt;p&gt;Over the last year I have been given the chance to work with some amazing people and we all have been developing micro-services that expose RESTful APIs.&lt;/p&gt;

&lt;p&gt;Through out all this year we had to integrate with other APIs, such as RESTful, NVP - Name-Value Pair, etc, and both internal or external 3rd parties.&lt;/p&gt;

&lt;p&gt;Making sure the project runs without any major incident is hard work. It involves a lot of people from a lot of departments and their ability to share information is the most vital part before developing the API.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In no way am I stating that these are the right approaches to take when designing an API. I am just sharing what I have learned the hard way.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So here are some points I find important to keep in mind when given a new task, aka, build a new micro-service.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand the API dependencies;

&lt;ul&gt;
&lt;li&gt;a &lt;em&gt;dependency&lt;/em&gt; can be an internal API, external API or an AWS service you need to integrate with, etc...&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Understand if those dependencies provide all the functionality the API requires (both tech and business);

&lt;ul&gt;
&lt;li&gt;does it fit the purpose;&lt;/li&gt;
&lt;li&gt;how well it is documented/supported;&lt;/li&gt;
&lt;li&gt;is it too strict;&lt;/li&gt;
&lt;li&gt;how flexible regarding unforeseen/future changes.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Understand what the API &lt;strong&gt;MUST&lt;/strong&gt; deliver;

&lt;ul&gt;
&lt;li&gt;current deliver;&lt;/li&gt;
&lt;li&gt;future deliveries &lt;em&gt;(although in an agile environment this is a fuzzy topic)&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;An API contract;

&lt;ul&gt;
&lt;li&gt;a &lt;em&gt;contract&lt;/em&gt; is an agreement between two or more parties that develop/consume the API.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;API documentation;&lt;/li&gt;

&lt;li&gt;API testing.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;All above topics can be grouped into 3 main categories:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;API dependencies&lt;/li&gt;
&lt;li&gt;API specification&lt;/li&gt;
&lt;li&gt;API development&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  API dependencies
&lt;/h2&gt;

&lt;p&gt;As I stated above, this is where typically you will have the business and technical requirements and you or your team start brainstorming/spiking on the best course of action.&lt;/p&gt;

&lt;p&gt;This means, understanding what are the API dependencies and their added value.&lt;/p&gt;

&lt;p&gt;From personal experience, you always miss some edge cases so it is a good practice to use UML sequence diagrams to help you structure how your endpoints will behave, such as request headers, payloads, responses, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is an UML sequence diagram?
&lt;/h3&gt;

&lt;p&gt;An &lt;strong&gt;UML sequence diagram&lt;/strong&gt; describes how operations are carried out in an interactive format. They are time based and they show the order of those interactions. They also specify all the participants in the workflow.&lt;/p&gt;

&lt;p&gt;A visual interpretation helps you keep track of the workflow and define happy paths as well as errors from any 3rd party API and how your own API should deal with that information.&lt;/p&gt;

&lt;p&gt;How can we as a developer take advantage of sequence diagrams? By using tools such as &lt;a href="http://plantuml.com/" rel="noopener noreferrer"&gt;PlantUML&lt;/a&gt; or &lt;a href="https://mermaidjs.github.io/" rel="noopener noreferrer"&gt;mermaidJS&lt;/a&gt; which allows us to generate diagrams from textual representations.&lt;/p&gt;

&lt;p&gt;A simple example with PlantUML (taken from the official website):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@startuml
Alice -&amp;gt; Bob: Authentication Request
Bob --&amp;gt; Alice: Authentication Response

Alice -&amp;gt; Bob: Another authentication Request
Alice &amp;lt;-- Bob: Another authentication Response
@enduml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which will generate the next image:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F6d99osiyx4nluwrjastf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F6d99osiyx4nluwrjastf.png" alt="small-example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a cool feature because it can be control versioned.&lt;/p&gt;

&lt;p&gt;I find that &lt;a href="https://mermaidjs.github.io/" rel="noopener noreferrer"&gt;mermaidJS&lt;/a&gt; is still a little behind of &lt;a href="http://plantuml.com/" rel="noopener noreferrer"&gt;PlantUML&lt;/a&gt; in terms of integrations and functionalities but they are both powerful tools and I have used both in different contexts. You should use the one that best fits your needs.&lt;/p&gt;

&lt;p&gt;If you use &lt;a href="https://www.atlassian.com/software/confluence" rel="noopener noreferrer"&gt;Confluence&lt;/a&gt;, there is a nice plugin for &lt;a href="http://plantuml.com/" rel="noopener noreferrer"&gt;PlantUML&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  API specification
&lt;/h2&gt;

&lt;p&gt;After you have defined the diagrams, the next step is to start drafting the contract.&lt;/p&gt;

&lt;p&gt;This contract should be "signed off" in a standard specification that most developers can be familiarised with. Luckily the &lt;strong&gt;&lt;a href="https://www.openapis.org/" rel="noopener noreferrer"&gt;OpenAPI Specification&lt;/a&gt;&lt;/strong&gt; has been here for a while.&lt;/p&gt;

&lt;p&gt;The specification is written in yaml and it can also be control versioned.&lt;/p&gt;

&lt;p&gt;Once again and from personal experience, the drafted contract may suffer small to medium changes. Which is normal, it's a contract where more than one team is involved and feedback is always a good thing.&lt;/p&gt;

&lt;p&gt;Always be open to suggestions but don't forget that your team owns the API.&lt;/p&gt;

&lt;p&gt;Discussion is healthy and allows us to see different angles to achieve the same goal.&lt;/p&gt;

&lt;p&gt;Keep in mind that your API may also suffer changes in the future which may impact production environments. So think wisely on versioning your API being that through path versioning such as &lt;code&gt;/v1&lt;/code&gt;, etc. Or by headers such as GitHub's example &lt;code&gt;Accept: application/vnd.github.v3+json&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are like me and your OCD kicks in when the topic "API versioning" comes to the table then read this interesting post about Evolvable APIs from Fagner Brack - &lt;a href="https://medium.com/@fagnerbrack/to-create-an-evolvable-api-stop-thinking-about-urls-2ad8b4cc208e" rel="noopener noreferrer"&gt;To Create An Evolvable API, Stop Thinking About URLs&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  API development
&lt;/h2&gt;

&lt;p&gt;It's time to take all the value we gained before to start implementing it into code. Just make sure to follow the contract and protect the micro-service against unexpected 5xx popping into production.&lt;/p&gt;

&lt;p&gt;But depending on the language you choose to code, a big part of the development is testing - unit, functional, etc...&lt;/p&gt;

&lt;p&gt;With the right tools you can prepare functional test scenarios by using &lt;a href="https://www.getpostman.com/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt; or &lt;a href="https://insomnia.rest/" rel="noopener noreferrer"&gt;Insomnia&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.getpostman.com/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt; has a neat feature which is called &lt;a href="https://github.com/postmanlabs/newman" rel="noopener noreferrer"&gt;Newman&lt;/a&gt; where you can run a collection against a file to check if your endpoints follow the contract.&lt;/p&gt;

&lt;p&gt;At this point I had shared tools that can be version controlled along with the current code. Making it easy to keep all of them synced.&lt;/p&gt;

&lt;h1&gt;
  
  
  Demoing with an example
&lt;/h1&gt;

&lt;p&gt;Nothing is better than an "almost real" example to demonstrate everything described above.&lt;/p&gt;

&lt;p&gt;This example is based on making capture, void and refund transactions, given an authorization identifier.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;an authorization identifier means that we locked some amount from the payment method used by a customer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Fictional requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;capture the authorization;

&lt;ul&gt;
&lt;li&gt;charge the account an amount lower or equal than the locked funds in a specified currency;&lt;/li&gt;
&lt;li&gt;returns a transaction identifier for possible refund.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;void the authorization;

&lt;ul&gt;
&lt;li&gt;release the locked funds.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;refund the account;

&lt;ul&gt;
&lt;li&gt;providing a valid transaction identifier;&lt;/li&gt;
&lt;li&gt;returns a refund transaction identifier.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;all above actions &lt;strong&gt;MUST&lt;/strong&gt; be validated against another fictional internal API;

&lt;ul&gt;
&lt;li&gt;validate that accountId is linked to the authorizationId.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;all above actions &lt;strong&gt;MUST&lt;/strong&gt; have a required &lt;a href="https://api.data.gov/docs/api-key/" rel="noopener noreferrer"&gt;X-Api-Key&lt;/a&gt; header;

&lt;ul&gt;
&lt;li&gt;for security reasons.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;all above actions &lt;strong&gt;SHOULD&lt;/strong&gt; have an &lt;a href="https://hilton.org.uk/blog/microservices-correlation-id" rel="noopener noreferrer"&gt;X-Correlation-Id&lt;/a&gt; header.

&lt;ul&gt;
&lt;li&gt;for keeping track of workflows.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Let's name the micro-service as &lt;code&gt;process-transactions&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Planning with sequence diagrams
&lt;/h2&gt;

&lt;p&gt;From the previous fictional requirements we can define 3 participants:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;USER&lt;/strong&gt; - The API consumers;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MS&lt;/strong&gt; - The API micro-service;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API&lt;/strong&gt; - The API consumed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A draft of the diagram should resemble as the following image:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fhw2d3up9w0aqav7ey0xc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fhw2d3up9w0aqav7ey0xc.png" alt="capture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tooling for PlantUML
&lt;/h3&gt;

&lt;p&gt;Consider the following file structure.&lt;/p&gt;

&lt;pre&gt;
&lt;b&gt;./images
./plantuml
├── capture.puml&lt;/b&gt;
&lt;/pre&gt;

&lt;p&gt;Where &lt;code&gt;capture.puml&lt;/code&gt; has the following content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@startuml

participant "USER" as A
participant "MS" as B
participant "API" as C

title //process-transactions// micro-service capture workflow

rnote left A
**headers**
  X-Api-Key&amp;lt;font color="red"&amp;gt;*&amp;lt;/font&amp;gt; //&amp;lt;string&amp;gt;//
  X-Correlation-Id //&amp;lt;string&amp;gt;//
end note

activate A
A -&amp;gt; B: **POST** ""/capture/:authorizationId""

rnote left A
**payload**
  accountId:&amp;lt;font color="red"&amp;gt;*&amp;lt;/font&amp;gt; //&amp;lt;string&amp;gt;//
  amount:&amp;lt;font color="red"&amp;gt;*&amp;lt;/font&amp;gt; //&amp;lt;number&amp;gt;//
  currency:&amp;lt;font color="red"&amp;gt;*&amp;lt;/font&amp;gt; //&amp;lt;string&amp;gt;//
end note

rnote left B
**headers**
  X-Api-Key&amp;lt;font color="red"&amp;gt;*&amp;lt;/font&amp;gt; //&amp;lt;string&amp;gt;//
  X-Correlation-Id //&amp;lt;string&amp;gt;//
end note

activate B
B -&amp;gt; C: **POST** ""/validate""

rnote left B
**payload**
  accountId:&amp;lt;font color="red"&amp;gt;*&amp;lt;/font&amp;gt; //&amp;lt;string&amp;gt;//
  authorizationId:&amp;lt;font color="red"&amp;gt;*&amp;lt;/font&amp;gt; //&amp;lt;string&amp;gt;//
end note

alt success request

rnote right B
**headers**
  X-Correlation-Id //&amp;lt;string&amp;gt;//
end note

activate C
B &amp;lt;-- C: ""**200** OK""

rnote right B
**payload**
  success: //true//
end note

|||

B -&amp;gt; B: capture amount
activate B
deactivate B

rnote right A
**headers**
  X-Correlation-Id //&amp;lt;string&amp;gt;//
end note

A &amp;lt;-- B: ""**200** OK""

rnote right A
**payload**
  transactionId: //&amp;lt;string&amp;gt;//
end note

|||

else failure request

rnote right B
**headers**
  X-Correlation-Id //&amp;lt;string&amp;gt;//
end note

B &amp;lt;-- C: ""**200** OK""
deactivate C

rnote right B
**payload**
  success: //false//
end note

rnote right A
**headers**
  X-Correlation-Id //&amp;lt;string&amp;gt;//
end note

A &amp;lt;-- B: ""**422** UNPROCESSABLE ENTITY""
deactivate B

rnote right A
**payload**
  error: //true//
  reason: Conditions could not be met
end note

|||

end
deactivate A

@enduml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use the package &lt;code&gt;node-plantuml&lt;/code&gt; for generating the sequence diagram as an image.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npm install node-plantuml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;puml generate -s -o ./images/capture.svg ./plantuml/capture.puml&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we have a version controlled file that describes our &lt;code&gt;/capture&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing the contract in the OpenAPI Specification
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;PlantUML&lt;/code&gt; gives us a pretty good view of what the &lt;code&gt;capture&lt;/code&gt; endpoint expects as a request and responses.&lt;/p&gt;

&lt;p&gt;Remember that at this point the micro-service logic is still a &lt;strong&gt;black-box&lt;/strong&gt;, and it should remain that way for now.&lt;/p&gt;

&lt;p&gt;We are trying to achieve a contract that does what business is expecting.&lt;/p&gt;

&lt;p&gt;It's also expected that all the dependencies of the micro-service regarding 3rd/internal parties APIs are clear on their purposes and which of their endpoints suits our needs.&lt;/p&gt;

&lt;p&gt;In our &lt;code&gt;capture&lt;/code&gt; endpoint we assume some generic response. But we could be calling x number of endpoints if needed before the &lt;code&gt;capture&lt;/code&gt; replies with anything.&lt;/p&gt;

&lt;p&gt;Anyways, the OpenAPI is defined as a yaml file with all the specifications.&lt;/p&gt;

&lt;p&gt;But if we have a few endpoints and a lot of responses, it might be useful to have separate files for each section of the Specification.&lt;/p&gt;

&lt;p&gt;Ultimately this will ease the burden of maintaining the specification.&lt;/p&gt;

&lt;h3&gt;
  
  
  Organising the contract structure
&lt;/h3&gt;

&lt;p&gt;Updating the above file structure.&lt;/p&gt;

&lt;pre&gt;
./images
├── capture.svg
./plantuml
├── capture.puml
&lt;b&gt;./open-api
├── components
│   ├── headers
│   │   └── x-correlation-id.yaml
│   ├── headers.yaml
│   ├── parameters
│   │   ├── authorization-id.yaml
│   │   └── x-correlation-id.yaml
│   ├── responses
│   │   ├── capture-200.yaml
│   │   └── capture-422.yaml
│   ├── responses.yaml
│   ├── schemas
│   │   ├── capture-200.yaml
│   │   ├── capture-422.yaml
│   │   └── capture.yaml
│   └── schemas.yaml
├── components.yaml
├── index.yaml
├── info.yaml
├── paths
│   └── capture.yaml
└── paths.yaml&lt;/b&gt;
&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;Instead of using the normal &lt;code&gt;'#/components/...'&lt;/code&gt;, ref is a relative link to the file, which after the compile step will be properly OAS "reffed".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Content of &lt;code&gt;./open-api/index.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;openapi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3.0.2&lt;/span&gt;
&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;capture&lt;/span&gt;
&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./info.yaml'&lt;/span&gt;
&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./paths.yaml'&lt;/span&gt;
&lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./components.yaml'&lt;/span&gt;
&lt;span class="na"&gt;security&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;X-Api-Key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Content of &lt;code&gt;./open-api/paths.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;/capture/{authorizationId}&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./paths/capture.yaml'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Content of &lt;code&gt;./open-api/paths/capture.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Capture an amount&lt;/span&gt;
&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;capture&lt;/span&gt;
&lt;span class="na"&gt;operationId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;capturePost&lt;/span&gt;
&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;../components/parameters/authorization-id.yaml'&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;../components/parameters/x-correlation-id.yaml'&lt;/span&gt;
&lt;span class="na"&gt;requestBody&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;../components/schemas/capture.yaml'&lt;/span&gt;
&lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;200'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;../components/responses/capture-200.yaml'&lt;/span&gt;
&lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;422'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;../components/responses/capture-422.yaml'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tooling for OAS
&lt;/h3&gt;

&lt;p&gt;We can use the package &lt;code&gt;swagger-cli&lt;/code&gt; for generating the compiled Specification file.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npm install swagger-cli&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;swagger-cli bundle -o open-api.yaml --type yaml open-api/index.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the full specification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;openapi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3.0.2&lt;/span&gt;
&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;capture&lt;/span&gt;
&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.0.0&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Process Transactions Micro-service&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Capture,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;void&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;refund&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;an&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;account.'&lt;/span&gt;
&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/capture/{authorizationId}'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Capture an amount&lt;/span&gt;
      &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;capture&lt;/span&gt;
      &lt;span class="na"&gt;operationId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;capturePost&lt;/span&gt;
      &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;authorizationId&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Authorization Id which allows to capture the locked funds&lt;/span&gt;
          &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;path&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;X-Correlation-Id&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Correlation Id to keep track of workflow&lt;/span&gt;
          &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;header&lt;/span&gt;
          &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
      &lt;span class="na"&gt;requestBody&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/capture'&lt;/span&gt;
      &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;200'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/responses/capture-200'&lt;/span&gt;
      &lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;422'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/responses/capture-422'&lt;/span&gt;
&lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;securitySchemes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;X-Api-Key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apiKey&lt;/span&gt;
      &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;header&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;X-Api-Key&lt;/span&gt;
  &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;capture-200&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Capture of funds has succedeed&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;X-Correlation-Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/headers/X-Correlation-Id'&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/capture-200'&lt;/span&gt;
    &lt;span class="na"&gt;capture-422&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Capture did not succeed&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;X-Correlation-Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/headers/X-Correlation-Id'&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/capture-422'&lt;/span&gt;
  &lt;span class="na"&gt;schemas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;capture&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
      &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;accountId&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;amount&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;currency&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;accountId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;number&lt;/span&gt;
          &lt;span class="na"&gt;example&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;9.99&lt;/span&gt;
        &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
          &lt;span class="na"&gt;example&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EUR&lt;/span&gt;
    &lt;span class="na"&gt;capture-200&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;transactionId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;The transaction id which will allow to refund&lt;/span&gt;
    &lt;span class="na"&gt;capture-422&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;boolean&lt;/span&gt;
          &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
          &lt;span class="na"&gt;example&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Conditions could not be met&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;X-Correlation-Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
&lt;span class="na"&gt;security&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;X-Api-Key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing against the API
&lt;/h2&gt;

&lt;p&gt;Now that we defined diagrams and the contract is settled, we are ready to implement it.&lt;/p&gt;

&lt;p&gt;Let's say you have a server up and running with all of the requirements in place.&lt;/p&gt;

&lt;p&gt;Wouldn't it be better to have a Postman collection based on the OAS instead of manually creating it?&lt;/p&gt;

&lt;h3&gt;
  
  
  Converting OpenAPI to Postman Collection
&lt;/h3&gt;

&lt;p&gt;We can use the package &lt;code&gt;openapi-to-postmanv2&lt;/code&gt; for generating the Postman collection.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npm install openapi-to-postmanv2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;openapi2postmanv2 -s open-api.yaml -o postman-collection.json -p&lt;/code&gt; it will generate the a Postman collection almost pre-filled.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Obvious you will need to fill the blanks such as the &lt;code&gt;X-Api-Key&lt;/code&gt; and alike.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;Building the Postman collection through the OpenAPI Specification will help find breaches in the development.&lt;/p&gt;

&lt;p&gt;Just keep in mind that changes to the contract often happen during development or even when all the functionality is being tested.&lt;/p&gt;

&lt;p&gt;Hope this workflow helps in any way possible to fasten and tighten the development.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What are your thoughts? Please share your experience and all constructive feedback is welcome!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Links
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Specifications&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.omg.org/spec/UML/" rel="noopener noreferrer"&gt;UML Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.openapis.org/" rel="noopener noreferrer"&gt;OpenAPI Specification&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tools&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://plantuml.com/" rel="noopener noreferrer"&gt;PlantUML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mermaidjs.github.io/" rel="noopener noreferrer"&gt;mermaidJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.getpostman.com/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://insomnia.rest/" rel="noopener noreferrer"&gt;Insomnia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman" rel="noopener noreferrer"&gt;Newman&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://editor.swagger.io/" rel="noopener noreferrer"&gt;Swagger Editor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://liveuml.com/" rel="noopener noreferrer"&gt;LiveUML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/markushedvall/node-plantuml" rel="noopener noreferrer"&gt;node-plantuml&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/APIDevTools/swagger-cli" rel="noopener noreferrer"&gt;swagger-cli&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/openapi-to-postman" rel="noopener noreferrer"&gt;openapi-to-postmanv2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>microservices</category>
      <category>design</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Modern monitoring</title>
      <dc:creator>João Guimarães</dc:creator>
      <pubDate>Tue, 20 Aug 2019 08:08:07 +0000</pubDate>
      <link>https://dev.to/jccguimaraes/modern-monitoring-1d49</link>
      <guid>https://dev.to/jccguimaraes/modern-monitoring-1d49</guid>
      <description>&lt;h1&gt;
  
  
  Table Of Contents
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Abstract&lt;/li&gt;
&lt;li&gt;The concept&lt;/li&gt;
&lt;li&gt;Monitoring&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Abstract &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;I want to share my experience when dealing with monitoring applications such as micro-services and/or lambdas and how too much monitoring (or lack of it) causes an impact in ways beyond just analysis or pretty dashboards.&lt;/p&gt;

&lt;p&gt;If you have another opinion on the concepts described here, I encourage you to provide constructive feedback so I too can learn with other people's ideas and thoughts.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Opinions are my own and not of my employer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  The concept &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Monitoring is the combination of logging and adding metrics, but usually, they are treated as separate areas of our applications when in fact they can both work together and we can take advantage of this union.&lt;/p&gt;

&lt;p&gt;Instead of logging everything (which is unhealthy) and add metrics for everything (which is also unhealthy), we can complement a metric that has triggered an alert with detailed logs. &lt;em&gt;This is modern monitoring!&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Monitoring &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Very briefly, &lt;em&gt;logs&lt;/em&gt; represent information that can't be grouped but they provide unique details about an event that happened, while &lt;em&gt;metrics&lt;/em&gt; represent information that can be grouped by events but don't provide unique details.&lt;/p&gt;

&lt;p&gt;Consider that an &lt;code&gt;HTTP&lt;/code&gt; request returned a &lt;code&gt;404&lt;/code&gt; status code. We can use a counter metric called &lt;code&gt;clientError&lt;/code&gt;, as an example, which will continue to increment whenever another &lt;code&gt;4xx&lt;/code&gt; error occurs. Detailed information about individual errors can be logged to provide additional information for troubleshooting purposes. You can correlate them by their timestamp.&lt;/p&gt;

&lt;p&gt;Consider that the above error was caused by the following &lt;code&gt;HTTP/1.1&lt;/code&gt; request to &lt;code&gt;my-service&lt;/code&gt; application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;GET&lt;/span&gt; &lt;span class="nn"&gt;/my-path?id=my-resource&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;www.my-host.com&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and its corresponding response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;404&lt;/span&gt; &lt;span class="ne"&gt;NOT FOUND&lt;/span&gt;
&lt;span class="na"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Wed, 17 Jun 2019 10:36:20 GMT&lt;/span&gt;
&lt;span class="na"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Apache/2.2.14 (Win32)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your application, after processing the request, logs something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"app"&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-service"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"xcid"&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uuid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"time"&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2019-07-17T10:36:19.000Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"host"&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"www.my-host.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-path"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"statusCode"&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"msg"&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"client error"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Would be a waste of resources as it does not provide any value to understand the reasons why it happened!&lt;/p&gt;

&lt;p&gt;Although the next log may give us data to understand why the event occurred, it leaks sensible data and should be avoided:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We &lt;strong&gt;SHOULD&lt;/strong&gt; only log information that will help identify &lt;strong&gt;why&lt;/strong&gt; a certain event occurs without exposing sensible data.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"app"&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-service"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"xcid"&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uuid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"time"&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2019-07-17T10:36:20.000Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"host"&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"www.my-host.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-path"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"statusCode"&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"msg"&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"client error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deleted"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sensibleKey1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sensibleValue1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sensibleKey2"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sensibleValue2"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The 3rd log entry example can provide valuable information to understand why this event occurred.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"app"&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-service"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"xcid"&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uuid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"time"&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2019-07-17T10:36:20.000Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"host"&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"www.my-host.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-path"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"statusCode"&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"msg"&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"'my-resource' does not exist"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This subtle difference allows you to investigate the reason why that resource was deleted without exposing sensible data.&lt;/p&gt;

&lt;p&gt;Bottom line:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The metric &lt;code&gt;clientError&lt;/code&gt; triggered an alarm for the event;&lt;/li&gt;
&lt;li&gt;The log entry provided a reason why it happened.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We now have all the information to troubleshoot this event outside the monitoring scope.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is a pretty simple example but it shows how we need to weight metrics and logs accordingly to the situation and business value.&lt;/p&gt;

&lt;p&gt;Logs should tell you why an event occurred, but not explain the specific reason it happened, or you'll risk exposing, once again, sensible data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is no need to have logs that won't serve any purpose, they'll just cost you or your company money.&lt;/p&gt;

&lt;p&gt;If your application is behind a High Availability application it most likely is backed-up by a load balancer / Auto Scaling Group of some sort or you are simply spinning up some containers yourself, your application &lt;strong&gt;SHOULD&lt;/strong&gt; log only exit codes that aren't expected.&lt;/p&gt;

&lt;p&gt;When your services are under heavy load, they will spin up more containers, and when that load drops, containers are going to be spin down. Logging those predictable shutdowns, again, will have no meaningful information.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AWS and/or Kubernetes set the exit code when a container has been ordered to shut down, allowing the application to read that code and log meaningful information.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Having predictable log objects can also help you manage and estimate the service daily capacity for your LMS - Log Management Service of choice. This is not the same described here.&lt;/p&gt;

&lt;p&gt;What should represent a metric?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Business value to dashboards;&lt;/li&gt;
&lt;li&gt;Information for triggering alerts (on its own or aggregated with other metrics).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some LMS can add dimensions/tags/labels to metrics which is great but can turn into a nightmare in terms of costs.&lt;/p&gt;

&lt;p&gt;A bad example of adding a dimension is the &lt;code&gt;hostname&lt;/code&gt;, instead, it &lt;strong&gt;SHOULD&lt;/strong&gt; be a part of the logs (if applied).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;region&lt;/code&gt; where your application is running is a good dimension (if applied) as it can provide insight on which regions some services have more load.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;At the end it's a trade-off between costs and business value.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Any unique combination of a metric with its dimensions represents a new time series, which will increase the amount of data that will be stored in your provider. Once again, this also increases the overall costs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A dimension &lt;strong&gt;MUST&lt;/strong&gt; have a &lt;em&gt;low cardinality&lt;/em&gt;. High cardinality means that the dimension will have many different values.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Conclusion &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;We should not jump into adding logs and metrics for everything. We are tempted to do this while developing to find issues and bugs but we will certainly leave them wandering around in production as well.&lt;/p&gt;

&lt;p&gt;This is not a topic to fire and forget. Keep them sane and most important, secure and that they provide the minimum information for proper troubleshooting outside the monitoring scope.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
