<?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: Txus</title>
    <description>The latest articles on DEV Community by Txus (@txus).</description>
    <link>https://dev.to/txus</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%2F215641%2Ffcb266b3-6077-43e4-8160-3c094465a969.jpeg</url>
      <title>DEV Community: Txus</title>
      <link>https://dev.to/txus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/txus"/>
    <language>en</language>
    <item>
      <title>Becoming a logician with TypeScript</title>
      <dc:creator>Txus</dc:creator>
      <pubDate>Tue, 17 Sep 2019 08:34:26 +0000</pubDate>
      <link>https://dev.to/codegram/becoming-a-logician-with-typescript-575i</link>
      <guid>https://dev.to/codegram/becoming-a-logician-with-typescript-575i</guid>
      <description>&lt;p&gt;Logic and computation are two sides of the same coin —this is called the &lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/Curry%E2%80%93Howard_correspondence"&gt;Curry-Howard correspondence&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;



&lt;h2&gt;
  
  
  Eh?
&lt;/h2&gt;

&lt;p&gt;Let's explore what this means in a short tour, by the end of which I aim to convince you that, as a developer writing TypeScript, &lt;strong&gt;you are writing propositions and proofs&lt;/strong&gt; for a living!&lt;/p&gt;

&lt;p&gt;Throughout recent history, computer scientists and logicians seem to keep discovering the same concepts independently —each new concept discovered in one field seems to neatly map to one in the other.&lt;/p&gt;

&lt;p&gt;This duality has been a great driver of innovation in practical type systems — for example, the discovery of new formal logics such as &lt;a href="https://homepages.inf.ed.ac.uk/wadler/papers/lineartaste/lineartaste-revised.pdf"&gt;linear logic&lt;/a&gt; led to Rust's famous borrow checker.&lt;/p&gt;

&lt;p&gt;Let's use TypeScript to explore how everyday types, our bread and butter, acquire a new meaning when looked at from... the other side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proving the obvious
&lt;/h2&gt;

&lt;p&gt;Let's look at possibly the simplest type we use in our everyday job: &lt;code&gt;number&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;n&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="mi"&gt;4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This code typechecks —it has a type and a value that matches that type. But how does this have anything to do with formal logic?&lt;/p&gt;

&lt;p&gt;We can look at the type &lt;code&gt;number&lt;/code&gt; as a logical &lt;strong&gt;proposition&lt;/strong&gt;, which in plain language we could express as &lt;strong&gt;there exists a number&lt;/strong&gt;. Pretty obvious right? But TypeScript won't believe us &lt;em&gt;until we prove it&lt;/em&gt;. And that proof is &lt;em&gt;the value 4&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Let's re-read the above code as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The type &lt;code&gt;number&lt;/code&gt; is the &lt;strong&gt;proposition&lt;/strong&gt; or claim that &lt;em&gt;there exists a number&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;The value &lt;code&gt;4&lt;/code&gt; is a valid &lt;strong&gt;proof&lt;/strong&gt; of that proposition or claim&lt;/li&gt;
&lt;li&gt;TypeScript is convinced with our proof, so our program type-checks!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  This, and that too
&lt;/h2&gt;

&lt;p&gt;If simple types are claims that values of that type simply exist... what are tuples?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nameAndAge&lt;/span&gt;&lt;span class="p"&gt;:&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="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Curry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;119&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Turns out tuples let us have our cake and eat it too, that is, do conjunction! Again, let's put our logician hats:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The tuple type &lt;code&gt;[string, number]&lt;/code&gt; is the &lt;strong&gt;proposition&lt;/strong&gt; that &lt;em&gt;there exists a string AND there exists a number&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;The value &lt;code&gt;['Curry', 119]&lt;/code&gt; is a valid &lt;strong&gt;proof&lt;/strong&gt; of that proposition&lt;/li&gt;
&lt;li&gt;That is convincing enough for TypeScript, and so our program type-checks!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What about or?
&lt;/h2&gt;

