<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Guillaume Dormoy</title>
    <description>The latest articles on Forem by Guillaume Dormoy (@gdsources).</description>
    <link>https://forem.com/gdsources</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2070112%2F0074733a-37cd-4d88-b08e-51e08906c54c.png</url>
      <title>Forem: Guillaume Dormoy</title>
      <link>https://forem.com/gdsources</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/gdsources"/>
    <language>en</language>
    <item>
      <title>Building Techniques: A Deep Dive into TypeScript</title>
      <dc:creator>Guillaume Dormoy</dc:creator>
      <pubDate>Mon, 14 Oct 2024 09:19:05 +0000</pubDate>
      <link>https://forem.com/gdsources/building-techniques-a-deep-dive-into-typescript-3g7h</link>
      <guid>https://forem.com/gdsources/building-techniques-a-deep-dive-into-typescript-3g7h</guid>
      <description>&lt;p&gt;After &lt;a href="https://dev.to/gdsources/the-art-and-science-of-software-building-from-source-to-executable-5503"&gt;the fundamentals of building in part1&lt;/a&gt; and a closer look into &lt;a href="https://dev.to/gdsources/building-techniques-a-deep-dive-into-go-27ed"&gt;Go building phase,&lt;/a&gt; let’s dive into typescript.&lt;/p&gt;

&lt;p&gt;TypeScript, a typed superset of JavaScript developed by Microsoft, has its own unique build process that involves transpilation to JavaScript. Let's explore the various aspects of building TypeScript applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  TypeScript's Approach to Building
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The TypeScript Compiler (tsc)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;TypeScript comes with its compiler that translates TypeScript code into JavaScript code.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tsc main.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;tsconfig.json&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The compiler needs to know what to do, and TypeScript offers a large range of configuration options. You can add flags to the &lt;code&gt;tsc&lt;/code&gt; command, but it's far better to use the &lt;code&gt;tsconfig.json&lt;/code&gt; file. You can either create the file by hand or get a basic one with the command &lt;code&gt;tsc --init&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ES2015"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"commonjs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"strict"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"outDir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./dist"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"include"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"src/**/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this file, you will be able to specify the compiler options you want and which files you want to compile. For example, you will be able to specify how you handle modules. TypeScript supports various module systems: CommonJS, AMD, UMD, ES6. If you want to learn more about modules in TypeScript, the official documentation has a whole dedicated section: &lt;a href="https://www.typescriptlang.org/docs/handbook/modules/introduction.html" rel="noopener noreferrer"&gt;https://www.typescriptlang.org/docs/handbook/modules/introduction.html&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Example in tsconfig.json:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esnext"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can configure a lot more, but going through it all would take forever and would be really boring. Check out the dedicated section on TS documentation &lt;a href="https://www.typescriptlang.org/tsconfig/" rel="noopener noreferrer"&gt;https://www.typescriptlang.org/tsconfig/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Declaration Files (.d.ts)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nowadays, a lot of libraries are coded straight in TypeScript, but when a library is coded in JavaScript, it can still be used in your TypeScript project if the library has a declaration file. These files ending with .d.ts are basically the typed interface of the library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nx"&gt;helloer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sayHello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The TypeScript team has eased the creation of this file with the generate command: &lt;code&gt;tsc --declaration&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Advanced TypeScript Building Techniques
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Project References&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Project references in TypeScript offer significant benefits for managing large-scale applications. They provide a structured approach to organizing codebases, improving build performance, and enhancing code maintainability.&lt;/p&gt;

&lt;p&gt;Without this reference system, when you modify your codebase, TypeScript will compile everything, and your IDE will do the same in the background for type checking. On large codebases, it can consume a lot of resources and take a few minutes.&lt;/p&gt;

&lt;p&gt;With these references and a modular approach, you only compile what's being changed. You can have tailored compilation based on your module needs. And last but not least, it allows TypeScript to compile the modules in parallel!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Custom Transformers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I am not really into this one, but it's a really interesting feature that TypeScript allows. Custom transformers are functions that can modify the Abstract Syntax Tree (AST) of your TypeScript code during the compilation process. They allow you to add, remove, or modify nodes in the AST, enabling powerful code transformations and generation.&lt;/p&gt;

&lt;p&gt;The reason I don't like transformers is because I feel like they hide stuff from the developers. If there's something I hate when I develop, it's when something looks like magic. When everything works, it's awesome, but when it breaks, nightmare comes.&lt;/p&gt;

