<?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: Mathias D</title>
    <description>The latest articles on DEV Community by Mathias D (@mathiasdpunkt).</description>
    <link>https://dev.to/mathiasdpunkt</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%2F4216%2Faa5ef744-f36b-47c8-813e-671b13fe91f2.jpg</url>
      <title>DEV Community: Mathias D</title>
      <link>https://dev.to/mathiasdpunkt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mathiasdpunkt"/>
    <language>en</language>
    <item>
      <title>Five reasons for writing a custom CDK Construct Library</title>
      <dc:creator>Mathias D</dc:creator>
      <pubDate>Mon, 22 Mar 2021 20:54:51 +0000</pubDate>
      <link>https://dev.to/mathiasdpunkt/five-reasons-for-writing-a-custom-cdk-construct-library-1pni</link>
      <guid>https://dev.to/mathiasdpunkt/five-reasons-for-writing-a-custom-cdk-construct-library-1pni</guid>
      <description>&lt;p&gt;When I started using AWS Lambda, my team used the &lt;a href="https://www.serverless.com"&gt;serverless framework&lt;/a&gt; to describe our AWS resources. This is easing things a lot compared to writing only plain CloudFormation templates. But still, there was a lot of CloudFormation to be written. This used to be nobody's favourite task. Then &lt;a href="https://aws.amazon.com/cdk/"&gt;CDK&lt;/a&gt; came to the rescue.&lt;/p&gt;

&lt;h2&gt;
  
  
  The general advantages of CDK
&lt;/h2&gt;

&lt;p&gt;Writing CloudFormation sucks. It is highly repetitive, lengthy, and slow. Code completion is really limited and I just cannot manage to remember the syntax of those intrinsic functions.&lt;/p&gt;

&lt;p&gt;So nobody needed to convince me when CDK came along. Finally, there is code completion, extraction of repetitive parts, and there are constructs. CDK &lt;a href="https://docs.aws.amazon.com/cdk/latest/guide/constructs.html"&gt;constructs&lt;/a&gt; are infrastructure building blocks for your application - they can represent a single CloudFormation resource or represent a higher-level component consisting of multiple resources. They bundle things that usually go together - like a Lambda Function with LogGroup and execution role. These constructs reduce the amount of code needed to describe a stack. So CDK does not mean describing CloudFormation resources in a programming language. It also provides an abstraction above CloudFormation resources.&lt;/p&gt;

&lt;p&gt;Also, CDK allows for easy connection between constructs. There is a method to grant read access to a DynamoDB table for a Lambda function. This is so much more convenient than CloudFormation.&lt;/p&gt;

&lt;p&gt;Yes, there are downsides, too. CloudFormation usually has no surprises when it comes to structure. There is not much freedom there, so CloudFormation templates are usually lengthy but still rather easy to read. The freedom of a higher-level programming language leaves much more room to structure things in different ways. So it usually takes a bit until I understand a CDK app that I did not write myself.&lt;/p&gt;

&lt;p&gt;But after all the benefits outweigh the downsides by far.&lt;/p&gt;

&lt;p&gt;By using your custom CDK construct library you can get even more advantages out of CDK. When I say custom CDK construct library I mean writing your own constructs that you package into a library and make them available in your organization.&lt;/p&gt;

&lt;p&gt;So let's look into what is in for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Suddenly conventions are your friend 🧐
&lt;/h2&gt;

&lt;p&gt;When you work in an organisation larger than just a few developers you will have conventions around AWS resources. Something like "Enable encryption at rest for your SQS queue!" or "Point-in-time recovery should be enabled for every DynamoDB table!". Usually, such conventions are documented in a guideline somewhere. You rely on the discipline of your developers that those conventions are actually applied. Maybe you even write some code that checks your resources regarding those conventions and raises alarms if the rules are violated. This is a little better. Now you can be sure that those conventions are applied - but only after they already have been deployed.&lt;/p&gt;

&lt;p&gt;I find it a little smarter if developers are incentivised to consider those conventions by making their lives easier. With CDK you can have your custom construct wrapping the DynamoDB Table construct which defaults some settings according to your conventions. Developers will like to use this because they have to worry about a few things less.&lt;/p&gt;

&lt;p&gt;Such convention constructs are a good start, since they are easy to write.&lt;/p&gt;

&lt;h2&gt;
  
  
  Declutter where possible 🧹
&lt;/h2&gt;