&lt;p&gt;Similarily, union types let us &lt;em&gt;or&lt;/em&gt; propositions together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nameOrAge&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="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Curry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The union type &lt;code&gt;string | number&lt;/code&gt; is the &lt;strong&gt;proposition&lt;/strong&gt; that &lt;em&gt;there exists a string OR a number&lt;/em&gt; (a non-exclusive &lt;code&gt;or&lt;/code&gt; like we're used to in programming)&lt;/li&gt;
&lt;li&gt;The value &lt;code&gt;'Curry'&lt;/code&gt; is a valid &lt;strong&gt;proof&lt;/strong&gt; of that proposition&lt;/li&gt;
&lt;li&gt;TypeScript says sure, type-checked!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  If this, then that
&lt;/h2&gt;

&lt;p&gt;Probably the most interesting kind of TypeScript types from the point of view of logic are... function types!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&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;b&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="kr"&gt;number&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;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Functions represent &lt;strong&gt;logical implication&lt;/strong&gt; (if &lt;code&gt;x&lt;/code&gt;, then &lt;code&gt;y&lt;/code&gt;). Let's see how:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The function type &lt;code&gt;(a: number, b: number): number&lt;/code&gt; is the &lt;strong&gt;proposition&lt;/strong&gt; that &lt;em&gt;if there exists a number &lt;code&gt;a&lt;/code&gt; and a number &lt;code&gt;b&lt;/code&gt;, there also exists a third number&lt;/em&gt; (the return value).&lt;/li&gt;
&lt;li&gt;The implementation &lt;code&gt;return a + b&lt;/code&gt; is a valid &lt;strong&gt;proof&lt;/strong&gt; that you can effectively make a number given these two numbers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Less is more
&lt;/h3&gt;

&lt;p&gt;As you've probably noticed, just as there are many numbers of type &lt;code&gt;number&lt;/code&gt;, there are many implementations of the function &lt;code&gt;(a: number, b: number): number&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;One possible implementation could always return &lt;code&gt;42&lt;/code&gt;, and it would still type-check, because you were able to produce a &lt;code&gt;number&lt;/code&gt; given &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;, even if you didn't use them.&lt;/p&gt;

&lt;p&gt;That is why, the more expressive a type system is, the more you can &lt;em&gt;constrain types&lt;/em&gt; (propositions), so that there are &lt;em&gt;fewer valid implementations&lt;/em&gt; (proofs) — and so that the type-checker will reject more invalid ones!&lt;/p&gt;

&lt;h2&gt;
  
  
  Generalizing with... generics
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;All generalizations are dangerous, even this one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Alexandre Dumas-fils&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;How do generic types come into play? What do they mean in logic? They are a way to generalize claims, so that we don't have to concern ourselves with unnecessary detail.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In formal logic, they are akin to &lt;em&gt;universal quantification&lt;/em&gt; of propositions (claiming that a proposition holds for all things, for every case). Let's look at it from the point of view of TypeScript:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The function type &lt;code&gt;(array: Array&amp;lt;A&amp;gt;): number&lt;/code&gt; is the &lt;strong&gt;proposition&lt;/strong&gt; that &lt;em&gt;for any type &lt;code&gt;A&lt;/code&gt;, if there exists an array of &lt;code&gt;A&lt;/code&gt;s, there also exists a number&lt;/em&gt; (the return value, its length).&lt;/li&gt;
&lt;li&gt;The implementation &lt;code&gt;array.length&lt;/code&gt; is a valid &lt;strong&gt;proof&lt;/strong&gt; that you can effectively make a number given an array of absolutely any type.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Staring at the abyss: never say &lt;code&gt;never&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;In any cool formal logic, there should be a way to swear. TypeScript has the &lt;code&gt;never&lt;/code&gt; type for that! Let's look at how it's used in practice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;goOnForever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&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;never&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;while&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="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;I never end!&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The type &lt;code&gt;never&lt;/code&gt; is also known as the bottom type, and it has &lt;strong&gt;no values&lt;/strong&gt;. That means we can &lt;strong&gt;never return anything&lt;/strong&gt; from this function (and I mean NOTHING, not even &lt;code&gt;undefined&lt;/code&gt; or &lt;code&gt;null&lt;/code&gt;). In plain English, I like to translate it as the proposition &lt;strong&gt;we are screwed&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The function type &lt;code&gt;(a: number): never&lt;/code&gt; is the &lt;strong&gt;proposition&lt;/strong&gt; that &lt;em&gt;if there exists a number &lt;code&gt;a&lt;/code&gt;, we're screwed&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;The implementation never returns any value, and so no further reasoning can be done. We're screwed. TypeScript happily type-checks, because we did fulfill our promise: that we'll never return anything at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Promising the moon
&lt;/h2&gt;