&lt;p&gt;For the sake of this article, here is a dead simple example:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;myCustomTransformer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TransformationContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sourceFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SourceFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Perform transformations here&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isCallExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getText&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;console.log&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCallExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createIdentifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;console.warn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;visitEachChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;visitNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sourceFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The configuration for TypeScript to use the transformer depends on your building system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monorepo Builds&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We have spoken about having a modular approach in the compilation with project references; let's just take a moment to speak about some useful tools that do similar jobs, like Nx.&lt;/p&gt;

&lt;p&gt;While Project References focuses solely on TypeScript compilation, Nx provides broader project management capabilities that can incorporate TypeScript builds alongside other development tasks in a more extensive ecosystem. It supports multiple languages and offers features like dependency visualization and smart command execution, which can really help in managing mono-repos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimization Techniques
&lt;/h3&gt;

&lt;p&gt;To end this post, let's go over two optimization techniques that can make your code faster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tree Shaking&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tree shaking is an optimization technique used in modern JavaScript bundlers to eliminate dead code. I hear you say, "It's the developer's duty to clean their code," and you are right! We developers are still human beings and therefore imperfect.&lt;/p&gt;

&lt;p&gt;Most of the time, you already use Tree Shaking optimization without knowing it. It's in your favorite framework's production build setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Splitting&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I am sure you already do this, but this one is more important than you may think. By adopting a modular approach and splitting your code into smaller chunks, you get faster loading times.&lt;/p&gt;

&lt;p&gt;You can also use dynamic imports to import modules on the go.&lt;/p&gt;

&lt;p&gt;—&lt;/p&gt;

&lt;p&gt;And we are done for today! I hope you found some good techniques or interesting insights on how TypeScript software is compiled and how you can improve your loved projects.&lt;/p&gt;

&lt;p&gt;Next, we will have a look into the history of building tools.&lt;/p&gt;

&lt;p&gt;Until then, happy coding!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Building Techniques: A Deep Dive into Go</title>
      <dc:creator>Guillaume Dormoy</dc:creator>
      <pubDate>Mon, 30 Sep 2024 09:43:01 +0000</pubDate>
      <link>https://forem.com/gdsources/building-techniques-a-deep-dive-into-go-27ed</link>
      <guid>https://forem.com/gdsources/building-techniques-a-deep-dive-into-go-27ed</guid>
      <description>&lt;p&gt;Go has been an important language in my personal career. I built a solid audio adServer and SSP with it when I was CTO at Soundcast. Go makes networking and parallelism so easy it feels like cheating. All that with really good performance, which was perfect for the job we had to do.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://dev.to/gdsources/the-art-and-science-of-software-building-from-source-to-executable-5503"&gt;part 1&lt;/a&gt;, we unveiled the fundamentals of the building phase of software. In this article, we will make this more relevant with the help of a language that has a special place in my heart. Indeed, while the fundamentals of building software are similar across languages, each language ecosystem has its own unique tools and practices.&lt;/p&gt;

&lt;p&gt;Without further ado, let's explore these, with a particular focus on Go.&lt;/p&gt;

&lt;h3&gt;
  
  
  Go's Approach to Building
&lt;/h3&gt;

&lt;p&gt;Go, designed by Google, takes a unique approach to building that emphasizes simplicity and speed.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;A Command&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Go comes with a build command. This command compiles the packages named by the import paths, along with their dependencies, but doesn't install the results. It generates an executable file.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go build main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Cross-Compilation in Go&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;One of the most useful features of the Go compiler is the ability to perform cross-compilation remarkably easily. All you have to do is set the &lt;code&gt;GOOS&lt;/code&gt; and &lt;code&gt;GOARCH&lt;/code&gt; environment variables to target the desired platforms.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GOOS=windows GOARCH=amd64 go build main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create an executable for Windows under an amd64 architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Go Modules&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Go mod&lt;/code&gt; came a bit late because it was introduced with Go 1.11, but it's a built-in dependency management system. Before that, we had to place all our Go projects into a dedicated directory on our machine called &lt;code&gt;{$GOPATH}&lt;/code&gt;. While it worked, &lt;code&gt;Go mod&lt;/code&gt; gives us more flexibility now, which is great!&lt;/p&gt;

&lt;p&gt;Usage is pretty straightforward, like everything in Go.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;go mod init&lt;/code&gt; initializes a new module.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;go.mod&lt;/code&gt; file tracks dependencies and their versions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can add conditional compilation by using build tags, but the most interesting feature, in my opinion, is that Go automatically caches build output to speed up subsequent builds (of course, you can clean the cache if needed).&lt;/p&gt;

