<feed xml:lang="en">
  <title>rslabbert.com</title>
  <link rel="self" type="application/atom+xml" href="https://rslabbert.com/atom.xml"></link>
  <link rel="alternate" type="text/html" href="https://rslabbert.com"></link>
  <generator uri="https://zine-ssg.io">Zine</generator>
  <updated>2026-07-24T00:16:57+00:00</updated>
  <id>https://rslabbert.com/atom.xml</id>
  
    <entry xml:lang="en">
      <title>Technological materialism</title>
      <published>2021-08-17T00:00:00+00:00</published>
      <updated>2021-08-17T00:00:00+00:00</updated>
      <link rel="alternate" type="text/html" href="https://rslabbert.com/blog/historical_materialism_in_technology/"></link>
      <id>https://rslabbert.com/blog/historical_materialism_in_technology/</id>
      <content type="html" xml:base="https://rslabbert.com/blog/historical_materialism_in_technology/">&lt;p&gt;One of the core traits of a good technologist is the ability to understand technology not just in terms of code, but also in terms of history: how it came to be, the people that created it, and what influenced them (the companies they worked for, the dominant languages, etc.). To &lt;del&gt;steal&lt;/del&gt; borrow terminology from another domain:&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Historical_materialism&quot;&gt;Historical materialism&lt;/a&gt; is—incredibly roughly—a method for understanding the development of human society and history through the lens of material circumstances as opposed to individuals and ideas. That is to say, we can examine society and how it has progressed in terms of the material realities of its productive forces and the relation of people to these productive forces.&lt;/p&gt;&lt;p&gt;Consider a technology such as &lt;a href=&quot;https://delta.io/&quot;&gt;Delta Lake&lt;/a&gt;. To fully understand it, we must consider a few elements:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Its lineage and the forces of the previous generations that shaped it: created by Databricks, which was founded on Spark, which can be traced to Hadoop/MapReduce at Google, which favours horizontally scaling on commodity hardware, and so-on. Consider also:&lt;ul&gt;&lt;li&gt;Parquet as an influence on highly-performant file formats, and Orc as an influence on file formats supporting transactional operations;&lt;/li&gt;&lt;li&gt;Hive and Iceberg as examples of metadata storage at scale; and&lt;/li&gt;&lt;li&gt;Arrow as a data interoperabiltiy format.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;The productive forces that created it and influenced it: heavily utilises Scala similar to most of the Spark ecosystem, which is heavily influenced by Java in the Hadoop ecosystem.&lt;/li&gt;&lt;li&gt;The relation of the technology to the companies (capital) owning it: Delta Lake is a component of Databricks built to fit their product (and potentially others).&lt;/li&gt;&lt;li&gt;The superstructure or culture of the developers and the company: we can ask why Delta Lake is open-source, and what incentives does Databricks have for it.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The core argument to understand here is that technology does not develop by accident or in a vacuum, there are many forces that influence it and cause it to take shape. With this we can inform our choices, building a nuanced perspective on a technology that might not be easy understand otherwise.&lt;/p&gt;&lt;p&gt;For example, we can shortcut a lot of the Rust vs Go arguments that came out in the early days of these languages to the following:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Go came out of Google which predominantly writes server-side code in C++, Java, and Python. We can see how Go is an attempt to:&lt;ul&gt;&lt;li&gt;Mesh elements from these languages, such as the static compilation of C++, and the garbage collector of Java;&lt;/li&gt;&lt;li&gt;Avoid mistakes such as slow compilation (C++), and complex dependency management (Python); and&lt;/li&gt;&lt;li&gt;Subvert some second-order effects such as ease of use for a large employee base compared to C++.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Rust (of a certain time) came out of a predominantly open source culture which primarily worked with C++ and ML. While it went through many iterations, the Rust we have today is an attempt to bring rigour and correctness to the systems world, trying to blend C++‘s low(er)-level, structural elements from ML (error monads and modules), low-cost abstractions from languages like Haskell to match C’s performance. We can also see how the focus on crafting a systems language—directed by efforts such as &lt;a href=&quot;https://servo.org/&quot;&gt;Servo&lt;/a&gt;—gave us a very specific kind of language.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The “which language to choose” argument becomes easy when looking through this lens: If you’re looking to build low-latency user-facing software with a strong focus on security and robustness, preference Rust. If you’re looking to pick a standardised language for a medium-to-large company that is productive to use and deploy, preference Go. That’s not to say you can’t use either of these languages for either of these things, but that they were designed in fairly specific ways to address specific concerns.&lt;/p&gt;&lt;p&gt;Both of these languages also show how development continues as more varied use-cases and users get involved, for example, Go transitioning to modules instead of GOPATH as users outside of monorepos need to take advantage of it, and Rust’s development of async/await and Tokio to simplify concurrent programming.&lt;/p&gt;&lt;p&gt;Going forward, critically examine the technology you use not just from a purely technical lens, but also from a historical and cultural one. Who created it, why did they create it, how concentrated is the ownership of it. Doing this will start to reveal patterns in the technological world that gives you more insight into decisions, and provide you with better heuristics for evaluation.&lt;/p&gt;</content>
    </entry>
  
    <entry xml:lang="en">
      <title>Pulling strings</title>
      <published>2021-08-09T00:00:00+00:00</published>
      <updated>2021-08-09T00:00:00+00:00</updated>
      <link rel="alternate" type="text/html" href="https://rslabbert.com/blog/pulling_strings/"></link>
      <id>https://rslabbert.com/blog/pulling_strings/</id>
      <content type="html" xml:base="https://rslabbert.com/blog/pulling_strings/">&lt;p&gt;We can think of “goals”, not as targets to hit in of themselves, but aspirational projects, where the constituent steps taken towards this goal as worth doing in of themselves. In essence, “goals” become a proxy for all of the practices we need to make achieve them.&lt;/p&gt;&lt;p&gt;Consider the goal to “deploy code to production mutliple times per day” which requires:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Comprehensive testing so we’re sure the change we’re deploying has a low chance of failure&lt;/li&gt;&lt;li&gt;Monitoring and error logging so that we know if a deployment is causing issues (either direct errors or performance regressions)&lt;/li&gt;&lt;li&gt;An automated deployment process, because it’s unrealistic to spend multiple hours a day deploying software&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Looking at lofty goals through this lens can help us make sense of the initial discomfort we might feel. If we understand that the reason we feel uncomfortable is because there are foundations missing, we need to identify what’s lacking before moving on. Even if we don’t ever end up hitting our goal, we’re most likely still in a better place because of all the incremental steps we’ve taken along the way.&lt;/p&gt;</content>
    </entry>
  
    <entry xml:lang="en">
      <title>Complex solutions require complex configuration or strong convention</title>
      <published>2021-06-21T00:00:00+00:00</published>
      <updated>2021-06-21T00:00:00+00:00</updated>
      <link rel="alternate" type="text/html" href="https://rslabbert.com/blog/complex_solutions_require_complex_configuration_or_strong_convention/"></link>
      <id>https://rslabbert.com/blog/complex_solutions_require_complex_configuration_or_strong_convention/</id>
      <content type="html" xml:base="https://rslabbert.com/blog/complex_solutions_require_complex_configuration_or_strong_convention/">&lt;p&gt;One of the observable phenomena in engineering is that as a system becomes more complex, using it or realising value from it requires the use of complex configuration, or strong convention to reduce complexity. Understanding the implications of this idea allows us to a) design complex systems with usability in mind, and b) critique some of the software marketing in the wild.&lt;/p&gt;&lt;p&gt;For the purposes of this post, I want to explore a few examples where we can observe this idea. To start us off, consider a car. A car is a fairly complex system that has been reduced (from the perspective of the driver) down to a set of simple inputs. This means the car forces a strong convention. In other words, your ability to change how the car operates as a driver is fairly limited, instead, you are required to follow the way the designer intended.&lt;/p&gt;&lt;p&gt;In keeping with the theme of cars, we can expand this view to traffic as a whole, which also relies heavily on strong convention. On a freeway/motorway/highway/caraway, you are able to “configure” your driving by changing lanes or taking an exit (weak configuration), and in turn, you know everyone else will follow the same set of basic rules (strong convention). These two examples help demonstrate one of the implications of this hypothesis, which is that if your audience is large and untrained, stronger convention tends to lead to better usage of the system.&lt;/p&gt;&lt;p&gt;Contrast our examples of cars to air traffic. I’m not a pilot (I hawk examples), but my understanding is that aeroplanes (and air traffic in general) have a lot of configuration options. Some of this is inherent in the problem space (an entire additional dimension of space), but a lot of it is also to allow skilled operators to more effectively utilise the system. Consider now how auto-pilot changes this equation. Can a non-skilled operator use an auto-pilot to fly a plane? Maybe you’ll be the &lt;a href=&quot;https://en.wikipedia.org/wiki/Talk-down_aircraft_landing&quot;&gt;first to find out&lt;/a&gt;. At first glance, it seems that auto-pilot allows us to change the system between configuration and convention, but on further inspection, we realise that it is just another state of configuration. The rule of thumb we can use here is “Do I need a full understanding of the configuration of the system to ensure the convention is doing the right thing?”. This question is also immensely valuable as a litmus test in software engineering.&lt;/p&gt;&lt;p&gt;To round out our example section I want to touch on two more complex configuration systems which are hopefully instructive. Firstly, an Enterprise resource planning (&lt;abbr title=&quot;Enterprise resource planning&quot;&gt;ERP&lt;/abbr&gt;) (think SAP). The reason ERP implementations tend to have enormous price-tags is generally that they require large amounts of complex configuration to be fit for purpose. The reason, also, why most ERP projects fail, is because the number of people—on both the vendor and customer side—involved in these implementations who truly understand this complexity is low, leading to under-scoped timelines and a tendency to fail to predict problems.&lt;/p&gt;&lt;p&gt;Our final example is probably the quintessential example of a complex system requiring complex configuration to realise value: general purpose programming languages. To realise value for a system built from scratch in a programming language generally requires a full understanding of the code written in the language (the configuration). I point out this extreme because it shows us that configuration complexity is a spectrum, and more importantly, that any configuration that smells like coding probably sits further on the complexity spectrum than you might realise at first glance.&lt;/p&gt;&lt;p&gt;Now for our next section, you guessed it: more examples. This time, however, we’re looking at examples of systems or software where the actual configuration/convention required to use the system is obscured by marketing. The two examples are machine learning, and complex business software (there’s a third example that combines these two that I’m not brave enough to talk about).&lt;/p&gt;&lt;p&gt;Machine learning falls into a great space where it &lt;em&gt;can&lt;/em&gt; be incredibly useful for &lt;em&gt;certain&lt;/em&gt; problems, given the right level of &lt;em&gt;complex configuration&lt;/em&gt;, but most of the marketing for companies that make money selling machine learning don’t like to point out these caveats. There is only one world in which machine learning can work for you without you having to personally configure it to a tee, and that’s the world in which that configuration has been done for you and you have to use the software on its own terms. That is why the most successful machine learning solutions right now tend to be tools such as OCR or speech detection because they are able to force very specific ways of interacting with the system. Contrast this to tools that promise to take doctor’s notes and automatically extract patient information from them. This forces the tool to operate based on your conventions, which means you will have to spend time configuring it.&lt;/p&gt;&lt;p&gt;Finally, business systems tend to fall into this trap frequently (true for both vendors selling/marketing their products and business procuring/tendering for solutions). The two most common scenarios in my experience are a) when the system needs to integrate with other business systems to function and no one involved understands how complex that is (a lot), and b) when the business doesn’t understand how their business processes map to the system’s functionality (and are unwilling to change to fit the system’s convention).&lt;/p&gt;&lt;p&gt;What all of this means is that if you’re purchasing software or otherwise evaluating a system, do an in-depth analysis of how a) your process will have to change if the system requires convention, or b) how much configuration is required to make it fit. If you sell software, it’s your responsibility to ensure your customers understand this, and if you create software, it is valuable to consider where you want your software to sit on this spectrum, especially when you consider factors such as user training or safety/correctness guarantees.&lt;/p&gt;</content>
    </entry>
  
    <entry xml:lang="en">
      <title>Types upon types: Making plaintext coding safer</title>
      <published>2021-05-16T00:00:00+00:00</published>
      <updated>2021-05-16T00:00:00+00:00</updated>
      <link rel="alternate" type="text/html" href="https://rslabbert.com/blog/types_upon_types/"></link>
      <id>https://rslabbert.com/blog/types_upon_types/</id>
      <content type="html" xml:base="https://rslabbert.com/blog/types_upon_types/">&lt;p&gt;In a &lt;a href=&quot;https://rslabbert.com/blog/typescript_proxy_magic/&quot;&gt;previous post&lt;/a&gt;, I ran through how we were able to make coding of the Azure Data Factory (&lt;abbr title=&quot;Azure Data Factory&quot;&gt;ADF&lt;/abbr&gt;) dynamic language safer by extracting the plain text language into equivalent Typescript functions. What this means is that something like &lt;code&gt;&amp;quot;concat()&amp;quot;&lt;/code&gt; can instead be written as &lt;code&gt;concat()&lt;/code&gt; (notice the lack of quotes, meaning it’s a real Typescript function).&lt;/p&gt;&lt;p&gt;Because the Typescript function will eventually just “compile” down to the equivalent string, the immediate benefit is that it’s easier to code because we can take advantage of the Typescript compiler to identify glaring issues (parentheses, commas, misspellings, etc.). It was, however, really easy to add a layer on top of this that provides type safety.&lt;/p&gt;&lt;p&gt;The crux of our type-safety is the use of the following classes:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;ts&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;ADFExpression&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;property function_method&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;variable_parameter variable constructor constant variable_builtin function_builtin type&quot;&gt;value&lt;/span&gt;: &lt;span class=&quot;type_builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;property function_method&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;type_builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;variable_builtin&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;StringExpression&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;ADFExpression&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;_phantom&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&amp;quot;string&amp;quot;&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;rawString&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable_parameter variable constructor constant variable_builtin function_builtin type&quot;&gt;str&lt;/span&gt;: &lt;span class=&quot;type_builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;type&quot;&gt;StringExpression&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;StringExpression&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;`&amp;apos;&lt;/span&gt;&lt;span class=&quot;string embedded punctuation_special&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;string embedded variable constructor constant variable_builtin function_builtin type&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;string embedded punctuation_special punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;apos;`&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;IntegerExpression&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;ADFExpression&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;_phantom&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&amp;quot;integer&amp;quot;&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;integer&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;rawInt&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable_parameter variable constructor constant variable_builtin function_builtin type&quot;&gt;n&lt;/span&gt;: &lt;span class=&quot;type_builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;type&quot;&gt;IntegerExpression&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;IntegerExpression&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;comment&quot;&gt;// and so on for float, boolean, etc.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The key thing to note here is the use of a &lt;code&gt;_phantom&lt;/code&gt; field on the class which ensures that Typescript’s structural type checking can disambiguate between the different types. With the above, it then becomes really easy to create the aforementioned &lt;code&gt;concat&lt;/code&gt; function:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;ts&quot;&gt;&lt;span class=&quot;comment&quot;&gt;/**
 * Combine two or more strings, and return the combined string.
 * @param args At least two strings to combine
 * @returns The string created from the combined input strings
 */&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;concat&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;args&lt;/span&gt;: &lt;span class=&quot;type&quot;&gt;StringExpression&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;type&quot;&gt;StringExpression&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;must provide at least 1 argument to concat&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;StringExpression&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;string&quot;&gt;&amp;quot;concat(&amp;quot;&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable_parameter variable constructor constant variable_builtin function_builtin type&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;)&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;concat() throws&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toThrowError&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;must provide at least 1 argument to concat&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;concat(&amp;apos;hello&amp;apos;)&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;rawString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;concat(&amp;apos;hello&amp;apos;)&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;concat(&amp;apos;hello&amp;apos;, &amp;apos;world&amp;apos;)&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;rawString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;rawString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;world&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;string&quot;&gt;&amp;quot;concat(&amp;apos;hello&amp;apos;, &amp;apos;world&amp;apos;)&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The trick here is that the &lt;code&gt;concat&lt;/code&gt; function is only allowed to accept &lt;code&gt;StringExpression&lt;/code&gt; arguments, and also only return a &lt;code&gt;StringExpression&lt;/code&gt;. Consider how we can then combine these functions together in a type-safe manner:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;ts&quot;&gt;&lt;span class=&quot;comment&quot;&gt;// Compiles successfully&lt;/span&gt;