&lt;p&gt;Lastly, let's look at an impossible type (proposition), and try to implement (prove) it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;arbitrary&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;A&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What? We are claiming that &lt;em&gt;for any type A, we can come up with a value of that type&lt;/em&gt;. Over-confident much? How are you going to implement that function so that you can create a value of type &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;Record&amp;lt;string, Password&amp;gt;&lt;/code&gt;, and &lt;code&gt;UserPreferencesFactory&lt;/code&gt; and whatever else I throw at this function as type &lt;code&gt;A&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;This function is surely impossible to implement... in a sound type system. But lo and behold, this type-checks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;arbitrary&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;A&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Aha! Turns out TypeScript is not sound —and neither are most modern practical type systems. That's not necessarily a bad thing, but it offers us a major way to screw up our programs. Be careful!&lt;/p&gt;

&lt;p&gt;Ambrose Bonnaire-Sergeant wrote an &lt;a href="https://blog.ambrosebs.com/2018/04/07/unsoundness-in-untyped-types.html"&gt;insightful piece&lt;/a&gt; about why unsoundness in modern type systems might not be a bad thing.&lt;/p&gt;

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

&lt;p&gt;If you enjoyed this post and want to learn more about these ideas, I recommend you read Philip Wadler's paper &lt;a href="https://homepages.inf.ed.ac.uk/wadler/papers/propositions-as-types/propositions-as-types.pdf"&gt;Propositions as Types&lt;/a&gt;. It's very well-written, witty and understandable even by non-mathy types like me.&lt;/p&gt;

&lt;p&gt;I also gave a few talks about the topic, and the potential of expressive type systems to make our programs safer (and thus, our world, increasingly dependant on those programs). Watch it &lt;a href="https://vimeo.com/191131741"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now I shall let you go get back to your propositions and proofs, I mean, your TypeScript project.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Cover photo by Benjamin Lizardo on &lt;a href="https://unsplash.com/photos/IZsbWBZ08cs"&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>typetheory</category>
      <category>logic</category>
    </item>
    <item>
      <title>Infrastructure as code with Pulumi</title>
      <dc:creator>Txus</dc:creator>
      <pubDate>Mon, 19 Aug 2019 13:53:13 +0000</pubDate>
      <link>https://dev.to/codegram/infrastructure-as-code-with-pulumi-4fbm</link>
      <guid>https://dev.to/codegram/infrastructure-as-code-with-pulumi-4fbm</guid>
      <description>&lt;p&gt;When it comes to managing our infrastructure, as developers we often face a double standard. Our code is version-controlled, subject to code reviews, checked periodically by test harnesses. We don't risk it.&lt;/p&gt;

&lt;p&gt;However, the infrastructure running our code, often the most critical part of our production systems, is treated differently. Log onto your AWS account, a few clicks, provision a machine. With the advent of Docker, at least environments have become more reproducible, but still too many of us spend their days clicking around with their cloud superuser account to terraform the world.&lt;/p&gt;

&lt;h2&gt;
  
  
  Declarative DSLs
&lt;/h2&gt;

&lt;p&gt;Speaking of which, there is... well, &lt;a href="https://www.terraform.io"&gt;Terraform&lt;/a&gt;! And other solutions too. The notion of &lt;em&gt;Infrastructure As Code&lt;/em&gt; is just starting to become the new default in the DevOps mindset. Declaratively defining your infrastructure, running some basic health checks and having everything version-controlled is a huge step forward.&lt;/p&gt;