&lt;h3&gt;
  
  
  Advanced Go Building Techniques
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Embedding Resources&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have static files that you want to include in your binary, you can use the &lt;code&gt;//go:embed&lt;/code&gt; directive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Race Detection&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go is awesome when it comes to parallelism. With its system of goroutines and channels to communicate between them, developers can easily split the workload of the software on different cores. But it's also easy to mess things up and create "races."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A data race occurs when two goroutines access the same variable concurrently and at least one of the accesses is a write. See the The Go Memory Model for details.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Go compiler can help you find them!&lt;/p&gt;

&lt;p&gt;Use the &lt;code&gt;race&lt;/code&gt; flag to detect race conditions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go build -race main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Profiling and Optimization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the main things I like in Go is its performance. This language gives solid results with not much effort. But if you want to go the extra mile, the Go ecosystem also gives you some really great tools to measure your performance and optimize your code.&lt;/p&gt;

&lt;p&gt;I am not going to go into the details, but if you want to dive into the subject, I invite you to read this gem: &lt;a href="https://www.practical-go-lessons.com/chap-34-benchmarks" rel="noopener noreferrer"&gt;https://www.practical-go-lessons.com/chap-34-benchmarks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Custom Build Modes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sometimes, you are not building software but a plugin or a library, for example. The Go team has got your back. In Go, you can define the buildmode to get the result you want!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build shared libraries: &lt;code&gt;go build -buildmode=c-shared&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Build plugins: &lt;code&gt;go build -buildmode=plugin&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Get the full list at &lt;a href="https://pkg.go.dev/cmd/go#hdr-Build_modes" rel="noopener noreferrer"&gt;https://pkg.go.dev/cmd/go#hdr-Build_modes&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, Go provides a lot of features in its compiler and ecosystem to allow developers to get the most out of the Go technology.&lt;/p&gt;

&lt;p&gt;And that's it for today. I'll be releasing another article this week showcasing the building techniques for TypeScript, so subscribe or follow if you want to make sure not to miss it!&lt;/p&gt;

&lt;p&gt;Until then, happy coding!&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>TSyringe and Dependency Injection in TypeScript</title>
      <dc:creator>Guillaume Dormoy</dc:creator>
      <pubDate>Wed, 25 Sep 2024 09:06:48 +0000</pubDate>
      <link>https://forem.com/gdsources/tsyringe-and-dependency-injection-in-typescript-3i67</link>
      <guid>https://forem.com/gdsources/tsyringe-and-dependency-injection-in-typescript-3i67</guid>
      <description>&lt;p&gt;I am not a big fan of large frameworks like NestJS; I've always liked the freedom of building my software the way I want with the structure I decide in a lightweight way. But something I liked when testing NestJS out was the Dependency injection.&lt;/p&gt;

&lt;p&gt;Dependency Injection (DI) is a design pattern that allows us to develop loosely coupled code by removing the responsibility of creating and managing dependencies from our classes. This pattern is crucial for writing maintainable, testable, and scalable applications. In the TypeScript ecosystem, TSyringe stands out as a powerful and lightweight dependency injection container that simplifies this process.&lt;/p&gt;