&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;rawString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;prefix&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;rawString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;-&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;rawString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;suffix&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;comment&quot;&gt;// Fails to compile with:&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;//   Argument of type &amp;apos;IntegerExpression&amp;apos; is not assignable to parameter of type &amp;apos;StringExpression&amp;apos;.&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;//   Types have separate declarations of a private property &amp;apos;_phantom&amp;apos;.ts(2345)&lt;/span&gt;
&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;rawString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;suffix&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;rawInt&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This becomes particularly valuable in the larger dynamic property sections which might look something like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;ts&quot;&gt;&lt;span class=&quot;comment&quot;&gt;// This code creates a path to a blob storage endpoint using a json object&lt;/span&gt;
&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;equals&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;punctuation_bracket operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;Params&lt;/span&gt;&lt;span class=&quot;punctuation_bracket operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;targetIsSecure&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;string&quot;&gt;&amp;apos;https://&amp;apos;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;string&quot;&gt;&amp;apos;http://&amp;apos;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;punctuation_bracket operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;Params&lt;/span&gt;&lt;span class=&quot;punctuation_bracket operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;targetEndpoint&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;rawString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;punctuation_bracket operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;Params&lt;/span&gt;&lt;span class=&quot;punctuation_bracket operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;targetPath&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;rawString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;guid&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;apos;D&amp;apos;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Creating the above as a plain text string would present tangible maintainability issues, but with our approach, we get the following:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Code is type-checked&lt;/li&gt;&lt;li&gt;We can make use of native testing facilities&lt;/li&gt;&lt;li&gt;Intellisense of all ADF functions&lt;/li&gt;&lt;li&gt;JSDoc documentation provides explanations of functions in code&lt;/li&gt;&lt;li&gt;Additional compile-time logic can be added as TS code (see &lt;code&gt;args.length &amp;lt; 1&lt;/code&gt; check in &lt;code&gt;concat&lt;/code&gt;).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In the future, we might revisit this and consider creating a parser &amp; interpreter, allowing us to execute these expressions locally (instead of relying on the ADF service). For now, however, this approach only took a small amount of time and gave us a significant maintainability improvement.&lt;/p&gt;</content>
    </entry>
  
    <entry xml:lang="en">
      <title>Typescript proxy magic</title>
      <published>2021-05-13T00:00:00+00:00</published>
      <updated>2021-05-13T00:00:00+00:00</updated>
      <link rel="alternate" type="text/html" href="https://rslabbert.com/blog/typescript_proxy_magic/"></link>
      <id>https://rslabbert.com/blog/typescript_proxy_magic/</id>
      <content type="html" xml:base="https://rslabbert.com/blog/typescript_proxy_magic/">&lt;p&gt;As part of my day job I published a &lt;a href=&quot;https://web.archive.org/web/20230322025601/https://aginic.com/blog/creating-azure-data-factory-pipelines-using-typescript/&quot;&gt;blog post&lt;/a&gt; on how we are able to build a Typescript-based abstraction layer on top of the Azure Data Factory (&lt;abbr title=&quot;Azure Data Factory&quot;&gt;ADF&lt;/abbr&gt;) API. Given that the “Typescript magic” code was my personal contribution, I wanted to do a quick personal post to show how a specific part of it works.&lt;/p&gt;&lt;p&gt;The relevant piece is near the end where we are able to replace a dynamic language run by &lt;abbr title=&quot;Azure Data Factory&quot;&gt;ADF&lt;/abbr&gt; (normally written as plain text) with Typescript code that “compiles” to the correct text while providing type safety:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;ts&quot;&gt;&lt;span class=&quot;comment&quot;&gt;// This string is how we would normally write a dynamic property:&lt;/span&gt;