&lt;p&gt;Often there are standard ways of doing things in an organisation. Here are a few examples.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logs for Lambda functions have a retention of 14 days and are always shipped to ElasticSearch for central log aggregation&lt;/li&gt;
&lt;li&gt;Every REST API is using a subdomain of our corporate domain (requiring DNS Records and a certificate)&lt;/li&gt;
&lt;li&gt;For every Lambda function, we want an alarm when errors are logged&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Such standard cases result in a lot of code that is copied over and over again. Those are perfect candidates for custom constructs.&lt;/p&gt;

&lt;p&gt;So our custom Lambda function construct can create the Lambda function and make sure that the LogGroup is configured appropriately. We can also offer an &lt;a href="https://docs.aws.amazon.com/cdk/latest/guide/aspects.html"&gt;aspect&lt;/a&gt; that can be added to a stack to add MetricFilters and Alarms for error log entries in every Lambda LogGroup.&lt;/p&gt;

&lt;p&gt;In the end, we have saved a few lines of code in many projects, developers have to worry about fewer things, and we are making sure that best practices are applied.&lt;/p&gt;

&lt;h2&gt;
  
  
  Constants - Everything in one place 🧰
&lt;/h2&gt;

&lt;p&gt;Your CDK construct library can also be the go-to place for important constants. Usually, constants around the AWS accounts and shared resources are scattered around different pieces of documentation. So developers need to go to various places to look them up. Often such values are then hard-coded in the CloudFormation or the CDK configuration.&lt;/p&gt;

&lt;p&gt;We can add those constants to our custom CDK construct library. So they are easy to find and access. Also, they do not have to be copied into application code. Those constants can be ids of AWS accounts, the standard destinations for alarms, or the webhooks of important slack channels that you want to post to from your AWS infrastructure.&lt;/p&gt;

&lt;p&gt;With these constants, information moves closer to the place of use and thus less time is spent searching for this information in the documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Foster cross-team collaboration 🙌
&lt;/h2&gt;

&lt;p&gt;A CDK construct library can be something a developer community can share and care about together. This can foster collaboration across teams and can start important conversations about lessons learned and best practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deliver polyglot libraries from a single codebase
&lt;/h2&gt;

&lt;p&gt;You are working in a polyglot environment - also this is not an obstacle. It is possible to write your CDK construct library once in TypeScript and use jsii to deliver polyglot libraries from it (Go, Java, Python). Jsii is also used by the CDK project itself to deliver the different language bindings it offers.&lt;/p&gt;




&lt;p&gt;I hope you cannot wait now to create your own customer CDK construct library. Just head over to your favorite terminal and enter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk init lib - language=typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use &lt;a href="https://github.com/projen/projen/blob/main/API.md#class-awscdkconstructlibrary--"&gt;projen&lt;/a&gt; to jump into developing your custom construct library.&lt;/p&gt;

&lt;p&gt;Furthermore the CDK Workshop is a good start for starting to write your first own construct. It contains an &lt;a href="https://cdkworkshop.com/20-typescript/40-hit-counter.html"&gt;example&lt;/a&gt; for writing a construct.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cdk</category>
      <category>cloudformation</category>
    </item>
    <item>
      <title>How to enforce type-safety at the boundary of your code</title>
      <dc:creator>Mathias D</dc:creator>
      <pubDate>Tue, 16 Feb 2021 21:55:02 +0000</pubDate>
      <link>https://dev.to/mathiasdpunkt/how-to-enforce-type-safety-at-the-boundary-of-your-code-36kk</link>
      <guid>https://dev.to/mathiasdpunkt/how-to-enforce-type-safety-at-the-boundary-of-your-code-36kk</guid>
      <description>&lt;p&gt;I recently started digging more into TypeScript. The structural typing approach in TypeScript is interesting and often a little bit surprising for developers coming from languages with a reified, nominal type system like Kotlin and Java.&lt;/p&gt;

&lt;p&gt;I realised that it is very important to understand that types in TypeScript are completely erased at runtime.&lt;/p&gt;

&lt;p&gt;Let's look at the following code. We are receiving JSON input and want to parse this into an object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"id": "some"}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;maybeNoUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maybeNoUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 👇💥 TypeError: Cannot read property 'toLocaleLowerCase' of undefined&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maybeNoUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLocaleLowerCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Kotlin similar code would already fail while parsing the Json string into an object of type &lt;code&gt;User&lt;/code&gt;. But here the code happily executes and only fails with a &lt;code&gt;TypeError&lt;/code&gt; at the second log statement. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;as&lt;/code&gt; type assertion is basically telling the compiler to should shut up and that you know what you are doing. There is no checking performed - it has no runtime impact at all. It is not in the slightest similar to a type cast in e.g. Java. And because types are erased at runtime the type system cannot help us out here.&lt;/p&gt;