&lt;p&gt;TSyringe is a lightweight dependency injection container for TypeScript/JavaScript applications. Maintained by Microsoft on their GitHub (&lt;a href="https://github.com/microsoft/tsyringe" rel="noopener noreferrer"&gt;https://github.com/microsoft/tsyringe&lt;/a&gt;), it uses decorators to do &lt;a href="https://en.wikipedia.org/wiki/Dependency_injection#Constructor_injection" rel="noopener noreferrer"&gt;Constructor injection&lt;/a&gt;. Then, it uses an &lt;a href="https://en.wikipedia.org/wiki/Inversion_of_control" rel="noopener noreferrer"&gt;Inversion of Control&lt;/a&gt; container to store the dependencies based on a token that you can exchange for an instance or a value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Dependency Injection
&lt;/h2&gt;

&lt;p&gt;Before diving into TSyringe, let's briefly explore what dependency injection is and why it's important.&lt;/p&gt;

&lt;p&gt;Dependency injection is a technique where an object receives its dependencies from external sources rather than creating them itself. This approach offers several benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Improved testability: Dependencies can be easily mocked or stubbed in unit tests.&lt;/li&gt;
&lt;li&gt;Increased modularity: Components are more independent and can be easily replaced or updated.&lt;/li&gt;
&lt;li&gt;Better code reusability: Dependencies can be shared across different parts of the application.&lt;/li&gt;
&lt;li&gt;Enhanced maintainability: Changes to dependencies have minimal impact on dependent code.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setting Up TSyringe
&lt;/h2&gt;

&lt;p&gt;First, let's set up TSyringe in your TypeScript project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;tsyringe reflect-metadata

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your &lt;code&gt;tsconfig.json&lt;/code&gt;, ensure you have the following options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"experimentalDecorators"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"emitDecoratorMetadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Import &lt;code&gt;reflect-metadata&lt;/code&gt; at the entry point of your application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reflect-metadata&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entry point of your application is, for example, the root layout on Next.js 13+, or it can be the main file in a small Express application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Dependency Injection with TSyringe
&lt;/h2&gt;

&lt;p&gt;Let's take the example from the introduction and add the TSyringe sugar:&lt;/p&gt;

&lt;p&gt;Let's start with the adapter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// @/adapters/userAdapter.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;injectable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tsyringe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserAdapter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;fetchByUUID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the &lt;code&gt;@injectable()&lt;/code&gt; decorator? It's to tell TSyringe that this class can be injected at runtime.&lt;/p&gt;

&lt;p&gt;So my Service is using the adapter we just created. Let's inject that Adapter into my Service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// @/core/user/user.service.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;injectable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inject&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tsyringe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UserAdapter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;userAdapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserAdapter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;fetchByUUID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userAdapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchByUUID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I also used the &lt;code&gt;@injectable&lt;/code&gt; decorator because the Service is going to be injected into my command class, but I also added the &lt;code&gt;@inject&lt;/code&gt; decorator in the constructor params. This decorator tells TSyringe to give the instance or the value it has for the token &lt;code&gt;UserAdapter&lt;/code&gt; for the userAdapter property at runtime.&lt;/p&gt;

&lt;p&gt;And last but not least, the root of my Core: the command class (often wrongly called usecase).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// @/core/user/user.commands.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;inject&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tsyringe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserCommands&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UserService&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;fetchByUUID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchByUUID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, we've told TSyringe what is going to be injected and what to inject in the constructor. But we still haven't made our containers to store the dependencies. We can do that in two ways:&lt;/p&gt;

&lt;p&gt;We can create a file with our dependency injection registry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// @/core/user/user.dependencies.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tsyringe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UserService&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;useClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;// associate the UserService with the token "UserService"&lt;/span&gt;
&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UserAdapter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;useClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserAdapter&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;// associate the UserAdapter with the token "UserAdapter"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But we can also use the &lt;code&gt;@registry&lt;/code&gt; decorator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// @/core/user/user.commands.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;injectable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tsyringe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UserService&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;useClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UserAdapter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;useClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserAdapter&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserCommands&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UserService&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;fetchByUUID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchByUUID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UserCommands&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;useClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserCommands&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both methods have pros and cons, but at the end of the day, it's a matter of taste.&lt;/p&gt;

&lt;p&gt;Now that our container is filled with our dependencies, we can get them from the container as needed by using the resolve method of the container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;UserCommands&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/core/user/user.commands&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userCommands&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserCommands&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UserCommands&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;userCommands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchByUUID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example is pretty simple as each class only depends on another, but our services could depend on many, and dependency injection would really help keep everything tidy.&lt;/p&gt;

&lt;p&gt;But wait! Don't leave me like that! How about the tests?&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing with TSyringe
&lt;/h2&gt;

&lt;p&gt;Our injections can also help us test our code by sending mock objects straight into our dependencies. Let's see a code example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;UserCommands&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/core/user/user.commands&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test ftw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;userAdapterMock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserAdapterMock&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;userCommands&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserCommands&lt;/span&gt;

    &lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;userAdapterMock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserAdapter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;registerInstance&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserAdapter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UserAdapter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userAdapter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;userCommands&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserCommands&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UserCommands&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the &lt;code&gt;UserAdapter&lt;/code&gt; token contains a mock that will be injected into the dependent classes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices and Tips
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use interfaces&lt;/strong&gt;: Define interfaces for your dependencies to make them easily swappable and testable. I didn't use interfaces for the sake of simplicity in this article, but interfaces are life.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid circular dependencies&lt;/strong&gt;: Structure your code to avoid circular dependencies, which can cause issues with TSyringe.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use tokens for naming&lt;/strong&gt;: Instead of using string literals for injection tokens, create constant tokens:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;USER_REPOSITORY_TOKEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UserRepository&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scoped containers&lt;/strong&gt;: Use scoped containers for request-scoped dependencies in web applications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Don't overuse DI&lt;/strong&gt;: Not everything needs to be injected. Use DI for cross-cutting concerns and configurable dependencies.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you've come this far, I want to say thank you for reading. I hope you found this article instructive. Remember to always consider the specific needs of your project when implementing dependency injection and architectural patterns.&lt;/p&gt;

&lt;p&gt;Likes and comment feedback are the best ways to improve.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>dependencyinversion</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>The Art and Science of Software Building: From Source to Executable</title>
      <dc:creator>Guillaume Dormoy</dc:creator>
      <pubDate>Mon, 23 Sep 2024 08:57:37 +0000</pubDate>
      <link>https://forem.com/gdsources/the-art-and-science-of-software-building-from-source-to-executable-5503</link>
      <guid>https://forem.com/gdsources/the-art-and-science-of-software-building-from-source-to-executable-5503</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1g0fkcdb1za7c4dsgby8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1g0fkcdb1za7c4dsgby8.png" alt="Image description" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
In today's fast-paced world of software development, the journey from writing code to deploying a functional application is more complex—and more fascinating—than ever before. Whether you're a seasoned developer or just starting your coding journey, understanding the intricacies of software building is crucial for creating efficient, scalable, and robust applications.&lt;/p&gt;
&lt;h2&gt;
  
  
  Introduction: Why Software Building Matters
&lt;/h2&gt;

&lt;p&gt;Last week, we explored what makes an effective Continuous Integration (CI) process. Now, we're diving deeper into the foundation of CI and software development as a whole: the art and science of software building. This article kicks off a series that will take you on a journey through the evolution of build processes, from simple command-line compilations to sophisticated containerized build environments.&lt;/p&gt;

&lt;p&gt;Throughout this series, we'll uncover:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The fundamentals of software building and its critical role in the development lifecycle&lt;/li&gt;
&lt;li&gt;Various building techniques across programming languages, with a special focus on Go and TypeScript&lt;/li&gt;
&lt;li&gt;The game-changing role of containers in modern build processes&lt;/li&gt;
&lt;li&gt;A historical perspective on the evolution of software building over the decades&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end of this series, you'll have a comprehensive understanding of software building that will empower you to make informed decisions in your development projects. So, let's compile our thoughts and build our way through this fascinating aspect of software development!&lt;/p&gt;
&lt;h2&gt;
  
  
  Defining Software Building
&lt;/h2&gt;

&lt;p&gt;Before we dive in, let's establish a clear definition:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In the world of software development, "building" is the crucial step that transforms human-readable source code into machine-executable programs. It's the bridge between the creative process of writing code and the practical reality of running software on computers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  My Journey: From University Labs to Modern Development
&lt;/h2&gt;
&lt;h3&gt;
  
  
  The Early Days: C and Manual Dependency Management
&lt;/h3&gt;

&lt;p&gt;My software engineering journey began in 2006 when I started studying computer science at university. One of our first major projects was to re-implement the C library from scratch. As a 19-year-old student, I found myself grappling with the complexities of compiled languages for the first time.&lt;/p&gt;

&lt;p&gt;Initially, compiling our C code involved a seemingly simple yet bewildering command line interface. As our projects grew more complex, we graduated to using makefiles—a significant step up, but still far from the streamlined processes we enjoy today.&lt;/p&gt;

&lt;p&gt;Perhaps the most striking difference was dependency management. Back then, I handled dependencies manually, scouring the internet for the right libraries and importing them into my projects one by one. It was a tedious and error-prone process that consumed a significant portion of development time.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Revelation: Automated Dependency Management
&lt;/h3&gt;

&lt;p&gt;It wasn't until I left university and started working with Symfony around 2013 that I discovered the power of automated dependency management. The revelation was game-changing: tools could handle the complex web of dependencies for us, saving time and reducing errors.&lt;/p&gt;

&lt;p&gt;Fast forward to today, and it's almost unbelievable to think of a time without robust dependency management tools. Every major programming ecosystem now boasts one or several such tools, transforming what was once a burdensome task into a seamless part of the development process.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Modern Mantra: "Check out the dependencies, then build"
&lt;/h3&gt;

&lt;p&gt;Today, whether we're working with containers or on bare metal, the software building process has been distilled to a simple yet powerful mantra: "Check out the dependencies, then build." This elegantly simple approach belies the complex evolution of build processes over the years.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Fundamentals of Software Building
&lt;/h2&gt;

&lt;p&gt;Now that we've set the stage with a bit of history, let's break down the key components and concepts of software building. Understanding these fundamentals is crucial for any developer looking to optimize their build processes and create more efficient software.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Compilation vs. Interpretation: The Language Spectrum
&lt;/h3&gt;

&lt;p&gt;Programming languages generally fall into three categories, each with its own approach to turning code into executable instructions:&lt;/p&gt;
&lt;h3&gt;
  
  
  Compiled Languages: Speed at the Cost of Flexibility
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;: C, C++, Go&lt;/p&gt;

&lt;p&gt;Compiled languages use a compiler to translate code directly into machine code, which can be executed by the computer's hardware. This approach typically results in faster runtime performance but requires a separate build step for each target platform.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Example of a simple Go program&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, compiled world!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run this, you'd first compile it with &lt;code&gt;go build&lt;/code&gt;, then execute the resulting binary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interpreted Languages: Flexibility and Ease of Use
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;: Python, Ruby, JavaScript&lt;/p&gt;

&lt;p&gt;Interpreted languages are executed line by line by an interpreter. While generally slower than compiled languages, they offer greater flexibility and ease of use. You can run the code directly without a separate compilation step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Example of a simple Python script
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello, interpreted world!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script can be run directly with &lt;code&gt;python script.py&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hybrid Languages: The Best of Both Worlds?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;: Java, C#&lt;/p&gt;

&lt;p&gt;Hybrid languages are compiled into an intermediate bytecode, which is then interpreted or just-in-time compiled by a virtual machine. This approach aims to balance the performance benefits of compilation with the flexibility of interpretation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example of a simple Java program&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloWorld&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, hybrid world!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would be compiled to bytecode with &lt;code&gt;javac HelloWorld.java&lt;/code&gt;, then run with &lt;code&gt;java HelloWorld&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The New Generation: Blurring the Lines
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: TypeScript&lt;/p&gt;

&lt;p&gt;Modern languages like TypeScript are blurring the traditional boundaries. TypeScript adds features like type annotations to JavaScript but needs to be compiled down to JavaScript to run.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// TypeScript example&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, TypeScript world!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would be compiled to JavaScript before running in a browser or Node.js environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Build Process: Assembling Your Software LEGO
&lt;/h3&gt;

&lt;p&gt;Just as building with LEGO involves following a set of instructions to assemble bricks into a cohesive structure, software building follows a process to transform source code into a functioning application. Let's break down the key steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Preprocessing&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Gather all necessary pieces (source files, dependencies)&lt;/li&gt;
&lt;li&gt;Prepare the build environment&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compilation&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Translate source code to object code or bytecode&lt;/li&gt;
&lt;li&gt;Check for syntax errors and type mismatches&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linking&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Connect all the compiled pieces together&lt;/li&gt;
&lt;li&gt;Resolve references between different parts of the code&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Packaging&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Create the final executable or distributable package&lt;/li&gt;
&lt;li&gt;May include bundling assets, creating installers, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3. Build Tools and Dependency Management: The Right Tools for the Job
&lt;/h3&gt;

&lt;p&gt;Different programming ecosystems have developed specialized tools to manage the build process and handle dependencies. Here's a quick overview of some popular ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Make&lt;/strong&gt;: A classic tool for C/C++ projects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maven/Gradle&lt;/strong&gt;: Popular for Java projects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm/yarn/webpack/vite&lt;/strong&gt;: Common in JavaScript ecosystems&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go build&lt;/strong&gt;: Go's built-in build command&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these tools aims to streamline the build process, making it more efficient and less error-prone.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Cross-Compilation: Building for Different Targets
&lt;/h3&gt;

&lt;p&gt;Cross-compilation allows developers to build executables for different architectures or operating systems than the one they're working on. This is crucial for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developing mobile apps on desktop computers&lt;/li&gt;
&lt;li&gt;Creating software for IoT devices&lt;/li&gt;
&lt;li&gt;Ensuring software compatibility across different OS versions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, at Soundcast, I was compiling Go on a Mac using the following command to build for a Linux system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;GOOS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;linux &lt;span class="nv"&gt;GOARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;amd64 go build main.go

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Optimization: Fine-tuning Performance
&lt;/h3&gt;

&lt;p&gt;Build processes often include optimization steps to improve the performance of the resulting software. These can include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compile-time optimizations (e.g., dead code elimination)&lt;/li&gt;
&lt;li&gt;Link-time optimizations&lt;/li&gt;
&lt;li&gt;Profile-guided optimizations based on runtime data&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Software building is a crucial step in transforming source code into executable programs.&lt;/li&gt;
&lt;li&gt;Different language types (compiled, interpreted, hybrid) have different build processes.&lt;/li&gt;
&lt;li&gt;The build process typically involves preprocessing, compilation, linking, and packaging.&lt;/li&gt;
&lt;li&gt;Modern build tools and dependency management systems have greatly simplified the process.&lt;/li&gt;
&lt;li&gt;Cross-compilation and optimization are advanced techniques that can enhance software portability and performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Ever-Evolving Landscape of Software Building
&lt;/h2&gt;

&lt;p&gt;As we've seen, the world of software building is rich with complexity and constantly evolving. From the early days of manual compilation and dependency management to today's containerized build environments and automated processes, the field has come a long way.&lt;/p&gt;

&lt;p&gt;In my day-to-day work, I now leverage containers for both production and development environments. Combined with powerful package management tools like NPM, these modern approaches have transformed what was once a cumbersome process into a streamlined, efficient part of the development workflow.&lt;/p&gt;

&lt;p&gt;As we continue this series, we'll delve deeper into specific build techniques, explore the impact of containerization, and look at how different programming languages approach the build process. Stay tuned for the next installment, where we'll focus on building in Go and TypeScript environments.&lt;/p&gt;

&lt;p&gt;I invite you to share your own experiences with software building in the comments below. What challenges have you faced? What tools or techniques have you found most helpful? Your insights could be invaluable to fellow developers navigating this complex landscape.&lt;/p&gt;

&lt;p&gt;Don't forget to subscribe and follow to catch the next part of this series. Until then, happy building!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Effective CI: A Comprehensive Guide</title>
      <dc:creator>Guillaume Dormoy</dc:creator>
      <pubDate>Mon, 16 Sep 2024 08:36:52 +0000</pubDate>
      <link>https://forem.com/gdsources/effective-ci-a-comprehensive-guide-1g4f</link>
      <guid>https://forem.com/gdsources/effective-ci-a-comprehensive-guide-1g4f</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7pgp52ym9sjso48t3dir.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7pgp52ym9sjso48t3dir.png" alt="Image description" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction: The Tale of Two CIs
&lt;/h2&gt;

&lt;p&gt;As a software developer and manager, I've experienced the highs and lows of working with different Continuous Integration (CI) systems. Let me share two contrasting stories that shaped my understanding of what makes an effective CI.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Nightmare
&lt;/h3&gt;

&lt;p&gt;I once worked on a monorepo project with a massive codebase. When I first arrived, the CI system was manageable, but after months of development, feature additions, and more code and tests, it became a burden. I was leading the development team but hadn’t closely monitored how long the CI process was taking—until one day, a developer mentioned that one of his daily frustrations was waiting 40 minutes just to see his tests fail. (I spoke with this team recently and they managed to reduce it to about 10 minutes with several optimisations.)&lt;/p&gt;

&lt;p&gt;This significant time loss impacted our productivity. Developers tried to work on other tasks while waiting for the CI, but it caused frequent context-switching, delayed code reviews, and introduced inefficiencies. In short, it was a nightmare.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Dream
&lt;/h3&gt;

&lt;p&gt;On the other hand, I once worked with a CI system so smooth that we forgot it was even there. It was fast, reliable, and delivered feedback in under five minutes. Our tests gave us confidence in the code, and code reviews were effortless. Deployments were so seamless they felt almost like cheating.&lt;/p&gt;

&lt;p&gt;At the time, I was no stranger to CI pipelines, having built a few for personal projects and contributed to some at my previous jobs. However, seeing a team prioritize and maintain such a well-functioning CI pipeline changed my entire perspective on its importance.&lt;/p&gt;

&lt;p&gt;These two experiences made me realize that an effective CI isn't just a nice-to-have—it's a game-changer that can dramatically improve code quality, team productivity, and overall project success. In hindsight, I view the nightmare scenario as a personal leadership failure for not addressing the CI issues sooner.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Anatomy of an Effective CI Pipeline
&lt;/h2&gt;

&lt;p&gt;Now, let's break down the key components of an effective CI pipeline and explore how to optimize each stage.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Code Commit and Version Control
&lt;/h3&gt;

&lt;p&gt;There’s a reason most version control systems now integrate CI tools. I was even surprised it took GitHub so long to introduce GitHub Actions. You can’t have continuous integration without a proper version control system, and the workflow you adopt is just as important.&lt;/p&gt;

&lt;p&gt;A poorly designed workflow can result in a messy history, merge conflicts, and large, unmanageable commits that make review and integration difficult. A good version control system keeps the codebase clean, with a clear history. But how can teams ensure it stays that way?&lt;/p&gt;

&lt;p&gt;The answer lies in adopting a well-defined workflow. For many of the projects I've worked on, the &lt;a href="https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow" rel="noopener noreferrer"&gt;GitFlow&lt;/a&gt; workflow has been particularly effective. One often overlooked aspect is commit messages—many developers (myself included) tend to neglect their importance. However, clear commit messages provide valuable context to reviewers, resulting in faster and better feedback. Fortunately, AI tools can now help with writing clear commit messages.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Build Automation
&lt;/h3&gt;

&lt;p&gt;Remember my nightmare? I can honestly say, "never again." Automated builds ensure your code is compiled and packaged consistently across environments.&lt;/p&gt;

&lt;p&gt;Now, imagine a world where builds take 50 minutes and occasionally break due to connectivity issues. Horrible, right?&lt;/p&gt;

&lt;p&gt;To avoid this, several strategies can be applied. Containerization helps maintain consistent build environments, and you can run these images locally. Caching strategies can also be employed to prevent pulling unnecessary dependencies for every build.&lt;/p&gt;

&lt;p&gt;For monolithic codebases, tools like &lt;a href="https://nx.dev/" rel="noopener noreferrer"&gt;NX&lt;/a&gt; allow you to split your build process into smaller parts, enabling parallel builds or selective builds of only the required sections of your code. This significantly improves build times.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Automated Testing
&lt;/h3&gt;

&lt;p&gt;Automated tests are critical for catching bugs early, providing confidence in code changes, and acting as living documentation for expected behavior. They verify that code changes don’t break existing functionality and ensure requirements are met.&lt;/p&gt;

&lt;p&gt;For tests to be effective, they need to be both fast and reliable. Flaky tests—tests that sometimes fail due to external factors—can be frustrating. I've dealt with intermittent test failures caused by improper date handling, but fortunately, they were easy to fix.&lt;/p&gt;

&lt;p&gt;Early in my career, I thought unit tests were a waste of time because they didn’t validate database assertions. So, I focused on integration and end-to-end tests. While useful, these tests are often slow. Slow tests delay feedback, which slows everything down. Now, I prioritize unit tests with larger scopes (typically at the layer level), which allows for faster, more effective pipelines. I still use integration and end-to-end tests, but they serve as circuit breakers during staging rather than being the primary feedback loop.&lt;/p&gt;

&lt;p&gt;Running tests in parallel is another great way to reduce execution time.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Code Quality Checks
&lt;/h3&gt;

&lt;p&gt;Maintaining consistent coding standards and adhering to best practices improves code readability and maintainability. This is why enforcing coding standards and catching issues before they hit production is crucial, especially in today's AI-driven world.&lt;/p&gt;

&lt;p&gt;Static code analysis tools like Sonar and Snyk.io provide valuable insights into potential security threats in both your code and dependencies. Additionally, configuring your linter to automatically clean code based on your team's style guidelines helps keep the codebase tidy.&lt;/p&gt;




&lt;p&gt;Stopping here gives you a decent pipeline, but we can go even further with the delivery.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Artifact Generation and Storage
&lt;/h3&gt;

&lt;p&gt;Artifacts, such as compiled binaries and container images, should be consistently built and easily accessible for deployment. Rebuilding the same code repeatedly is wasteful.&lt;/p&gt;

&lt;p&gt;The goal is to produce and store versioned artifacts that can be deployed to any environment, with differences handled through environment variables.&lt;/p&gt;

&lt;p&gt;In the "dream" scenario, we had artifacts for previous versions readily available, allowing us to quickly roll back when production issues occurred. Since deployment was fast, we could buy time to fix the problem without disrupting service.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Staging Deployment
&lt;/h3&gt;

&lt;p&gt;A staging environment provides a final opportunity to catch issues before they reach production. I mentioned earlier that this is where I run end-to-end tests. Staging should closely mirror production, and automating its setup is essential.&lt;/p&gt;

&lt;p&gt;Infrastructure-as-code tools like Terraform or Pulumi can help ensure staging environments are accurate reflections of production. Another key aspect is ensuring data consistency. Companies often struggle with staging environments because of poor or outdated data. Implementing data processing pipelines to anonymize production data can create a relevant dataset for testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Production Deployment
&lt;/h3&gt;

&lt;p&gt;The ultimate goal of CI is to deliver value to end-users quickly and reliably. A CI pipeline wouldn’t be effective if it didn’t provide a safe and efficient way to release features and fixes to production.&lt;/p&gt;

&lt;p&gt;Manual deployment slows everything down, and the pressure to get it right can lead to mistakes. Automating deployment processes within the CI pipeline mitigates these risks. With versioned artifacts ready for deployment, rolling back to a stable state is simple and stress-free.&lt;/p&gt;

&lt;p&gt;This is the part I loved most about working on the "Dream" project—stress-free releases, knowing I could easily roll back if something went wrong.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion: Continuous Improvement in Continuous Integration
&lt;/h2&gt;

&lt;p&gt;An effective CI pipeline is not a "set it and forget it" solution. It requires ongoing attention, optimization, and adaptation to meet the evolving needs of your project and team. By focusing on each stage of the pipeline and continuously seeking improvements, you can create a CI system that not only integrates code but also empowers your team to deliver high-quality software confidently.&lt;/p&gt;

&lt;p&gt;The ultimate goal of CI is to enhance collaboration, boost productivity, and deliver better software to your users. With a well-crafted CI pipeline, you can turn the nightmare of uncertain deployments into a dream of smooth, reliable releases.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>ci</category>
      <category>cicd</category>
    </item>
  </channel>
</rss>