&lt;p&gt;Declarative DSLs are an improvement, but we can do better. In our experience at Codegram, often you can spend 80% of your time figuring out the right incantation of your cloud provider's module, with very little help from tooling. That means the debugging cycle is painfully slow, and often very frustrating. Even more so in a serverless context, where most of the code is infrastructure glue --queues, storage buckets, and lambdas all need to talk to each other in just the right ways, with the right ACL permissions.&lt;/p&gt;

&lt;p&gt;Pulumi was built to leverage the power of general-purpose programming languages to solve these very shortcomings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter Pulumi
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: &lt;em&gt;Codegram is not affiliated with pulumi.com in any way. None of the benefits detailed in this post require a subscription to pulumi.com --you can just use the open-source library.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/pulumi/pulumi"&gt;Pulumi&lt;/a&gt; is an open-source library that lets you use a general-purpose programming language to build your infrastructure on your cloud provider of choice. At Codegram we usually choose TypeScript as our language for this task.&lt;/p&gt;

&lt;p&gt;As an example, here's all the code it takes to create an S3 bucket and spin up an AWS Lambda that triggers on every document uploaded to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;aws&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@pulumi/aws&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;docsBucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;docs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;docsBucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onObjectCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;docsHandler&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="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;for&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;rec&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Records&lt;/span&gt; &lt;span class="o"&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;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="s2"&gt;`Hello from Lambda -- got an S3 Object: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;rec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&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="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&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="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;docsBucketName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;docsBucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;All this glue code is type-checked by the Typescript compiler --from the records inside the S3 event, to the properties of the created S3 Bucket should be want to inspect them. And it goes way beyond serverless --whether you're deploying to Kubernetes, or plain Docker containers, you're good to go.&lt;/p&gt;

&lt;p&gt;In my opinion, the advantages of this approach go well beyond mere convenience. Read on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extensibility via Terraform providers
&lt;/h2&gt;

&lt;p&gt;Even though Pulumi doesn't depend on Terraform, The Pulumi CLI often leverages Terraform providers, and there is nice tooling to generate a Pulumi library from an existing Terraform provider. In our case, this was tremendously useful as we needed to manage DNSs with DNSimple through Pulumi. Even though it was my first time using the code generation tool, it was only an hour or two until I had the &lt;a href="//github.com/pulumi/pulumi-dnsimple"&gt;DNSimple integration&lt;/a&gt; working.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repeatable environments
&lt;/h2&gt;

&lt;p&gt;When you keep all your infrastructure alongside your code, spinning up a staging environment, or a test environment in a different cloud region, is trivial. We find that Pulumi helps us bring the gap between starting &lt;em&gt;testing out&lt;/em&gt; a piece of code and having a deployed, repeatable environment provisioned from our Continuous Deployment pipeline.&lt;/p&gt;

&lt;p&gt;For an agency like us, this becomes even more critical --often, projects start out in our cloud accounts, only to then be moved over to the client's --without the certainty that environments are completely repeatable and nothing is left to point and click interfaces, it would be a daunting task to ensure a smooth handover (and believe me, it used to be).&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoiding cloud vendor lock-in
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.pulumi.com/docs/reference/pkg/nodejs/pulumi/cloud/"&gt;pulumi.cloud&lt;/a&gt; right now implements a lot of the basic concepts of a cloud service, in a cloud-agnostic way.&lt;/p&gt;

&lt;p&gt;This lets you abstract a lot of the cloud-specific tools to facilitate deploying a multi-cloud project. However, wherever the current APIs can't reach, it's just code -- you can leverage abstraction to avoid locking your infrastructure to a particular cloud vendor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serverless and magic functions
&lt;/h2&gt;