&lt;span class=&quot;string&quot;&gt;`@concat(pipeline().paramaters.Folder, &amp;quot;/&amp;quot;, pipeline().paramaters.File)`&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;comment&quot;&gt;// This is the updated Typescript method:&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;MyPipelineParams&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;property&quot;&gt;Folder&lt;/span&gt;: &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;type&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&amp;quot;String&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;property&quot;&gt;File&lt;/span&gt;: &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;type&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&amp;quot;String&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;expression&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;punctuation_bracket operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;MyPipelineParams&lt;/span&gt;&lt;span class=&quot;punctuation_bracket operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;Folder&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;rawString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;punctuation_bracket operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;MyPipelineParams&lt;/span&gt;&lt;span class=&quot;punctuation_bracket operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;File&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The specific part I wanted to dig into is the &lt;code&gt;pipeline&amp;lt;T&amp;gt;()&lt;/code&gt; function. This is the code we used:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;ts&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;pipeline&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;type&quot;&gt;PipelineFunction&lt;/span&gt;&lt;span class=&quot;punctuation_bracket operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;punctuation_bracket operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;PipelineFunction&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;createParamProxy&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;parameters&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;pipeline()&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;type_builtin&quot;&gt;unknown&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;T&lt;/span&gt;
    &lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;createParamProxy&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;variable_parameter variable constructor constant variable_builtin function_builtin type&quot;&gt;p&lt;/span&gt;: &lt;span class=&quot;type_builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;type_builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;type_builtin&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;variable_parameter variable constructor constant variable_builtin function_builtin type&quot;&gt;parent&lt;/span&gt;: &lt;span class=&quot;type_builtin&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;type&quot;&gt;ADFExpression&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;Proxy&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;ADFExpression&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;property function_method&quot;&gt;get&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable_parameter variable constructor constant variable_builtin function_builtin type&quot;&gt;_target&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable_parameter variable constructor constant variable_builtin function_builtin type&quot;&gt;prop&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;0&lt;/span&gt; ? &lt;span class=&quot;string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt; : &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;parent&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;prop&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;toJSON&amp;quot;&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;prop&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;toString&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;createParamProxy&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;prop&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;createParamProxy&lt;/code&gt; function is the core part of this. Basically, it (ab)uses the JS &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy&quot;&gt;Proxy&lt;/a&gt; API to create a dynamic object that does the following:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;When you access a property on the paramProxy, it will return a new paramProxy with the name of the parent path added to the new property name.&lt;/li&gt;&lt;li&gt;Unless you call &lt;code&gt;toJSON&lt;/code&gt; or &lt;code&gt;toString&lt;/code&gt;, in which case it will dump the entire path out as a string.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The clearest examples of this are the test cases for the &lt;code&gt;createParamProxy&lt;/code&gt; function:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;ts&quot;&gt;&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;createParamProxy with parent toString()&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;proxy&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;createParamProxy&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;mock&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;mockparent&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;proxy&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;mockparent.mock&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// eslint-disable-next-line @typescript-eslint/no-explicit-any&lt;/span&gt;
    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;proxy&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;type_builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toJSON&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;mockparent.mock&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;createParamProxy without parent toString()&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;proxy&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;createParamProxy&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;mock&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;proxy&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;mock&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// eslint-disable-next-line @typescript-eslint/no-explicit-any&lt;/span&gt;
    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;proxy&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;type_builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toJSON&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;mock&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;createParamProxy nesting&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;MockType&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;property&quot;&gt;Nest1&lt;/span&gt;: &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;property&quot;&gt;Nest2&lt;/span&gt;: &lt;span class=&quot;type&quot;&gt;StringExpression&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;proxy&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;createParamProxy&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;mock&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;mockparent&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;type_builtin&quot;&gt;unknown&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;MockType&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;proxy&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;Nest1&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;Nest2&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;mockparent.mock.Nest1.Nest2&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// eslint-disable-next-line @typescript-eslint/no-explicit-any&lt;/span&gt;
    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable constructor constant variable_builtin function_builtin type&quot;&gt;proxy&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;Nest1&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;Nest2&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;type_builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toJSON&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;string&quot;&gt;&amp;quot;mockparent.mock.Nest1.Nest2&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And for an example of it in action with the &lt;code&gt;pipeline&lt;/code&gt; function, we can use this test case:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;ts&quot;&gt;&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;pipeline syntax with other functions&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;Test&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;property&quot;&gt;Nest1&lt;/span&gt;: &lt;span class=&quot;type&quot;&gt;StringExpression&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable function constructor constant variable_builtin function_builtin type&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;punctuation_bracket operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;Test&lt;/span&gt;&lt;span class=&quot;punctuation_bracket operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;Nest1&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;string&quot;&gt;&amp;quot;concat(pipeline().parameters.Nest1)&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All in all, this was a pretty cool example of how Typescript and Javascript operate at two different layers and that you can deliberately decouple those layers to do interesting things. Stay tuned for another post where I’ll dig into how we used Typescript types to ensure functions like &lt;code&gt;concat&lt;/code&gt; (which “compile” to the string &lt;code&gt;&amp;quot;concat()&amp;quot;&lt;/code&gt;) can be made type safe to ensure it only accepts other strings as inputs (i.e. &lt;code&gt;concat(&amp;quot;a string&amp;quot;, 2)&lt;/code&gt; fails to compile as Typescript).&lt;/p&gt;</content>
    </entry>
  
    <entry xml:lang="en">
      <title>Absolute vs Relative values</title>
      <published>2021-05-12T00:00:00+00:00</published>
      <updated>2021-05-12T00:00:00+00:00</updated>
      <link rel="alternate" type="text/html" href="https://rslabbert.com/blog/absolute_vs_relative_values/"></link>
      <id>https://rslabbert.com/blog/absolute_vs_relative_values/</id>
      <content type="html" xml:base="https://rslabbert.com/blog/absolute_vs_relative_values/">&lt;p&gt;A recent &lt;a href=&quot;https://news.ycombinator.com/item?id=27115551&quot;&gt;HN Post&lt;/a&gt; discussed the idea of Zig’s approach to safety, especially in comparison to Rust. While it is true that Rust is a “safer” language than Zig, I think there’s a lot of nuance that gets lost due to the nature of absolutes.&lt;/p&gt;&lt;h2&gt;&lt;!-- more --&gt;&lt;/h2&gt;&lt;p&gt;The first point here is that all projects/teams/etc. make use of a certain set of values, whether they acknowledge it at all. Values by nature are also relative. For a certain feature, one value might win out over another. For example, Rust values safety and compatibility, which is why &lt;code&gt;unsafe&lt;/code&gt; exists.&lt;/p&gt;&lt;p&gt;Secondly, some projects also choose to treat a specific value as overwhelmingly important. I call these &lt;em&gt;absolute&lt;/em&gt; values. That’s not to say that the value will always win out (reductively: the most secure language is one that doesn’t let you write code), but that it will overwhelmingly be used to justify decisions. Again, projects like Rust and OpenBSD value security as an absolute value, as it guides decisions that affect large parts of the projects.&lt;/p&gt;&lt;p&gt;Thirdly, for various reasons, nuance gets lost in general discussion. Something like “Rust will overwhelmingly value safety over other values, but not exclusively” is reduced to “Rust is a safe language”. This isn’t a &lt;em&gt;bad&lt;/em&gt; thing as such, but it can lead to issues such as the following: Rust is a safe language, Rust is safer than Zig, thus Zig is not a safe language. This is frequently not even a conscious decision. When I’m looking at two CLI tools to accomplish a specific task, I will most likely favour a Rust version over a C version, because subconsciously I have an negative association with some (poorly written) C programs.&lt;/p&gt;&lt;p&gt;The conclusion to take from this, in my opinion, is that we need to consistently challenge ourselves to fully consider what a project is actually trying to do, as opposed to what we think it’s trying to do at a glance. If we critically examine a project’s values, and especially when one wins over another, we can have a much better understanding of what it actually means to compare languages.&lt;/p&gt;&lt;p&gt;Additionally, if you’re a project maintainer, I’d highly recommend having a robust understanding of the values for your project and making that clear upfront. This will not only help developers on the project make more informed decisions, but it will also drive a deeper understanding of your project in the broader discussion sphere.&lt;/p&gt;</content>
    </entry>
  
    <entry xml:lang="en">
      <title>A build tool for the rest of us</title>
      <published>2021-04-13T00:00:00+00:00</published>
      <updated>2021-04-13T00:00:00+00:00</updated>
      <link rel="alternate" type="text/html" href="https://rslabbert.com/blog/a_build_tool_for_the_rest_of_us/"></link>
      <id>https://rslabbert.com/blog/a_build_tool_for_the_rest_of_us/</id>
      <content type="html" xml:base="https://rslabbert.com/blog/a_build_tool_for_the_rest_of_us/">&lt;p&gt;Imagine a hypothetical company with a codebase ranging between 0 to 10 million lines of code. This codebase spans a number of different languages such as Go/Java/Node.js servers, JS webapps, and Python data pipelines. Is there an existing tool we can use to provide a unified build system? Maybe, but it’s probably not worth the effort to implement. Can we do better?&lt;/p&gt;&lt;p&gt;When we talk about build tools it generally illicits one of three archetypes:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;“Execute commands in sequence” tools. e.g. Bash scripts, PHONY Makefiles.&lt;/li&gt;&lt;li&gt;Language centric systems, e.g. NPM, Cargo, CMake, Meson.&lt;/li&gt;&lt;li&gt;Polyglot build tools, e.g. Bazel, Buck, Please.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Given the above, our hypotethical company most likely wants the 3rd option, but these existing tools are fairly complex and have a number of shortcomings for companies that don’t need to build billions of lines of code.&lt;/p&gt;&lt;h2&gt;Language specific tool integration&lt;/h2&gt;&lt;p&gt;Bazel was initially designed heavily around Google’s core languages: C/++, Java, Python, and pre-npm Javascript. The thing all four of these technologies had in common (at the time the tool was written) was a lack of good language centric build tools. Coupled with a preference for vendoring libraries, this design get brought to a stretch when we look at how it handles languages such as &lt;a href=&quot;https://github.com/google/cargo-raze&quot;&gt;Rust&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;If we acknowledge that most modern development use a build tool that is already designed for the language in question, it would make sense for our hypothetical polyglot tool to natively support these language centric tools. In regards to Rust, instead of trying to extract a &lt;code&gt;Cargo.toml&lt;/code&gt; file into a generated &lt;code&gt;BAZEL&lt;/code&gt; file, our build tool could understand what a Rust project looks like, especially as it relates to how the tools already handle dependency management.&lt;/p&gt;&lt;p&gt;For example, consider the following project structure:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;src/
    internal/sdk/mylib/Cargo.toml (depends on crates.io libraries)
    team_a/services/myexe/Cargo.toml (depends on mylib)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We should be able to just run &lt;code&gt;ourtool run team_a/services/myexe&lt;/code&gt; (in addition to &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt;) and it should “just work”. That’s to say, it should fetch the crates.io libraries for mylib, build mylib, build myexe, and execute it. This is a dramatic departure from the current build tool migration process which generally involves extensive reworking of build scripts and dependency management.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.pantsbuild.org/&quot;&gt;Pants v2&lt;/a&gt; is looking very promising in this space. It currently only supports Python, but already tries to integrate natively with what Python development is today. For example, you can automatically run any python projects without first having to create a build file. In addition, adding third party dependencies is as simple as adding a &lt;code&gt;requirements.txt&lt;/code&gt; file and having pants push that into the virtual environment (via some Pex magic) for the Python app we’re trying to execute. I’m keeping an eye on this to see how it handles the next two languages they seem to be targeting (namely Rust and Go).&lt;/p&gt;&lt;h2&gt;Editor / IDE / Language Server Protocol Integration&lt;/h2&gt;&lt;p&gt;A follow on from the previous point is that most development smarts (intellisense, refactoring, etc.) all rely on the language centric tools. In the simplest case, having our Javascript project use a real &lt;code&gt;package.json&lt;/code&gt; file with a corresponding &lt;code&gt;node_modules&lt;/code&gt;/&lt;code&gt;.yarn&lt;/code&gt; directory (optimally created and managed by our tool), our editor will natively pick up types and libraries.&lt;/p&gt;&lt;p&gt;There are more complicated cases which are also generally solveable. Python, for example, needs a virtual environment or Pex file created, and code generation from tools such as GRPC needs to actually create the files in the same filesystem as the code (not in a hermetic directory) to ensure the editor picks it up (our tool should probably manage &lt;code&gt;.gitignore&lt;/code&gt; to ensure these files aren’t commited).&lt;/p&gt;&lt;h2&gt;Make is easy to integrate new tools&lt;/h2&gt;&lt;p&gt;While our tool natively supporting language centric build systems works in some environments (e.g. Rust or Go), there are others where it works slightly less well. Javascript web development, for example, doesn’t have a standardised build tool. Teams might use Webpack, Rollup, Parcel, Snowpack, Vite, Create-React-App, ESBuild, and so on. Trying to support each of these tools is a recipe for development failure.&lt;/p&gt;&lt;p&gt;The optimal way to approach this should probably two-fold:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Support the most popular tool and/or the tool that integrates best with the speed and caching principles of the build tool. For example, Webpack for popularity and ESBuild for speed could cover the majority of teams right off the bat.&lt;/li&gt;&lt;li&gt;Make it easy to integrate new tools.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;For example, if we wanted to integrate create react app natively into our build tool, for projects already using npm it should be as simple as:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;&lt;span class=&quot;constructor function_builtin constant variable function&quot;&gt;npm_bin&lt;/span&gt;(
    &lt;span class=&quot;constructor constant variable&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;build&amp;quot;&lt;/span&gt;,
    &lt;span class=&quot;constructor constant variable&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;react-scripts build&amp;quot;&lt;/span&gt;,
    &lt;span class=&quot;constructor constant variable&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; [&lt;span class=&quot;string&quot;&gt;&amp;quot;./build&amp;quot;&lt;/span&gt;]
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should change our &lt;code&gt;ourtool build ./a/path&lt;/code&gt; to “just work”.&lt;/p&gt;&lt;h2&gt;It should be better for single language projects&lt;/h2&gt;&lt;p&gt;Even if we use only a single language, our build tool should add enough on top of the native language tooling to justify it. There are a couple of examples that immediately jump out:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Make it easy to manage a single language monorepo. For example, being able to have a single command to run, build, test, format, lint, etc. no matter where in the repository I am. This also applies in a world where we have many smaller repos that span multiple languages (i.e. cross language command consistency).&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Provide opinionated improvements on top of the native language. &lt;a href=&quot;https://www.pantsbuild.org/&quot;&gt;Pants v2&lt;/a&gt; again here dramatically improves on the native python virtual environment setup, dependency management, and packaging (via Pex) that is makes sense even in repos that are just Python. For example, automatically managing &lt;a href=&quot;https://github.com/mozilla/sccache&quot;&gt;sccache&lt;/a&gt; for Rust projects.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Provide dependency management for languages that don’t have it. C/++, Zig are natural examples here where having a really simple dependency management system can provide immense benefits. For example:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# .build&lt;/span&gt;
&lt;span class=&quot;constructor function_builtin constant variable function&quot;&gt;github_dependency&lt;/span&gt;(&lt;span class=&quot;constructor constant variable&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;cesanta/mongoose&amp;quot;&lt;/span&gt;, &lt;span class=&quot;constructor constant variable&quot;&gt;tag&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;7.2&amp;quot;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;c&quot;&gt;&lt;span class=&quot;comment&quot;&gt;// build.zig&lt;/span&gt;
&lt;span class=&quot;delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;constant variable&quot;&gt;exe&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;addCSourceFiles&lt;/span&gt;(&lt;span class=&quot;operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;.&lt;/span&gt;{&lt;span class=&quot;string&quot;&gt;&amp;quot;third_party/github/cesanta/mongoose/mongoose.c&amp;quot;&lt;/span&gt;}, &lt;span class=&quot;operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;.&lt;/span&gt;{})&lt;span class=&quot;delimiter&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Fast / Correct - Choose 80%&lt;/h2&gt;&lt;p&gt;If you’re someone who worked on Bazel I hope you’re not reading this post, because at this point you’ll be thinking “all of these features will break invariants and make other features such as remote caching more difficult/impossible”. The issue is that I agree, but fundamentally, there is most likely an 80% version of these invariants that will enable most of these features while not requiring the same amount of specificity.&lt;/p&gt;&lt;p&gt;Additionally, there’s probably a &lt;code&gt;disable_smarts = true&lt;/code&gt; flag that can be conditionally or globally set in situations where an organisation finds the smarts are causing significant enough performance issues. Then again, for these organisations, Bazel already exists.&lt;/p&gt;&lt;p&gt;There are a couple of things we definitely want to keep, however:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Our tool should handle fetching and installing the language tools. There is immense value in being able to rock up to a repository, run &lt;code&gt;ourtool build&lt;/code&gt;, and have it download the right Rust compiler, Go compiler, Python version, and JVM.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;File input/output based caching, but we can improve this. A smart tool should be able to read our source files (e.g. &lt;code&gt;*.py&lt;/code&gt;) or project files (e.g. &lt;code&gt;package.json&lt;/code&gt;) and figure out what the files depend on. This is even possible in C/++ using Clang (Zig uses this internally I believe to track header includes). The tradeoff then becomes, there is a lot of parsing that needs to happen across different languages and for larger repositories disabling this in exchange for explicit configuration might be needed.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Concurrent execution and cross-language dependencies. While a tool like this by design locks us into the concurrency of the underlying tools (e.g. using Cargo to concurrently compile Rust projects), the layer of concurrency on top of that can provide benefits as well. For example, if my Go server uses &lt;a href=&quot;https://golang.org/pkg/embed/&quot;&gt;embed&lt;/a&gt; to include an esbuild built JavaScript bundle, and a SASS built CSS collection, esbuild and sass should be able to be run in parallel and our Go embed rebuilt (if the JS or scss files changed) when we run &lt;code&gt;ourtool run my/go/app&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;What is missing here and why does this tool not exist? There are a lot of gaps or issues that should immediately jump out to different people. Some of these issues might disqualify a tool like this from existing entirely, but I suspect that most of these issues can actually be worked around as long as we’re willing to accept that we just might not be able to perfectly guarantee certain things (such as pure hermeticism), but is that not still an improvement for teams where Bazel is too complex?&lt;/p&gt;</content>
    </entry>
  
</feed>