&lt;p&gt;What we did above looks OK at first sight and also the TypeScript compiler is satisfied with it. Not even ESLint complains. But this can still be really bad in a real-world code base. &lt;br&gt;
We are trusting that the Json is representing a User. If the input does not match our expectations we might get arbitrary problems in a totally different part of our code. Such errors will be tough to understand.&lt;/p&gt;

&lt;p&gt;So what should we do here? Exactly, let's get our hands dirty and write some good old validation code to make sure the user object is satisfying our expectations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"email": "some@test.com", "age":"some"}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parseUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;missing email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;age must be a number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// 👇💥 Error: age must be a number&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parseUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All right - this is much safer. But honestly - the code in &lt;code&gt;parseUser&lt;/code&gt; almost hurts. It is repetitive code that nobody likes to write. It is error prone and it is cumbersome to check every possible case. Even in our trivial case a complete implementation would need a lot more code than given in the example above. Also, everything we are checking in &lt;code&gt;parseUser&lt;/code&gt; is already expressed in our &lt;code&gt;User&lt;/code&gt; type. The validation logic is duplicating this. There has to be a better way. &lt;/p&gt;

&lt;p&gt;Fortunately, there is &lt;a href="https://github.com/colinhacks/zod"&gt;zod&lt;/a&gt; for the win.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Zod is a TypeScript-first schema declaration and validation library. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Zod lets you declare schemas describing your data structures. These schemas can then be used to parse unstructured data into data that conforms to the schema. Sticking to our example above this could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nonstrict&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;userSchema&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"email": "some@test.com", "age":"some"}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/* 👇💥 
[
  {
    code: 'invalid_type',
    expected: 'number',
    received: 'string',
    path: ['age'],
    message: 'Expected number, received string',
  },
]; */&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I really like the DSL for schema declaration. It is hardly more complex than defining a type in Typescript. And we can even use it to infer a type from it that we can use in our function signatures.  This way the usage of zod does not leak into our whole code base. The &lt;code&gt;nonstrict()&lt;/code&gt; option generates a schema that allows additional properties not defined in the schema. This is definitely a best-practice when parsing Json data.&lt;/p&gt;

&lt;p&gt;Zod also takes advantage of the structural typing characteristics of TypeScript. So you can derive similar types from a single schema. This can help e.g. when implementing a function to save a user. Such functions usually take an object, generate an id, save the object and return the object along with the id.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;v4&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;uuid&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uuid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userEntitySchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nonstrict&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userEntitySchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;omit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UserEntity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;userEntitySchema&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;userSchema&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"email": "some@test.com", "age":30}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saveUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;UserEntity&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userEntity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userEntity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;code&gt;omit&lt;/code&gt; we could just create a new schema out of the existing one. Also &lt;code&gt;pick&lt;/code&gt; exists to add to an existing schema. And again - we did not have to duplicate any knowledge about our types.&lt;/p&gt;

&lt;p&gt;I think this is really a neat tool that I recommend to use whenever potentially type-unsafe data is entering our code. Be it the Json input coming in via a REST invocation, or the result of a DynamoDB query. Zod has much more to offer then what I described here. So I can only encourage you to check out the excellent &lt;a href="https://github.com/colinhacks/zod/blob/master/README.md"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Further reading&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/colinhacks/zod"&gt;zod Github repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/colinhacks/designing-the-perfect-typescript-schema-validation-library-3335"&gt;Designing the perfect Typescript schema validation library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/"&gt;Parse, don’t validate&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>typescript</category>
      <category>node</category>
      <category>programming</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>How to get more out of Pull Request Reviews</title>
      <dc:creator>Mathias D</dc:creator>
      <pubDate>Wed, 22 Jan 2020 13:53:59 +0000</pubDate>
      <link>https://dev.to/mathiasdpunkt/you-can-get-more-out-of-pull-request-reviews-36c1</link>
      <guid>https://dev.to/mathiasdpunkt/you-can-get-more-out-of-pull-request-reviews-36c1</guid>
      <description>

&lt;p&gt;Pull request reviews are an essential tool to improve the quality of software. In a team working with or towards continuous deployment it is the last human quality gate on the way to production. And not only that, when done right, pull request reviews are also a great tool for knowledge sharing in a team. So we better get this right. Unfortunately, this is easier said than done.&lt;br&gt;
In this post we will look at some learnings about pull request reviews I collected in my daily work.&lt;/p&gt;