&lt;p&gt;Pulumi has the concept of a magic function. It's a closure that will be packaged into a Lambda or cloud function, and it can reference elements of the infrastructure. These elements are resolved at provisioning time, so they are not dynamic, even though they are as flexible as if they were.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;aws&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;@pulumi/aws&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inputBucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&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;outputBucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;output&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;onObjectCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for&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;rec&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Records&lt;/span&gt; &lt;span class="o"&gt;||&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;processed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;processFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&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="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;uploadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outputBucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;processed&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this example, every time a file is uploaded to &lt;code&gt;inputBucket&lt;/code&gt;, we call a Lambda that processes the file and uploads it to another bucket. The closure we use to define the lambda closes upon &lt;code&gt;outputBucket.bucketName&lt;/code&gt; and calls &lt;code&gt;get()&lt;/code&gt; on it. This code, at provisioning time, will be compiled to a Lambda that will contain the literal name of the output bucket, statically.&lt;/p&gt;

&lt;p&gt;We get all the benefit of seemingly dynamic references between elements of our infrastructure, without the hassle of configuration management --misconfigured environment variables and so on. These references are checked at &lt;em&gt;compile time&lt;/em&gt;, before provisioning time, and obviously way before runtime.&lt;/p&gt;

&lt;p&gt;Magic functions help building the kind of glue code that is so tedious to write in serverless, seamlessly and with the power of a full programming language and tooling at your disposal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encoding best practices
&lt;/h2&gt;

&lt;p&gt;When it comes to managing infrastructure as a team, standardizing best practices becomes essential. Which settings do we use for storage buckets? Do we always use queues to decouple production and consumption? What durability settings are good defaults?&lt;/p&gt;

&lt;p&gt;By abstracting common infrastructure patterns in our own company library, these questions are brought into the team, and answered in the form of Pull Requests, code reviews, and technical discussions around real, tangible code. This way we move away from the one person who &lt;em&gt;knows how things are done around here&lt;/em&gt;, to version controlled best practices owned by the whole team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Granular security by default
&lt;/h2&gt;

&lt;p&gt;In traditional infrastructure management, people usually default to creating a &lt;em&gt;superuser&lt;/em&gt; first, and &lt;em&gt;worry about tightening permissions later&lt;/em&gt;, when all the parts are defined and stable. Does it sound familiar?&lt;/p&gt;

&lt;p&gt;To avoid that, having infrastructure patterns in code means you can abstract granular permissions around resources. Whenever you create a queue, the code that does that can make sure that only a specific storage bucket can publish events to it, or that only a specific machine or lambda can read from it.&lt;/p&gt;

&lt;p&gt;Once it's in the library, its &lt;em&gt;users&lt;/em&gt; (team members) never have to worry about loose permissions again. Write once, worry never again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus points: type safety
&lt;/h2&gt;

&lt;p&gt;At Codegram, TypeScript is our language of choice to manage infrastructure. The myriad of options that each cloud provider exposes in their wide range of offerings, and the fact that these change often, makes compiler help invaluable.&lt;/p&gt;

&lt;p&gt;The reason is, most of the parameter validation in cloud providers is done at actual provisioning time of the particular resource, which means, for N resources, it can easily degenerate into a really long feedback loop.&lt;/p&gt;

&lt;p&gt;By having most of the parameter validation at compile time, you don't even need to run the code to make sure it matches. Plus, you get a lot of help from your tooling in terms of auto-completion.&lt;/p&gt;

&lt;p&gt;On top of that, TypeScript's type system is powerful enough to allow parametric polymorphism, which helps greatly in abstracting away common patterns, and helps a lot in the way of multi-cloud abstractions.&lt;/p&gt;

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

&lt;p&gt;Managing infrastructure used to be a tedious task that few people enjoyed doing. Since we started using Pulumi, it's fused with the process of developing a project from start to end, and it's given us extra confidence in the portability and repeatability of our production environments.&lt;/p&gt;

&lt;p&gt;And now, go forth and terraform the world! Pun intended.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Cover photo by Ricardo Gómez Ángel on &lt;a href="https://unsplash.com/photos/PhrneXLSYis"&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>pulumi</category>
    </item>
  </channel>
</rss>