&lt;h2&gt;
  
  
  You are going too fast
&lt;/h2&gt;

&lt;p&gt;The authors of "Accelerate" propose to measure the deployment frequency of a team as one of the key metrics for a team's performance. At the same time they suggest "change failure rate" as another metric to balance out the first one. Going too fast will do more harm than good. This also applies to pull request reviews. A decent review takes time. Rushing reviews might increase throughput now but it will most likely introduce quality problems and slow you down in future. Also chances for knowledge sharing and sharing responsibility in a team will be missed. So a detailed review is most likely well spent time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trust, but verify
&lt;/h2&gt;

&lt;p&gt;First of all, trust between members is a really good thing. It is one of the pillars of successful teams. But as often in life, you can go too far. I have seen reviews for pull requests with boring and repetitive changes over dozens of files being approved in 2 minutes. What can possibly be wrong in such a simple change? The change was also boring for the author. So chances are that one or the other thing slipped through, better verify.&lt;br&gt;
I have observed that a lot of trust in the skills of your co-workers can lead to increasingly sloppy pull request reviews. Let's work against this reflex! You have smart colleagues - this is great - but everybody makes mistakes once in a while.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start showing love to your test code
&lt;/h2&gt;

&lt;p&gt;Most reviewers focus on the production code. This is understandable because this is where the bug could be hidden that might trigger that alert in the middle of the night. But still, we produce at least as much test code as production code. I have heard of projects containing three times more test code than production code. And also test code can become an unmaintainable mess. So we better show some love to our test code as well. A co-worker of mine has the habit to start having a look at the tests when doing pull request reviews. I think this is a great idea that is worth giving it a try.&lt;/p&gt;

&lt;h2&gt;
  
  
  Search for the missing bits
&lt;/h2&gt;

&lt;p&gt;This one is really hard to get right. When reviewing a pull request you can easily see what is included. But in a pull request review it is also very important to find things that are missing. According to the excellent post by Scott Nonnenberg about the &lt;a href="https://blog.scottnonnenberg.com/top-ten-pull-request-review-mistakes/" rel="noopener noreferrer"&gt;Top ten pull request review mistakes&lt;/a&gt; we should focus on the things that are not in the pull request but should be. Did the author forget to change a piece of code, are tests missing, or are edge cases not considered? So looking at a pull request is not enough. We also need to understand the code around it. We need to look at the broader picture, understand the change and the motivation behind it completely and actively ask ourselves the question: What is missing?&lt;br&gt;
I tend to look at bigger pull requests in the IDE to get the complete picture. This way I can not just look at the changes but also at the code that is around these changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attack the flaw, not the person
&lt;/h2&gt;

&lt;p&gt;Pull request reviews are a form of feedback and we should be careful about how to get our message across. Especially new members of the team might take pull request feedback personally and feel bad about getting things wrong. This must not happen. It is about shipping code that is in good shape, it is about learning and growing together, about sharing responsibility and not about blaming or showing superiority. So here are a few tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;find an encouraging tone (full sentences do not hurt)&lt;/li&gt;
&lt;li&gt;offer help, be respectful&lt;/li&gt;
&lt;li&gt;do not just look for the flaws, also praise the parts that you like&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I can recommend the talk &lt;a href="https://www.youtube.com/watch?v=ly86Wq_E18o" rel="noopener noreferrer"&gt;Amazing Code Reviews: Creating a Superhero Collective&lt;/a&gt; from Alejandro Lujan for more information about this aspect of code reviews.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automate the nitpicking
&lt;/h2&gt;

&lt;p&gt;Many of us appreciate a consistently formatted code base. But we should not waste our time checking indentation or ordering of imports in a pull request review. Let a linting tool do this boring work and focus on the harder parts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unblock
&lt;/h2&gt;

&lt;p&gt;It is always a tough decision if we should focus on the current piece of work we are trying to get done or if it would be advisable to switch contexts and review the pull request a co-worker just created. In general we should remind ourselves that a pending pull request is probably blocking a co-worker from getting work done. Also postponing a pull request for a longer time will result in additional effort in resolving conflicts. So a timely review is very valuable. But on the other side the flood of pull request that a bigger team produces can be overwhelming and it can also be OK to finish up the current piece of work before diving into the pull request reviews.&lt;/p&gt;




&lt;p&gt;There are many aspects to pull request reviews and the ones mentioned above are just a few of those. It becomes apparent that a good pull request review culture is hard to achieve. I hope the thoughts above can be a trigger to revisit this important tool and get more out of your pull request reviews. It is worth it.&lt;/p&gt;

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