<?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: Dantis Mai</title>
    <description>The latest articles on Forem by Dantis Mai (@maithanhdanh).</description>
    <link>https://forem.com/maithanhdanh</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%2F326173%2F19ffbfc4-0dfa-4ac8-91f3-e711ce325509.png</url>
      <title>Forem: Dantis Mai</title>
      <link>https://forem.com/maithanhdanh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/maithanhdanh"/>
    <language>en</language>
    <item>
      <title>Postgres organizes Indexes</title>
      <dc:creator>Dantis Mai</dc:creator>
      <pubDate>Sat, 03 Sep 2022 17:16:13 +0000</pubDate>
      <link>https://forem.com/maithanhdanh/postgres-indexing-glp</link>
      <guid>https://forem.com/maithanhdanh/postgres-indexing-glp</guid>
      <description>&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;h3&gt;
  
  
  what is Index?
&lt;/h3&gt;

&lt;p&gt;The index is a &lt;strong&gt;datatype&lt;/strong&gt;, &lt;strong&gt;separated&lt;/strong&gt; from our data from the table. It likes a map of locations of data that points to a value located in which page on heap &lt;strong&gt;AND&lt;/strong&gt; row id (for Postgres, it is tupleId). Heap is a table of our data with its page after another.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(index value) =&amp;gt; (Page, rowId)
(index value) =&amp;gt; (Page, rowId)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Page
&lt;/h3&gt;

&lt;p&gt;At first, I thought when we make a query to get a single row, it just fetches that single row for us. Actually, it will &lt;strong&gt;fetch the whole page&lt;/strong&gt; that contained our row from the heap, then collect and return the row we want. For each page, we call it an I/O. &lt;strong&gt;So the performance of our query depends on how many pages the DB fetches&lt;/strong&gt;. In case each row of data contains a huge string or a lot of columns, then a page will include fewer rows, and then we will need more IO, so the performance of our query will decrease.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clustered Index
&lt;/h3&gt;

&lt;p&gt;Sometimes, we may hear about &lt;strong&gt;Clustered index&lt;/strong&gt;. When we define a column as a clustered index, the table now will &lt;strong&gt;organize around that key&lt;/strong&gt;. In case a new row is added to the table, the row will be added to the location on the heap that follows the index order. For example, we have a user table below with the id column is uuid, and &lt;strong&gt;priority_level&lt;/strong&gt; is a clustered index. Although, we all see the rows ordered Dantis &amp;gt; Vu &amp;gt; Ngan &amp;gt; John, the actual order in the heap is Dantis &amp;gt; Ngan &amp;gt; Vu &amp;gt; John.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;name&lt;/th&gt;
&lt;th&gt;priority_level&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;awes&lt;/td&gt;
&lt;td&gt;Dantis&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zwqe&lt;/td&gt;
&lt;td&gt;Vu&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tydb&lt;/td&gt;
&lt;td&gt;Ngan&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mnbv&lt;/td&gt;
&lt;td&gt;John&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Clustered index is really beneficial when we perform a &lt;strong&gt;range query&lt;/strong&gt;, like getting all users that are older than 90 with column age is a clustered index. The DB just need to find the start page and the end page, then fetch all of them.&lt;/p&gt;

&lt;p&gt;However, in &lt;strong&gt;Postgres&lt;/strong&gt;, we just have an eventually clustered database. Because even if we create a clustered index for our table, then a new row comes, &lt;strong&gt;Postgres does not guarantee that the row will be followed our order&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Organizing Indexes (Postgres vs Mysql)
&lt;/h2&gt;

&lt;p&gt;For Postgres, we still can do that, but actually, those indexes are all &lt;strong&gt;secondary indexes&lt;/strong&gt;. Different from other RDBMS, all indexes will point directly to the heap. So, you may ask where is the primary index, Postgres uses that for &lt;strong&gt;tupleId&lt;/strong&gt; (it likes rowId) to manage the data.&lt;/p&gt;

&lt;p&gt;For MySQL, we can create both &lt;strong&gt;primary index&lt;/strong&gt; and &lt;strong&gt;secondary index&lt;/strong&gt;, then &lt;strong&gt;the primary index will point to the heap&lt;/strong&gt;, and &lt;strong&gt;the secondary index will point to the primary one&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Because of that design, Postgres and Mysql have their own behaviors when querying, inserting, and updating (or deleting) a row. Basically, they are around the idea that &lt;strong&gt;the index needs to be aware of any change related to it&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Querying
&lt;/h3&gt;

&lt;p&gt;Because Postgres point the index directly to the heap, the DB just needs to &lt;strong&gt;use an index scan or another heap scan to get our targeted row&lt;/strong&gt;. Meanwhile, Mysql will perform 2 index scans on the secondary index and the primary index. So, Postgres can process just a little bit faster than Mysql.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inserting
&lt;/h3&gt;

&lt;p&gt;For inserting, Postgres and Mysql do the same thing that they need to &lt;strong&gt;update all the existing indexes to make those indexes aware of the new row coming&lt;/strong&gt;. For example, if our table has 10 indexes, then the table needs to perform 10 updates. That is the problem when we have too many indexes in a table.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating (Deleting) &lt;em&gt;This is the most interesting part&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;When updating a row, instead of changing the data, Postgres &lt;strong&gt;create a new row&lt;/strong&gt; from the original data with the changes and a new tupleId, then it &lt;strong&gt;points all the indexes to that new row&lt;/strong&gt;. You may ask about the old tupleId &lt;em&gt;(dead tuple)&lt;/em&gt;. Postgres uses that to revert a transaction, but then if we forget to clean up those dead tuples, they will take a large resource for nothing. That is why we need the 'vacuum', not to free our memory but to reuse it.&lt;/p&gt;

&lt;p&gt;For Mysql, the thing is quite more simple. it just needs to update the primary and the related index if necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Datatype
&lt;/h2&gt;

&lt;p&gt;The problem of the index datatype mostly comes from the randomness of the data. In case our index is &lt;strong&gt;Sequential data&lt;/strong&gt;, when we create or update a row, it is easy for the DB to locate the next location on the heap for the row. In addition, B-tree ,which is the most popular index datatype by default, is also need that sequential. Because it takes a lot of step to re-balance the structure. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://paypal.me/DantisMai"&gt;Paypal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I am really happy to receive your feedback on this article. Thanks for your precious time reading this.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>postgres</category>
      <category>indexes</category>
    </item>
    <item>
      <title>Enhance Logger Using Inversify Context, Decorators, and Reflect-metadata</title>
      <dc:creator>Dantis Mai</dc:creator>
      <pubDate>Sat, 19 Feb 2022 11:15:08 +0000</pubDate>
      <link>https://forem.com/maithanhdanh/enhance-logger-using-inversify-context-and-decorators-2gbe</link>
      <guid>https://forem.com/maithanhdanh/enhance-logger-using-inversify-context-and-decorators-2gbe</guid>
      <description>&lt;p&gt;Generally, Log is a footprint of a system, it tells us about the state of the service at a moment. With it, in case there is an issue on the server, we can trace the root cause.&lt;/p&gt;

&lt;p&gt;Nowadays, the logger is an important feature for any service, either small or big. However, we shouldn't write too much or too few records, that will lead to overwhelming or not enough information. Besides, those records need to follow the same format within a codebase.&lt;/p&gt;

&lt;p&gt;In this post, we will discuss how to enhance them by using &lt;strong&gt;inversify context&lt;/strong&gt; and &lt;strong&gt;Decorators&lt;/strong&gt;. The logger package used is &lt;a href="https://www.npmjs.com/package/winston" rel="noopener noreferrer"&gt;winston&lt;/a&gt;, and the below code I used to create log group&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const logger = LoggerWrapper();

export const createChildLogger = (messagePrefix: string): Logger =&amp;gt;
  Object.create(logger, {
    write: {
      value(info) {
        info.message = `[${messagePrefix}] ${info.message}`;
        logger.write(info);
      },
    },
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Inversify and Its Context
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A powerful and lightweight &lt;strong&gt;inversion of control (IoC)&lt;/strong&gt; container&lt;br&gt;
for JavaScript &amp;amp; Node.js apps powered by TypeScript&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We already talk about how to break the dependencies by IoC in &lt;a href="https://dev.to/maithanhdanh/applying-domain-driven-design-in-developing-software-4ld0"&gt;this post&lt;/a&gt;, the Inversify are made in order to help us follow IoC rule.&lt;/p&gt;

&lt;p&gt;We can create a Logger component bind to our container, and use &lt;code&gt;toDynamicValue&lt;/code&gt; API to create a logger instance for each other components. The input argument for the API is &lt;code&gt;context&lt;/code&gt;, it represents the called component and all its dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const getClassNameFromRequest = (context: interfaces.Context) =&amp;gt;
  (context.currentRequest.parentRequest &amp;amp;&amp;amp;
    context.currentRequest.parentRequest.bindings.length &amp;amp;&amp;amp;
    context.currentRequest.parentRequest.bindings[0].implementationType &amp;amp;&amp;amp;
    (context.currentRequest.parentRequest.bindings[0].implementationType as any)
      .name) ||
  'Undefined';

container
    .bind&amp;lt;Logger&amp;gt;(types.Logger)
    .toDynamicValue((context: interfaces.Context) =&amp;gt; {
      const namedMetadata = getClassNameFromRequest(context);
      return createChildLogger(namedMetadata);
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we are here, let say we have a below service to get service info. Then whenever we call the request, a logger instance will be created for &lt;code&gt;ServiceInfoServiceImpl&lt;/code&gt;, and the className will be added to the logger message. &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw2ci2dm9ubnghv8ux6iw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw2ci2dm9ubnghv8ux6iw.png" alt="controller-layer"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F377xd78674o1rcykjuo6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F377xd78674o1rcykjuo6.png" alt="application-layer"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgve2jkzklkwhnuo22tup.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgve2jkzklkwhnuo22tup.png" alt="log-result"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;h2&gt;
  
  
  Decorators
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Decorators are a stage 2 proposal for JavaScript and are &amp;gt;available as an experimental feature of TypeScript.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Decorator is farmiliar concept for Java, C++, and so on. But it is just a experiment feature of Typescript. According to &lt;a href="https://www.typescriptlang.org/docs/handbook/decorators.html" rel="noopener noreferrer"&gt;TS documentation&lt;/a&gt;, we must to endable &lt;strong&gt;experimentalDecorators&lt;/strong&gt; compiler option to use Decorator.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftkskyv560fr9lze1cx77.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftkskyv560fr9lze1cx77.png" alt="enable-option"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The goal of using decorator is the same with &lt;strong&gt;Inversify&lt;/strong&gt;, which is creating and customizing logger property for each class. Because the &lt;strong&gt;logger&lt;/strong&gt; is a property of a class so we need to use &lt;strong&gt;class decorator&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function classDecorator&amp;lt;T extends { new (...args: any[]): {} }&amp;gt;(constructor: T) {
  return class extends constructor {
    logger = createChildLogger(constructor.name);
  };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The class decorator will overide the class constructor, so we need to define a &lt;code&gt;logger&lt;/code&gt; property, and be careful with other constructor params.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpzm1i3yc5f6pc6l6dif2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpzm1i3yc5f6pc6l6dif2.png" alt="class-decorator"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs9p4u1r1dw6uj26n28x9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs9p4u1r1dw6uj26n28x9.png" alt="log-result"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Dive Deeper
&lt;/h2&gt;
&lt;h3&gt;
  
  
  what if we also need called method?
&lt;/h3&gt;

&lt;p&gt;It will look like &lt;code&gt;[className] [methodName] message ...&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I already tried &lt;em&gt;method and property decorators&lt;/em&gt;, but it didn't work well. The reason for this is that the decorators just run at the runtime, while the logger instance is still not created yet. &lt;/p&gt;

&lt;p&gt;After a lot of googling, I found &lt;a href="https://shusson.info/post/generic-logging-on-a-class-using-decorators-in-typescript" rel="noopener noreferrer"&gt;this post&lt;/a&gt;. That is a wonderful idea, I take that then modify &lt;code&gt;logger property&lt;/code&gt;, so I have what I need.&lt;/p&gt;

&lt;p&gt;However, because the solution change the original definition of the called method, I wonder about that, although I haven't faced any issue while using it. &lt;/p&gt;

&lt;p&gt;Ok, so how does it work??! The first thing we do is define &lt;code&gt;const originalMethod = descriptor.value;&lt;/code&gt;, the &lt;code&gt;originalMethod&lt;/code&gt; now belongs to the closure of our brand new &lt;code&gt;descriptor.value&lt;/code&gt;. Yes, it will work as its definition&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const createChildLogger = (messagePrefix: string,subPrefix?: string): Logger =&amp;gt;
  Object.create(logger, {
    write: {
      value(info) {
        info.message = `[${messagePrefix}]${subPrefix ? ` [${subPrefix}]` : ''} ${info.message}`;
        logger.write(info);
      },
    },
  });

export function logGroup() {
  return (target: any) =&amp;gt; {
    for (const propertyName of Object.getOwnPropertyNames(target.prototype)) {
      const descriptor = Object.getOwnPropertyDescriptor(
        target.prototype,
        propertyName,
      );
      if (!descriptor) {
        continue;
      }

      const originalMethod = descriptor.value;
      const isMethod = originalMethod instanceof Function;
      if (!isMethod) {
        continue;
      }

      descriptor.value = function (...args: any[]) {
        (this as any).logger = createChildLogger(target.name, propertyName);
        return originalMethod.apply(this, args);
      };

      Object.defineProperty(target.prototype, propertyName, descriptor);
    }
  };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; this class decorator doesn't work on the controller layer of Inversify&lt;/p&gt;

&lt;h3&gt;
  
  
  So, What if we need a prefix for a function outside of a class?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;The solution below just work on service that process one request at a time&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
Because the decorators just can work with class, whenever a method from a class calls a util function, the function will lose the context.&lt;/p&gt;

&lt;p&gt;When we install inversify, we always need a package called &lt;code&gt;reflect-metadata&lt;/code&gt;. Generally, it is like a global variable, but it just is applied to a specific target scope. you can take a look at &lt;a href="https://github.com/rbuckton/reflect-metadata" rel="noopener noreferrer"&gt;this repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The general idea is that we will store the caller &lt;code&gt;className&lt;/code&gt;, &lt;code&gt;methodName&lt;/code&gt; to the metadata of the logger property, then whenever we call an outside function, we structure the logger message using the context from metadata.&lt;/p&gt;

&lt;p&gt;First of all, we need a &lt;code&gt;customLogger&lt;/code&gt; as below and use it as the default logger. Then, we modify a few lines in our class decorator &lt;code&gt;logGroup&lt;/code&gt;, and container config. When an outside function calls &lt;code&gt;logger.debug&lt;/code&gt; or something, the new logger will check for the context then structure the message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgiscwykdz1929ds9hfwo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgiscwykdz1929ds9hfwo.png" alt="custom-logger"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fufaovmmkmyswaq6txu5t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fufaovmmkmyswaq6txu5t.png" alt="modified-logGroup"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ycc2k9rw94m7a34fip2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ycc2k9rw94m7a34fip2.png" alt="modified-container"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;h3&gt;
  
  
  Inversify context
&lt;/h3&gt;

&lt;p&gt;As mentioned above, the &lt;strong&gt;Inversify Context&lt;/strong&gt; show us the connection between the called component with its dependencies. we can use the code below to get it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const getContextName = (node : interfaces.Request | null):string =&amp;gt; 
  (node?.bindings[0].implementationType as any).name

export const getContextTree = (context:interfaces.Context): string[] =&amp;gt; {
  let node = context.currentRequest.parentRequest
  const listNode = [];

  while(node){
    listNode.unshift(getContextName(node));
    node = node.parentRequest;
  }

  return [... new Set(listNode)];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then call it in api &lt;code&gt;onACtivation&lt;/code&gt; or in creating logger instance when initilize container&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  container
    .bind&amp;lt;Logger&amp;gt;(types.Logger)
    .toDynamicValue((context: interfaces.Context) =&amp;gt; {
      const namedMetadata = getClassNameFromRequest(context);
      const listNode = getContextTree(context);
      console.log(listNode);
      return createChildLogger(namedMetadata);
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  container
    .bind&amp;lt;ServiceInfoService&amp;gt;(types.Service.SERVICE_INFO)
    .to(ServiceInfoServiceImpl)
    .onActivation((context: interfaces.Context, service: ServiceInfoService) =&amp;gt; {
      const listNode = getContextTree(context);
      console.log(listNode)
      return service
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To be honest, I still don't have any idea for that &lt;code&gt;listTree&lt;/code&gt;, just collect them then be proud of myself 🤣.&lt;/p&gt;

&lt;h2&gt;
  
  
  Play Around
&lt;/h2&gt;

&lt;p&gt;We can use this &lt;a href="https://www.npmjs.com/package/typescript-maker" rel="noopener noreferrer"&gt;npm package&lt;/a&gt; to init inversify project with build in the logger above, just install it then run the command below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;typescript-maker init -ioc test-repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://paypal.me/DantisMai" rel="noopener noreferrer"&gt;Paypal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I am really happy to receive your feedback on this article. Hope you have fun with it. Thanks for your precious time reading this.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>inversify</category>
      <category>decorator</category>
      <category>logger</category>
      <category>reflectmetada</category>
    </item>
    <item>
      <title>Create New Project Using NPM package</title>
      <dc:creator>Dantis Mai</dc:creator>
      <pubDate>Mon, 03 Jan 2022 16:37:16 +0000</pubDate>
      <link>https://forem.com/maithanhdanh/create-new-project-using-npm-package-1cgf</link>
      <guid>https://forem.com/maithanhdanh/create-new-project-using-npm-package-1cgf</guid>
      <description>&lt;p&gt;In the last article, we can create a new project by using &lt;a href="https://dev.to/maithanhdanh/create-express-typescript-boilerplate-3gf"&gt;Express Typescript Boilerplate&lt;/a&gt; template, it saves us pretty much time to do it from scratch. However, it is still not the best, we can optimize it using &lt;strong&gt;NPM&lt;/strong&gt; and just 1 command line, we get everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup account
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;we will need an account in &lt;a href="https://www.npmjs.com/" rel="noopener noreferrer"&gt;npm&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Login our account on our pc&lt;/li&gt;
&lt;li&gt;After that, we update our profile by access &lt;strong&gt;profile &amp;gt; edit profile&lt;/strong&gt;. There are 2 things we need to pay attention &lt;strong&gt;GitHub Username&lt;/strong&gt; and &lt;strong&gt;Email&lt;/strong&gt;, they will cause some problems when publishing a package. For example, after running command &lt;code&gt;npm publish&lt;/code&gt;, it returns &lt;code&gt;403 Forbidden - You do not have permission to publish. Are you logged in as the correct user?&lt;/code&gt;. In case that we can fix it by changing email to whatever, then revert it back to our main email.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setup project
&lt;/h2&gt;

&lt;p&gt;If we config npm account successfully, just running &lt;code&gt;npm publish&lt;/code&gt;, then we will see the log below&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftp830d1xb47zpipnlpl4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftp830d1xb47zpipnlpl4.png" alt="publishing successfully"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then it will be shown on our npm packages, and the other developer can reach to &lt;a href="https://www.npmjs.com/package/typescript-maker" rel="noopener noreferrer"&gt;the package&lt;/a&gt; also&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64r9i4aiykzwh3jb28w1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64r9i4aiykzwh3jb28w1.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to make our package more reliable, we should enable &lt;code&gt;security&lt;/code&gt;. If there is any issue Github will show us as below.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftj5p3h8qpasy1m14cgdi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftj5p3h8qpasy1m14cgdi.png" alt="security issue"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Otherwise, it will be green.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fry8j4rqrrk7aiyctrzej.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fry8j4rqrrk7aiyctrzej.png" alt="green security"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Config command
&lt;/h2&gt;

&lt;p&gt;In this post, we will use our &lt;a href="https://dev.to/maithanhdanh/create-express-typescript-boilerplate-3gf"&gt;last template&lt;/a&gt; as source code for the npm package. And below is my &lt;code&gt;package.json&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "typescript-maker",
  "version": "1.1.1",
  "description": "Minimalistic boilerplate to quick-start Node.js development in TypeScript.",
  "engines": {
    "node": "&amp;gt;=14 &amp;lt;15"
  },
  "bin": {
    "typescript-maker": "./bin/generateApp.js"
  },
  "scripts": {
    "start": "node src/index",
    "dev": "nodemon --config restart.json",
    "clean": "rm -rf coverage build tmp",
    "prebuild": "npm run lint",
    "build": "tsc -p tsconfig.build.json",
    "build:watch": "tsc -w -p tsconfig.build.json",
    "lint": "eslint . --ext .ts,.tsx",
    "test": "jest"
  },
  "author": "Dantis Mai",
  "license": "Apache-2.0",
  "dependencies": {
    "commander": "^8.3.0",
    "express": "^4.17.1",
    "module-alias": "^2.2.2",
    "tslib": "~2.3.0",
    "winston": "^3.3.3"
  },
  "devDependencies": {
    "@tsconfig/recommended": "^1.0.1",
    "@types/express": "^4.17.13",
    "@types/jest": "^26.0.24",
    "@types/node": "~14.14.45",
    "@typescript-eslint/eslint-plugin": "~4.28.2",
    "@typescript-eslint/parser": "~4.28.2",
    "dotenv": "^10.0.0",
    "eslint": "~7.30.0",
    "eslint-config-prettier": "~8.3.0",
    "eslint-plugin-jest": "~24.3.6",
    "jest": "^27.0.6",
    "jest-html-reporter": "^3.4.1",
    "nodemon": "^2.0.12",
    "prettier": "~2.3.2",
    "rimraf": "^3.0.2",
    "supertest": "^6.1.5",
    "ts-jest": "^27.0.3",
    "ts-node": "^10.2.0",
    "ts-node-dev": "^1.1.8",
    "tsconfig-paths": "^3.10.1",
    "tsutils": "~3.21.0",
    "typescript": "~4.3.5"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;package.json&lt;/code&gt; file, there are 3 fields, we need to update:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt;: npm package name. This name will be our &lt;strong&gt;npm package name&lt;/strong&gt;, ignoring the &lt;strong&gt;GitHub repository name&lt;/strong&gt;. For example, my repository name is &lt;code&gt;express-typescript-boilerplate&lt;/code&gt;, while the package name is &lt;code&gt;typescript-maker&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;version&lt;/strong&gt;: npm package version. By versioning, we can update the new features with backward compatibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;bin&lt;/strong&gt;: command configuration. We will direct the source code for the command. As you can see the &lt;code&gt;bin&lt;/code&gt; field in my &lt;code&gt;package.json&lt;/code&gt;, I define &lt;code&gt;"typescript-maker": "./bin/generateApp.js"&lt;/code&gt;, it means that &lt;code&gt;typescript-maker&lt;/code&gt; is the command name, and the options and arguments are described in &lt;code&gt;./bin/generateApp.js&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let jump to config our command.&lt;br&gt;
For a sample command, there are 4 steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verify arguments: verify the number of arguments to make sure, we have enough information.&lt;/li&gt;
&lt;li&gt;Parse arguments and options: get argument value from input&lt;/li&gt;
&lt;li&gt;Validate existing folder: prevent issues when creating a new folder or file. It will work like we clone a repository 2 times at the same directory. &lt;/li&gt;
&lt;li&gt;Define workflow: define what thing we gonna do when we call the command.&lt;/li&gt;
&lt;li&gt;Clear unused files: keep the result clean to not distract the user after running the command. &lt;/li&gt;
&lt;li&gt;Trigger workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Combine everything and we have a sample config for &lt;code&gt;typescript-maker&lt;/code&gt; below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Verify arguments
if (process.argv.length &amp;lt; 3) {
  console.log('You have to provide a name to your app.');
  console.log('For example :');
  console.log('    typescript-maker my-app');
  process.exit(1);
}

# Parse arguments and option
const projectName = process.argv[2];
const currentPath = process.cwd();
const projectPath = path.join(currentPath, projectName);
const git_repo = 'https://github.com/Maithanhdanh/express-typescript-boilerplate.git';

# Validate existing folder
try {
  fs.mkdirSync(appPath);
} catch (err) {
  if (err.code === 'EEXIST') {
    console.log('Directory already exists. Please choose another name for the project.');
  } else {
    console.log(error);
  }
  process.exit(1);
}

# define steps in workflow
async function main() {
  try {
    console.log('Downloading files...');
    execSync(`git clone --depth 1 ${git_repo} ${projectPath}`);


    // Change directory
    process.chdir(appPath);

    // Install dependencies
    const useYarn = await hasYarn();
    console.log('Installing dependencies...');
    if (useYarn) {
      await runCmd('yarn install');
    } else {
      await runCmd('npm install');
    }
    console.log('Dependencies installed successfully.');
    console.log();

    # Clean unused files
    console.log('Removing useless files');
    execSync('npx rimraf ./.git');
    fs.rmdirSync(path.join(projectPath, 'bin'), { recursive: true});

    console.log('The installation is done, this is ready to use !');

  } catch (error) {
    console.log(error);
  }
}

# trigger workflow
main();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In case we want a more complicated command, we can use module &lt;a href="https://www.npmjs.com/package/commander" rel="noopener noreferrer"&gt;commander&lt;/a&gt;, which supports us pretty much thing when we design the architecture of the command. After using the commander, I structure my command like &lt;a href="https://github.com/Maithanhdanh/express-typescript-boilerplate/blob/main/bin/generateApp.js" rel="noopener noreferrer"&gt;this&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;This is &lt;a href="https://www.npmjs.com/package/typescript-maker" rel="noopener noreferrer"&gt;mine&lt;/a&gt;, you can enjoy it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://paypal.me/DantisMai" rel="noopener noreferrer"&gt;Paypal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I am really happy to receive your feedback on this article. Thanks for your precious time reading this.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>npm</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Integrate Database Migration Using Flyway Into CI/CD</title>
      <dc:creator>Dantis Mai</dc:creator>
      <pubDate>Mon, 11 Oct 2021 18:30:09 +0000</pubDate>
      <link>https://forem.com/maithanhdanh/integrate-database-migration-using-flyway-into-ci-cd-241f</link>
      <guid>https://forem.com/maithanhdanh/integrate-database-migration-using-flyway-into-ci-cd-241f</guid>
      <description>&lt;p&gt;Practically, &lt;strong&gt;Database Migration&lt;/strong&gt; is changing the structure or data of a database, which includes some activities on the database, like create a table, update or insert data to a table. &lt;/p&gt;

&lt;p&gt;Without DB migration, if it is not establihsing new datbase, we need to consider whether the script has been run on the target DB or not. In case we accidentally re-run the script, it will causes duplicate records on the table for inserting data. That is one of reasons for manual deployment.&lt;/p&gt;

&lt;p&gt;With the development of CI/CD, there are a lot of great DB migration tools developed. In this post, I will use &lt;a href="https://flywaydb.org/"&gt;Flyway&lt;/a&gt; for &lt;strong&gt;CircleCI pipeline&lt;/strong&gt; to deploy on &lt;strong&gt;Heroku&lt;/strong&gt;, you can find their configurations in my &lt;a href="https://dev.to/maithanhdanh/ci-cd-pipeline-with-circleci-and-heroku-1j71"&gt;last article&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ideas
&lt;/h2&gt;

&lt;p&gt;We may use different platforms for DB migration, but overall they are just around the idea of generating the connection configuration from the connection string. In this session, I will realize that idea by using &lt;strong&gt;flyway&lt;/strong&gt; on &lt;strong&gt;Heroku PostgreSQL&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;Get the DB connection string using platform CLI&lt;/strong&gt;: For Heroku, it is &lt;code&gt;heroku config:get DATABASE_URL -a &amp;lt;APP_NAME&amp;gt;&lt;/code&gt;, then the console will print out &lt;code&gt;postgres://DB_USER:DB_PASSWORD@DB_HOST:5432/DB_NAME&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Extract DB user, password, host, name from connection string&lt;/strong&gt;: We may any technique to get that info out, in this article, I used &lt;code&gt;sed&lt;/code&gt;, &lt;code&gt;cut&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Generate a connection config for DB migration tool&lt;/strong&gt;: Depending on the DB migration tool, the config formats may be different. In this case, I created a config file like below. You may wonder about the &lt;strong&gt;locations&lt;/strong&gt;, and &lt;strong&gt;table&lt;/strong&gt;, they are SQL scripts directory for the former, and table for version control for the later.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flyway.url=jdbc:postgresql://DB_HOST/DB_NAME
flyway.locations=SQL_FILE_LOCATION
flyway.user=DB_USER
flyway.password=DB_PASSWORD
flyway.table=schema_history
flyway.outOfOrder=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Call DB migration tool CLI&lt;/strong&gt;: If we use flyway, the command will be &lt;code&gt;flyway -configFiles=&amp;lt;CONFIG_FILE_DIRECTORY&amp;gt; migrate&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Combine all things into a bash file&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Extract data from DB connection
export CONNECTION_URL="$(heroku config:get DATABASE_URL -a ${HEROKU_APP_NAME})"
export SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE}" )" &amp;amp;&amp;amp; pwd)"
export SQL_FILE_LOCATION="filesystem:/${SCRIPT_DIR}/migrations/scripts/sql"
export CONFIG_DIR="${SCRIPT_DIR}/migrations/config"
export DB_NAME="$(echo $CONNECTION_URL | sed "s|.*:5432/||")"
export DB_USER="$(echo $CONNECTION_URL | cut -d ":" -f 2 | sed "s|.*//||")"
export DB_PASSWORD="$(echo $CONNECTION_URL | cut -d ":" -f 3 | cut -d "@" -f 1)"
export DB_HOST="$(echo $CONNECTION_URL | cut -d ":" -f 3 | cut -d "@" -f 2)"

# Generate config file
sed -i -e "s|DB_HOST|${DB_HOST}|g" ${CONFIG_DIR}/flyway.conf
sed -i -e "s|DB_NAME|${DB_NAME}|g" ${CONFIG_DIR}/flyway.conf
sed -i -e "s|DB_USER|${DB_USER}|g" ${CONFIG_DIR}/flyway.conf
sed -i -e "s|DB_PASSWORD|${DB_PASSWORD}|g" ${CONFIG_DIR}/flyway.conf
sed -i -e "s|SQL_FILE_LOCATION|${SQL_FILE_LOCATION}|g" ${CONFIG_DIR}/flyway.conf

# Run flyway
flyway -configFiles=${CONFIG_DIR}/flyway.conf migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; This file should be run by the pipeline, but not manually. Because the information in the config file will change and lead to wrong information for the next run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrate DB migration to CI/CD
&lt;/h2&gt;

&lt;p&gt;Let re-use our CI/CD pipeline from the &lt;a href="https://dev.to/maithanhdanh/ci-cd-pipeline-with-circleci-and-heroku-1j71"&gt;last post&lt;/a&gt;. &lt;br&gt;
CirlceCI supports &lt;a href="https://circleci.com/docs/2.0/configuration-reference/#pre-steps-and-post-steps-requires-version-21"&gt;post-steps&lt;/a&gt;, which is the last part of the job. If &lt;code&gt;post-step&lt;/code&gt; is failed, the whole job will be marked as failed.&lt;br&gt;
Because CircleCI doesn't support &lt;strong&gt;flyway&lt;/strong&gt;, we need to install it independently by &lt;a href="https://flywaydb.org/documentation/usage/commandline/"&gt;command line&lt;/a&gt;. After installing flyway, we are good to call our bash file above to start the migration process.&lt;/p&gt;

&lt;p&gt;The pipeline config now will look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;orbs:
  node: circleci/node@4.1.0
  heroku: circleci/heroku@1.2.6

version: 2.1

commands:
  deploy-command:
    parameters:
      BRANCH:
        type: string
      HEROKU_APP_NAME:
        type: string
    steps:
      - run: heroku config:set YARN_PRODUCTION=false -a &amp;lt;&amp;lt;parameters.HEROKU_APP_NAME&amp;gt;&amp;gt;
      - heroku/deploy-via-git:
          app-name: &amp;lt;&amp;lt;parameters.HEROKU_APP_NAME&amp;gt;&amp;gt;
          branch: &amp;lt;&amp;lt;parameters.BRANCH&amp;gt;&amp;gt;

jobs:
  test:
    executor: node/default
    steps:
      - checkout
      - node/install-packages:
          cache-path: ~/project/node_modules
          override-ci-command: npm install
      - run: npm test

  deploy:
    executor: heroku/default
    steps:
      - checkout
      - heroku/install

      - when:
          condition:
            equal: [master, &amp;lt;&amp;lt; pipeline.git.branch &amp;gt;&amp;gt;]
          steps:
            - deploy-command:
                HEROKU_APP_NAME: production-server
                BRANCH: master

      - when:
          condition:
            equal: [staging, &amp;lt;&amp;lt; pipeline.git.branch &amp;gt;&amp;gt;]
          steps:
            - deploy-command:
                HEROKU_APP_NAME: staging-server
                BRANCH: staging

      - when:
          condition:
            equal: [develop, &amp;lt;&amp;lt; pipeline.git.branch &amp;gt;&amp;gt;]
          steps:
            - deploy-command:
                HEROKU_APP_NAME: develop-server
                BRANCH: develop

workflows:
  heroku_deploy:
    jobs:
      - test

      - deploy:
          requires:
            - test
          filters:
            branches:
              only:
                - master
                - develop
                - staging
          post-steps:
            - run: 
                name: install flyway
                command: wget -qO- https://repo1.maven.org/maven2/org/flywaydb/flyway-commandline/7.14.0/flyway-commandline-7.14.0-linux-x64.tar.gz | tar xvz &amp;amp;&amp;amp; sudo ln -s `pwd`/flyway-7.14.0/flyway /usr/local/bin
            - run: 
                name: run migration scripts
                command: sh migrations/scripts/migrations-run.sh
                environment:
                  GIT_BRANCH: &amp;lt;&amp;lt; pipeline.git.branch &amp;gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this new pipeline, you can see that I have the &lt;code&gt;environment&lt;/code&gt; part, which is used to declare &lt;strong&gt;environment variables&lt;/strong&gt;. We have totally 3 environments (develop, staging, production), so, with that variables, we can change &lt;code&gt;APP_NAME&lt;/code&gt; depending on &lt;code&gt;GIT_BRANCH&lt;/code&gt;. By adding the below condition at the very first of the bash script, the script will get the appropriate DB info for each environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if [ "$GIT_BRANCH" = "master" ]; then
  export HEROKU_APP_NAME=production-server
elif [ "$GIT_BRANCH" = "staging" ]; then
  export HEROKU_APP_NAME=staging-server
else
  export HEROKU_APP_NAME=develop-server
fi

# Extract data from DB connection ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://paypal.me/DantisMai"&gt;Paypal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I am really happy to receive your feedback on this article. Thanks for your precious time reading this.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>migration</category>
      <category>flyway</category>
      <category>cicd</category>
    </item>
    <item>
      <title>CI/CD Pipeline with CircleCI and Heroku</title>
      <dc:creator>Dantis Mai</dc:creator>
      <pubDate>Sat, 02 Oct 2021 18:13:42 +0000</pubDate>
      <link>https://forem.com/maithanhdanh/ci-cd-pipeline-with-circleci-and-heroku-1j71</link>
      <guid>https://forem.com/maithanhdanh/ci-cd-pipeline-with-circleci-and-heroku-1j71</guid>
      <description>&lt;h2&gt;
  
  
  Introduction to CircleCI
&lt;/h2&gt;

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

&lt;p&gt;&lt;a href="https://circleci.com" rel="noopener noreferrer"&gt;CircleCI&lt;/a&gt; is one of the greatest CI/CD platforms that helps a single developer or small team can quickly set up. CircleCI can be really flexible from a simple pipeline with build, test, and deploy to a complex one with caching, docker layer, and so on.&lt;/p&gt;

&lt;p&gt;After authenticating CircleCI with Github and register our repository, every integration will trigger the jobs. For a &lt;strong&gt;Free&lt;/strong&gt; plan, CircleCI provides us up to &lt;strong&gt;2500 credits per week&lt;/strong&gt;, I can try a lot of fun with that much.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to Heroku
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkxnc179jpg03hnvp7nqb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkxnc179jpg03hnvp7nqb.png" alt="heroku1"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.heroku.com" rel="noopener noreferrer"&gt;Heroku&lt;/a&gt; is a cloud service that allows developers to build and manage web services without getting headaches about configuration servers. We just need to focus on developing our product and let the other things for Heroku. Unlike other cloud services, Heroku computes bills by &lt;code&gt;dynos&lt;/code&gt;, which is a kind of a virtual machine that can auto-scale up or down depending on the size of our product.&lt;/p&gt;

&lt;p&gt;The biggest advantage of Heroku is Free within 550h per month, but still provides numerous addons like Database, SSL, and so on. Besides, it also supports Nodejs, Python, Java, Go, .... Heroku will be a great choice to test an idea, or hosting a small website, for me, I host my portfolio there.&lt;/p&gt;
&lt;h2&gt;
  
  
  Make it work
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Authenticate CircleCI with GitHub
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;First of all, we need to have a &lt;strong&gt;pipeline config in our repository&lt;/strong&gt;, otherwise, CircleCI won't allow us to go further. This &lt;a href="https://circleci.com/docs/" rel="noopener noreferrer"&gt;documenttation&lt;/a&gt; will help to config our own pipeline. Once finishing the pipeline in the directory &lt;code&gt;.circleci/config.yml&lt;/code&gt; and pushing it to GitHub, we are ready to go. I will show you my pipeline below.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After &lt;a href="https://circleci.com/signup/" rel="noopener noreferrer"&gt;sign up&lt;/a&gt; CircleCI by Github account, we can see all repositories listed out in the middle panel. By clicking &lt;strong&gt;set up project&lt;/strong&gt;, CircleCI will scan the pipeline config in the repository, because we have already done the first step, it will let us go, otherwise, the guard will ask us to create one. &lt;strong&gt;set up project&lt;/strong&gt; will be toggled to &lt;strong&gt;unfollow project&lt;/strong&gt;, if the scanning is successful, and CircleCI will lead us to a dashboard of the project.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

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

&lt;p&gt;Now, we can try to commit a small change. In case the pipeline is triggered, &lt;strong&gt;congratulation!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; CircleCI editor supports pretty well for creating, as well as debugging pipelines. I always use it, and I hope that it also can help you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frlr7qr76jr49zcjlp0po.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frlr7qr76jr49zcjlp0po.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Authenticate Heroku with GitHub, and CircleCI
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt; From the top right corner, we can access &lt;strong&gt;account setting&lt;/strong&gt; by clicking our avatars, then come to &lt;strong&gt;Applications &amp;gt; Third-party Services&lt;/strong&gt;. This step just helps Heroku can interact with GitHub, but not each repository.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frx4krkzoy1pe7fxqh2jt.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frx4krkzoy1pe7fxqh2jt.PNG" alt="Capture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Every time we create a new app, we need to choose &lt;strong&gt;Deployment method&lt;/strong&gt;, this way will help Heroku can use GitHub as a &lt;strong&gt;Version Control&lt;/strong&gt;. There are 2 more steps needed to be done:

&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;App connected to GitHub:&lt;/strong&gt; reach to the repository that we want to deploy&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Automatic deploys:&lt;/strong&gt; For every integration to the chosen branch, the new code will be deployed. In case we have already had CI for the app, we tick the option &lt;strong&gt;Wait for CI to pass before deploy&lt;/strong&gt;. And don't forget to &lt;strong&gt;Enable Automatic Deploys&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After a lot of configuration, let click on &lt;strong&gt;Deploy Branch&lt;/strong&gt; in the &lt;strong&gt;Manual deploy&lt;/strong&gt; session. To validate it is successful or not, we can check the status of the deployment appeared here. If successful, the &lt;strong&gt;Environments&lt;/strong&gt; session of the repository on &lt;strong&gt;GitHub&lt;/strong&gt; will list out the Heroku app name.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvf65v60y0fdzbwei8le0.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvf65v60y0fdzbwei8le0.PNG" alt="Capture"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To let CircleCI pipeline can deploy to Heroku, we need to 2 things, they are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;API Key:&lt;/strong&gt; This key is really important and we'd better let no one know it. With the key, authenticated CircleCI pipelines can process deployment to Heroku. In &lt;strong&gt;Project Settings&lt;/strong&gt;, We can set it by adding a new &lt;strong&gt;Environment Variables&lt;/strong&gt; with key name &lt;strong&gt;HEROKU_API_KEY&lt;/strong&gt;, and the value will be placed in &lt;strong&gt;Account Settings &amp;gt; Account &amp;gt; API Key&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;App name:&lt;/strong&gt; This key is the target app name needed to be deployed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fof2fvgh4yxpc1h0sghav.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fof2fvgh4yxpc1h0sghav.PNG" alt="Capture"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Config pipeline
&lt;/h3&gt;

&lt;p&gt;Below is pipeline for CircleCI and NodeJS platform to deploy to Heroku.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;orbs:
  node: circleci/node@4.1.0
  heroku: circleci/heroku@1.2.6

version: 2.1

commands:
  deploy-command:
    parameters:
      BRANCH:
        type: string
      HEROKU_APP_NAME:
        type: string
    steps:
      - run: heroku config:set YARN_PRODUCTION=false -a &amp;lt;&amp;lt;parameters.HEROKU_APP_NAME&amp;gt;&amp;gt;
      - heroku/deploy-via-git:
          app-name: &amp;lt;&amp;lt;parameters.HEROKU_APP_NAME&amp;gt;&amp;gt;
          branch: &amp;lt;&amp;lt;parameters.BRANCH&amp;gt;&amp;gt;

jobs:
  test:
    executor: node/default
    steps:
      - checkout
      - node/install-packages:
          cache-path: ~/project/node_modules
          override-ci-command: npm install
      - run: npm test

  deploy:
    executor: heroku/default
    steps:
      - checkout
      - heroku/install

      - when:
          condition:
            equal: [master, &amp;lt;&amp;lt; pipeline.git.branch &amp;gt;&amp;gt;]
          steps:
            - deploy-command:
                HEROKU_APP_NAME: production-server
                BRANCH: master

      - when:
          condition:
            equal: [staging, &amp;lt;&amp;lt; pipeline.git.branch &amp;gt;&amp;gt;]
          steps:
            - deploy-command:
                HEROKU_APP_NAME: staging-server
                BRANCH: staging

      - when:
          condition:
            equal: [develop, &amp;lt;&amp;lt; pipeline.git.branch &amp;gt;&amp;gt;]
          steps:
            - deploy-command:
                HEROKU_APP_NAME: develop-server
                BRANCH: develop

workflows:
  heroku_deploy:
    jobs:
      - test

      - deploy:
          requires:
            - test
          filters:
            branches:
              only:
                - master
                - develop
                - staging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For every integration, the pipeline will run 2 jobs, test for all branches, and deploy for just branch master, develop, and staging. The jobs are applied to feature branches gonna be shown in &lt;strong&gt;Pull Request&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;There are 4 parts that I think you need to notice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;orbs:&lt;/strong&gt; This session is where we declare "modules", like in &lt;code&gt;npm&lt;/code&gt; in case we use Javascript. By adding orbs, we are free to use the commands inside. &lt;/li&gt;
&lt;li&gt; &lt;strong&gt;commands:&lt;/strong&gt; we define reusable commands, and they are called by &lt;strong&gt;jobs&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;jobs:&lt;/strong&gt; we define what they will do for each job, they may call commands on &lt;strong&gt;orbs&lt;/strong&gt; or &lt;strong&gt;commands session&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;workflows:&lt;/strong&gt; &lt;strong&gt;jobs&lt;/strong&gt; will be called here, followed by the arrangement from top to bottom. Besides, we can require another successful running job, and which branch will be applied for the job. 
As you can see in the figures below, the branch &lt;code&gt;feature/demo&lt;/code&gt; is just required to pass the test job. In case the job is failed, the developers need to fix it before merging, That helps us save develop branch by preventing potential bugs. It's looked cool, right?&lt;/li&gt;
&lt;/ul&gt;

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

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

&lt;p&gt;&lt;em&gt;Let merge develop branch to staging branch, which are required successful both jobs&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8anujw0j1okkd4vbsewh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8anujw0j1okkd4vbsewh.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://paypal.me/DantisMai" rel="noopener noreferrer"&gt;Paypal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I hope that this post helps you have some idea for your pipeline. I am really happy to receive your feedback on this article. Thanks for your precious time reading this.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>circleci</category>
      <category>heroku</category>
    </item>
    <item>
      <title>CI/CD pipeline</title>
      <dc:creator>Dantis Mai</dc:creator>
      <pubDate>Sat, 25 Sep 2021 09:57:35 +0000</pubDate>
      <link>https://forem.com/maithanhdanh/ci-cd-pipeline-1e10</link>
      <guid>https://forem.com/maithanhdanh/ci-cd-pipeline-1e10</guid>
      <description>&lt;h2&gt;
  
  
  What is CI?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CI&lt;/strong&gt; is &lt;strong&gt;Continuous Integration&lt;/strong&gt;. It is a way-of-work that required teammates to integrate their work regularly. For each integration, the host server will do a series of steps to detect potential issues, automate repetitive manual processes, like test, build....&lt;/p&gt;

&lt;h2&gt;
  
  
  What is CD?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CD&lt;/strong&gt; is &lt;strong&gt;Continuous Delivery&lt;/strong&gt;. This process will automatically deploy every change in team code to the testing or staging environment. Besides, It also allows developers to set up other steps like system testing, performance testing... before actually deploy it to the production environment.&lt;/p&gt;

&lt;p&gt;In addition, &lt;strong&gt;CD&lt;/strong&gt; can stand for &lt;strong&gt;Continuous Deployment&lt;/strong&gt; (they are all CD in short form =) ). Continuous Delivery is a technique to auto-deploy code change to the staging environment, but manually deploy to the production, and Continuous Deployment is a technique to auto-deploy to &lt;strong&gt;production&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Basically, the staging and production environments have the same configuration. However, the production is a serious case, we don't want to make any mistakes on it. So, we usually choose manual deployment for the production.&lt;/p&gt;

&lt;h2&gt;
  
  
  CI/CD process
&lt;/h2&gt;

&lt;p&gt;Different processes are depending on companies. Below one is applied in most of my projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gpWl9w2c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n1qttp4a55b9io0q6ebu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gpWl9w2c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n1qttp4a55b9io0q6ebu.png" alt="cicd-process" width="880" height="52"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 1 [Hand]:&lt;/strong&gt; Init repository with, usually, master, staging, and develop branch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 2 [Hand]:&lt;/strong&gt; Developer will do their jobs in a &lt;strong&gt;new branch&lt;/strong&gt;, then create &lt;strong&gt;Pull Request (PR)&lt;/strong&gt; to start &lt;strong&gt;Peers Review&lt;/strong&gt; process. The new feature will be pushed to the &lt;strong&gt;develop&lt;/strong&gt; branch when the PR is accepted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 3 [Pipeline]:&lt;/strong&gt; After pushing code to the &lt;strong&gt;develop&lt;/strong&gt; branch, CI/CD pipeline is triggered to process testing. If it is passed, The feature will be deployed to the &lt;strong&gt;develop&lt;/strong&gt; environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 4 [Hand]:&lt;/strong&gt; Tester/QE will perform testing before confirming that the new feature is good to go.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 5 [Hand]:&lt;/strong&gt; Developer create &lt;strong&gt;PR&lt;/strong&gt; to merge code from the &lt;strong&gt;develop&lt;/strong&gt; branch to the &lt;strong&gt;staging&lt;/strong&gt; branch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 6 [Pipeline]:&lt;/strong&gt; CI/CD pipeline is triggered to process another test suite. If it is passed, the new feature will be deployed to the &lt;strong&gt;staging&lt;/strong&gt; environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 7 [Hand]:&lt;/strong&gt; Tester/QE will perform testing on the &lt;strong&gt;staging&lt;/strong&gt; environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 8 [Hand]:&lt;/strong&gt; Developer create &lt;strong&gt;PR&lt;/strong&gt; to merge code from the &lt;strong&gt;staging&lt;/strong&gt; branch to the &lt;strong&gt;master&lt;/strong&gt; branch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 9 [Pipeline]:&lt;/strong&gt; CI/CD pipeline finishes its job, and the new feature will be deployed on production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 10 [Hand]:&lt;/strong&gt; Tester/QE need to deal with the production environment. If it is not ok, developer will roll back the previous version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 11 [Hand]:&lt;/strong&gt; Pray!!!🙏🤞&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Pipeline tools
&lt;/h2&gt;

&lt;p&gt;With the movement of DevOps methodologies and Agile culture, a lot of good CI/CD tools are developed. Depending on your favor, you can find one &lt;a href="https://www.katalon.com/resources-center/blog/ci-cd-tools/"&gt;here&lt;/a&gt;. In this series, I will use &lt;a href="https://circleci.com/"&gt;CircleCI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://paypal.me/DantisMai"&gt;Paypal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;this is the first artical of &lt;strong&gt;CI/CD with CircleCI on Heroku&lt;/strong&gt; series. Honetly, I had a lot of fun when trying to build a CI/CD pipeline for my side project, and I hope you will too.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;I am really happy to receive your feedback on this article. Thanks for your precious time reading this.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>circleci</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Applying Domain-Driven Design in Developing Software</title>
      <dc:creator>Dantis Mai</dc:creator>
      <pubDate>Sun, 19 Sep 2021 13:36:08 +0000</pubDate>
      <link>https://forem.com/maithanhdanh/applying-domain-driven-design-in-developing-software-4ld0</link>
      <guid>https://forem.com/maithanhdanh/applying-domain-driven-design-in-developing-software-4ld0</guid>
      <description>&lt;p&gt;&lt;strong&gt;Domain-Driven Design (DDD)&lt;/strong&gt; is a concept of developing software that the structure of the codebase deeply matched the business domain.&lt;/p&gt;

&lt;p&gt;For more information about DDD, you can find it &lt;a href="https://en.wikipedia.org/wiki/Domain-driven_design" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It took me pretty much time to understand and apply it to daily tasks, so this article is my sharing all I know about DDD.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Rule
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;That rule specifies that something declared in an outer circle &amp;gt;must not be mentioned in the code by an inner circle.&lt;br&gt;
&lt;em&gt;--- The Clean Architecture - Uncle Bob ---&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dependency is the only thing we can't avoid in software development because a component/class either uses another component/class or is being used by another one. But we can control the direction of dependency.&lt;/p&gt;

&lt;p&gt;Let say we have a chain A -&amp;gt; B -&amp;gt; C&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A depends on B, B depends on C, then C depends on A. So if C changes, B has to change, which leads to A has to change. We call this &lt;strong&gt;circular dependency&lt;/strong&gt;, which is always a bad idea.&lt;/li&gt;
&lt;li&gt;We can control this direction of dependency by &lt;strong&gt;Dependency Inversion&lt;/strong&gt;. Adding additional component A', we have the new chain A -&amp;gt; B -&amp;gt; C, C -&amp;gt; A', A -&amp;gt; A'. Now, everything depends on A'. In this case, C may change, A may change, but when A' is the same, the changes won't affect others.&lt;/li&gt;
&lt;li&gt;A' could be an &lt;strong&gt;interface&lt;/strong&gt; in the context of Java language, and &lt;strong&gt;domain&lt;/strong&gt; at the module level.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Layers role
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Entity
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Description: represent the entry point of requests, messages from SQS, SNS, or Kafka&lt;/li&gt;
&lt;li&gt;Roles:

&lt;ul&gt;
&lt;li&gt;Middleware (Request validation, error handler).&lt;/li&gt;
&lt;li&gt;Router.&lt;/li&gt;
&lt;li&gt;Build response.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Repository
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Description: call request to external resources like external APIs.&lt;/li&gt;
&lt;li&gt;Roles:

&lt;ul&gt;
&lt;li&gt;Middleware (Request validation, authentication) for external API.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No business logic here.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Infrastructure
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Description: define resources replaced to infrastructure, like Database, Queues.&lt;/li&gt;
&lt;li&gt;Roles:

&lt;ul&gt;
&lt;li&gt;Establish connection.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No business logic here.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Application
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Description: contain orchestration/process logic.&lt;/li&gt;
&lt;li&gt;Roles:

&lt;ul&gt;
&lt;li&gt;Handle business flow.&lt;/li&gt;
&lt;li&gt;Make external calls to retrieve data.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Domain
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Description: contain shared logic across process, mainly focus on a specific domain.&lt;/li&gt;
&lt;li&gt;Roles:

&lt;ul&gt;
&lt;li&gt;validation for business logic.&lt;/li&gt;
&lt;li&gt;implement business logic.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Sometime, to simplify the codebase structure, We can combine &lt;strong&gt;infrastructure&lt;/strong&gt; to &lt;strong&gt;repository&lt;/strong&gt;, I do it in my example below.&lt;/p&gt;

&lt;p&gt;When we talk about DDD, we talk about interfaces, and &lt;strong&gt;all of them are declared in the domain layer&lt;/strong&gt; for each specific domain.&lt;br&gt;
It's too much for theory, now come back to reality!!&lt;/p&gt;
&lt;h2&gt;
  
  
  How to apply it to project
&lt;/h2&gt;

&lt;p&gt;Let assume we have a business flow below, which is about booking a seat in a cinema:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IsInvestor: We don't want to cause any trouble for investors, so if they ask for a seat, we will take it for them.&lt;/li&gt;
&lt;li&gt;IsEligible: in this step, we will check whether the user's age is old enough.&lt;/li&gt;
&lt;li&gt;Register seat: register the user for the seat.&lt;/li&gt;
&lt;li&gt;Notification: send email to let them know whether the request is success or fail.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Now we structure our codebase from outer layer to inner layer based on the onion model above.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Controller: This layer handles 3 things&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mapping router to the controller.&lt;/li&gt;
&lt;li&gt;Validate required data for the request.&lt;/li&gt;
&lt;li&gt;Get suitable business flow in the &lt;strong&gt;Application&lt;/strong&gt; layer to handle this request &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Repository: This layer makes requests to external services. In this case, we may need user information from User downstream, seat information from Seat database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Application: this layer just handles business logic of a &lt;strong&gt;specific domain&lt;/strong&gt;, otherwise the &lt;strong&gt;Domain&lt;/strong&gt; layer will do the job. &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7m1gw6lfflhvv5yfdq11.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7m1gw6lfflhvv5yfdq11.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Domain: this layer handles business logic about User, Seat, and Email service. There is a lot of work to do here: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retrieve required data for business logic from downstream.&lt;/li&gt;
&lt;li&gt;Return result of &lt;em&gt;isInvestor&lt;/em&gt;, &lt;em&gt;isEligible&lt;/em&gt;, and so on.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After all all codebase will look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── controller
|  └── register-seat
|     ├── registerSeat.controller.ts
|     ├── registerSeat.router.ts
|     └── registerSeat.validator.ts
├── application
|  └── register-seat
|     └── registerSeatService.ts
├── repository
|  └── email
|  |  ├── type.ts
|  |  ├── emailBuilder.ts
|  |  └── emailService.ts
|  ├── user
|  |  ├── type.ts
|  |  └── userService.ts
|  └── seat
|     ├── type.ts
|     ├── seatSchema.ts
|     └── seatService.ts
└── domain
   ├── user
   |  └── eligibility
   |     ├── isSeatAvailable.ts
   |     └── isCurrentUserOldEnough.ts
   ├── email
   |  └── sendEmail.ts
   └── seat
      └── seatInfoProvider.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: sub-domains name may have different of mine, depended on project business domain.&lt;/p&gt;

&lt;p&gt;As we can see in the onion model, the registry is the most outer layer, and the domain is the most inner one. How on earth the domain will call repositories to integrate with outside resources, so that &lt;strong&gt;violates our rule&lt;/strong&gt;, right?&lt;/p&gt;

&lt;p&gt;If we stay still applying the same thing for domain and repository, the answer for that question is yes 😑, we definitely break out the golden rule. It is the place which &lt;strong&gt;Dependency Inversion&lt;/strong&gt; plays its role. After creating an interface for a repository, we &lt;strong&gt;inject&lt;/strong&gt; that service into domain logic. So that, we separate 2 of them.x&lt;/p&gt;

&lt;p&gt;&lt;a href="https://paypal.me/DantisMai" rel="noopener noreferrer"&gt;Paypal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article is all thing I know about DDD, I may misunderstand some points, please help me fix it by leaving your feedback, I am really happy. Thanks for your precious time reading this.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Create Express Typescript Boilerplate</title>
      <dc:creator>Dantis Mai</dc:creator>
      <pubDate>Sat, 11 Sep 2021 12:03:05 +0000</pubDate>
      <link>https://forem.com/maithanhdanh/create-express-typescript-boilerplate-3gf</link>
      <guid>https://forem.com/maithanhdanh/create-express-typescript-boilerplate-3gf</guid>
      <description>&lt;h2&gt;
  
  
  What is Git Template?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://git-template.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;Git Template&lt;/a&gt; is a frame for us to make numerous clones with the same configuration&lt;/p&gt;

&lt;h2&gt;
  
  
  Create boilerplate
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Init git repository
&lt;/h3&gt;

&lt;p&gt;Depends on familiarity, we can init repository by using &lt;a href="https://github.com/new" rel="noopener noreferrer"&gt;Git Interface&lt;/a&gt; then clone it back or executing &lt;a href="https://git-scm.com/docs/git-init" rel="noopener noreferrer"&gt;Git CLI&lt;/a&gt; on local folder.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add configuration
&lt;/h3&gt;

&lt;p&gt;First of all, we need to &lt;strong&gt;initialize nodejs project&lt;/strong&gt; by answering some questions  after executing the command &lt;code&gt;npm init&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fezti07t2flrxso6xh9ng.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fezti07t2flrxso6xh9ng.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then we install &lt;a href="https://www.npmjs.com/package/typescript" rel="noopener noreferrer"&gt;Typescript&lt;/a&gt; by &lt;code&gt;npm&lt;/code&gt; or &lt;code&gt;yarn&lt;/code&gt;. I suggest installing it with &lt;code&gt;--save-dev&lt;/code&gt; flag, because usually, the production package is built to &lt;strong&gt;Javascript&lt;/strong&gt;*&lt;/p&gt;

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

#For npm
npm install --save-dev typescript

#For yarn
yarn add --dev typescript


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

&lt;/div&gt;

&lt;p&gt;Now, we need to config our project. If you have followed me until this post, you will have the configuration of &lt;a href="https://dev.to/maithanhdanh/configuration-for-tsconfig-json-3bg5"&gt;tsconfig.json&lt;/a&gt;, &lt;a href="https://dev.to/maithanhdanh/configuration-for-prettier-14g1"&gt;Prettier&lt;/a&gt;, &lt;a href="https://dev.to/maithanhdanh/configuration-for-eslint-b47"&gt;ESLint&lt;/a&gt;, &lt;a href="https://dev.to/maithanhdanh/configuration-for-javascript-testing-framework-jl1"&gt;Jest&lt;/a&gt;, and &lt;a href="https://dev.to/maithanhdanh/configuration-for-husky-pre-commit-1fo5"&gt;Husky&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We come to the main guy, &lt;strong&gt;Express server&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;a href="https://www.npmjs.com/package/express" rel="noopener noreferrer"&gt;Express&lt;/a&gt; module. As I mentioned in &lt;a href="https://dev.to/maithanhdanh/configuration-for-javascript-testing-framework-jl1"&gt;Jest&lt;/a&gt;, &lt;strong&gt;Express&lt;/strong&gt; can't understand TS, so we need an additional module,&lt;strong&gt;ts-node&lt;/strong&gt;, to run the server on local, and 2 other modules &lt;strong&gt;@types/express&lt;/strong&gt;, &lt;strong&gt;@types/node&lt;/strong&gt; to get types of &lt;strong&gt;Express&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

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

npm install express
npm install --save-dev @types/express @types/node ts-node


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;There are some other ones you may need &lt;a href="https://www.npmjs.com/package/nodemon" rel="noopener noreferrer"&gt;nodemon&lt;/a&gt; for watching the changes in the resource folder, &lt;a href="https://www.npmjs.com/package/dotenv" rel="noopener noreferrer"&gt;dotenv&lt;/a&gt; for loading environment variables files, or &lt;a href="https://www.npmjs.com/package/cors" rel="noopener noreferrer"&gt;cors&lt;/a&gt; for solving error "access-control-allow-origin".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create our &lt;strong&gt;server&lt;/strong&gt;. From my experience, we need to create 2 files in &lt;code&gt;src&lt;/code&gt; folder placed at root level. The first one is &lt;code&gt;src/config/express.ts&lt;/code&gt; which is used to config our express server, and the second one is &lt;code&gt;src/index.ts&lt;/code&gt; for starting the server. If we merge 2 of those files, we will violate the &lt;strong&gt;SOLID&lt;/strong&gt; theory.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8jqh789motjw93pror81.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8jqh789motjw93pror81.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7kjri5vszkfw3n0w4dr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7kjri5vszkfw3n0w4dr.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you ask about &lt;code&gt;errorhandler&lt;/code&gt; middleware, I have an example for you below. And about &lt;code&gt;@controller&lt;/code&gt;, it depends on your domain business.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff94q6q8enkd1omnxkuey.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff94q6q8enkd1omnxkuey.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add scripts to &lt;code&gt;package.json&lt;/code&gt; to start server. Thanks to &lt;code&gt;ts-node&lt;/code&gt; we can directly start server without continuous complier.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;"start": "ts-node -r tsconfig-paths/register src/index"&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Try `npm start` to make sure it can start the server successfully
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8rw1uoj0nx9llk98xpo6.png)

- Add **Unit tests** to make sure everything works as expected. In case you followed my configuration in this [post](https://dev.to/maithanhdanh/configuration-for-javascript-testing-framework-jl1), then push test files into folder `__tests__` placed at root level with the same location in `src` (your folder tree will look like below). I love using [supertest](https://www.npmjs.com/package/supertest) to test my express server, you can make this [page](https://www.albertgao.xyz/2017/05/24/how-to-test-expressjs-with-jest-and-supertest/) as your reference
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5kju7jqs3yh9oepc0777.png)
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8d1gj71p1s9hwaqkpb9c.png)
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jzzw7n1nerio8q51k76g.png)

- Now we can try to commit the changes to init our repository. If we config `Husky`, then it will run `npm test` before actually commit
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uijd9rycullsi9pzi3nd.png)

###Mark repository as template
Finally, we come to the last part. After access our repository on [github](https://github.com/), we tick the box **template repository** in tab **setting**
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vvkmjqhjirq5b5qxjl67.png)
**CONGRATULATION!!! EXPRESS TYPESCRIPT BOILERPLATE ACHIEVED**

You can try to use it by clicking on **Repository template** on **New repository** page

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dms70q4vf3ihcpa4e0y1.png)
This is my [Template](https://github.com/Maithanhdanh/express-typescript-boilerplate), I am glad if you give me a star 😍.
And [here](https://www.npmjs.com/package/typescript-maker) is my brand new npm 😍.

_We have gone on a long journey with the **Create Your Own TypeScript Express Template** series. Thank you very much. If You need GitHub template, you can refer [here](https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/creating-a-repository-from-a-template)_

[Paypal](https://paypal.me/DantisMai).

_I am really happy to receive your feedback on this article. Thanks for your precious time reading this._
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>express</category>
      <category>node</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Configuration for Husky + pre-commit</title>
      <dc:creator>Dantis Mai</dc:creator>
      <pubDate>Mon, 06 Sep 2021 13:22:41 +0000</pubDate>
      <link>https://forem.com/maithanhdanh/configuration-for-husky-pre-commit-1fo5</link>
      <guid>https://forem.com/maithanhdanh/configuration-for-husky-pre-commit-1fo5</guid>
      <description>&lt;h2&gt;
  
  
  What is Husky?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Husky improves your commits and more 🐶 woof!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/husky" rel="noopener noreferrer"&gt;Husky&lt;/a&gt; helps us do more things along with git commands. For example, we can run &lt;code&gt;npm test&lt;/code&gt; in &lt;code&gt;pre-commit&lt;/code&gt; phase and do something else in &lt;code&gt;post-commit&lt;/code&gt; phase&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;There is a bit difference between npm version below and above 7, so please check it by&lt;/p&gt;

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

npm -v


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Automatic (require npm version &amp;gt; 7)
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

#For npm
npx husky-init &amp;amp;&amp;amp; npm install

#For Yarn 1
npx husky-init &amp;amp;&amp;amp; yarn

#For Yarn 2
yarn dlx husky-init --yarn2 &amp;amp;&amp;amp; yarn


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

&lt;/div&gt;

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

&lt;p&gt;After executing the command successfully, we need to take a look at the directory tree to make sure &lt;code&gt;.husky/pre-commit&lt;/code&gt; is there.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzopcwmbgakst3acfnr20.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzopcwmbgakst3acfnr20.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Manual
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;code&gt;Husky&lt;/code&gt;
```
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;npm install --save-dev husky &lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Enable git hooks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;npx husky install&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Add `prepare` script to `package.json`, this script will be trigger enable Git hooks after install. This step also depeneds on our npm version
  - npm &amp;gt; 7: `npm set-script prepare "husky install"`
  - npm &amp;lt; 7: copy `"prepare": "husky install"` to `scripts` in `package.json` 
 `
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s0o6oq1dqngrjpttsiu2.png)

Once here, our folder tree look like below. 
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/avhpmlo0rqafqel6o3j1.png)

- Now we need to create a hook by command `husky add`. After executing the below command, a line `npm test` is added to a new file `pre-commit` in `.husky`, which means `npm test` will be run before we actually commit.

```
npx husky add .husky/pre-commit "npm test"
```

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/khzirhq9u0dvov4y931q.png)

*If you use yarn2, [here](https://typicode.github.io/husky/#/?id=yarn-2) is your reference*.

##Have fun
Now, depending on our needs, we list out commands in the file `pre-commit`. In my case, I want to verify **branch name pattern**, **lint**, and **test cases**
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fhgy3ws6egqh57nupnh0.png)

[Paypal](https://paypal.me/DantisMai).

_I hope you had fun with git hook. I am really happy to receive your feedback on this article. Thanks for your precious time reading this._
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>husky</category>
      <category>git</category>
    </item>
    <item>
      <title>Configuration for Jest</title>
      <dc:creator>Dantis Mai</dc:creator>
      <pubDate>Sat, 04 Sep 2021 12:24:04 +0000</pubDate>
      <link>https://forem.com/maithanhdanh/configuration-for-javascript-testing-framework-jl1</link>
      <guid>https://forem.com/maithanhdanh/configuration-for-javascript-testing-framework-jl1</guid>
      <description>&lt;h2&gt;
  
  
  Testing framework
&lt;/h2&gt;

&lt;p&gt;Besides development, &lt;strong&gt;testing&lt;/strong&gt; plays an important role, it helps us to make sure any developed feature works as expected. Especially in &lt;em&gt;the refactoring codebase process&lt;/em&gt;, the business has to be the same, so we just basically go through all the test cases without changing them. If all of them are passed, our new codebase is good to go.&lt;/p&gt;

&lt;p&gt;There are a lot of testing framework for Javascript (JS), which has thier own strength and weakness. Please take a look on this &lt;a href="https://openbase.com/categories/js/best-nodejs-testing-framework-libraries"&gt;Comparing JS testing framework&lt;/a&gt; to find one. In this post I will use &lt;strong&gt;Jest&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  My configuration
&lt;/h3&gt;

&lt;p&gt;I use the configuration below in most of my Typescript projects. Because there are some important parts, I will explant them later, but for others, you can search in &lt;a href="https://jestjs.io/docs/configuration"&gt;configuration files&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import path from 'path';
const rootDirector = path.resolve(__dirname);

export default {
  clearMocks: true,
  collectCoverage: true,
  coverageDirectory: 'coverage',
  coverageProvider: 'v8',
  coverageThreshold: {
    global: {
      branches: 70,
      function: 80,
      lines: 80,
      statements: 80,
    },
  },
  globals: {
    'ts-jest': {
      tsconfig: path.resolve(__dirname, 'tsconfig.json'),
    },
  },
  moduleDirectories: ['node_modules'],
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
  moduleNameMapper: {
    '@server(.*)$': `${rootDirector}/src$1`,
    '@config(.*)$': `${rootDirector}/src/config$1`,
    '@tests(.*)$': `${rootDirector}/__tests__$1`,
    '@domain(.*)$': `${rootDirector}/src/domain$1`,
    '@controller(.*)$': `${rootDirector}/src/controller$1`,
    '@middleware(.*)$': `${rootDirector}/src/middleware$1`,
  },
  reporters: [
    'default',
    [
      path.resolve(__dirname, 'node_modules', 'jest-html-reporter'),
      {
        pageTitle: 'Demo test Report',
        outputPath: 'test-report.html',
      },
    ],
  ],
  rootDir: rootDirector,
  roots: [rootDirector],
  setupFilesAfterEnv: [`${rootDirector}/__tests__/setup.ts`],
  testPathIgnorePatterns: [
    '/node_modules/',
    '&amp;lt;rootDir&amp;gt;/build',
    `${rootDirector}/__tests__/fixtures`,
    `${rootDirector}/__tests__/setup.ts`,
  ],
  transform: {
    '^.+\\.ts$': 'ts-jest',
  },
  testRegex: ['((/__tests__/.*)|(\\.|/)(test|spec))\\.tsx?$'],
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  To use
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Yup, first step is always installing the &lt;a href="https://www.npmjs.com/package/jest"&gt;package&lt;/a&gt;, we can use the below command to do it. Besides, we are going to setup Jest config for &lt;strong&gt;TS&lt;/strong&gt; project, so remember to install &lt;a href="https://www.npmjs.com/package/ts-test"&gt;ts-test&lt;/a&gt; also.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#For npm
npm install --save-dev jest ts-jest

#For yarn
yarn add --dev jest ts-jest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create a file &lt;code&gt;jest.config.ts&lt;/code&gt; or &lt;code&gt;jest.config.js&lt;/code&gt; at the root level, and copy the configuration above to this file.&lt;/li&gt;
&lt;li&gt;Add a script &lt;code&gt;"test": "jest"&lt;/code&gt; to &lt;code&gt;scripts&lt;/code&gt; in our &lt;strong&gt;package.json&lt;/strong&gt;. By default, without the flag &lt;code&gt;--config&lt;/code&gt;, &lt;strong&gt;jest&lt;/strong&gt; will search in root level for the configuration file, otherwise, we need to evaluate value for &lt;code&gt;--config&lt;/code&gt;, and also update options in the config, like &lt;code&gt;ts-jest&lt;/code&gt;, &lt;code&gt;reporters&lt;/code&gt;, and so on.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Root level
"scripts": {
    "test": "jest",
},

# With config flag
"scripts": {
    "test": "jest --config='./jest-config/jest.config.ts'",
},
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explaination
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Importing Path module&lt;/strong&gt;: the module helps us navigate directory easier. In case we let &lt;code&gt;jest.config.ts&lt;/code&gt; in other folder, let say &lt;code&gt;jest-config&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;rootDir&amp;gt;&lt;/code&gt; in this case is the directory that we put in flag &lt;code&gt;--config&lt;/code&gt;, so now the value for &lt;code&gt;setupFilesAfterEnv&lt;/code&gt; must be &lt;code&gt;['&amp;lt;rootDir&amp;gt;/../__tests__/setup.ts']&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;if we use &lt;code&gt;path&lt;/code&gt; module, &lt;code&gt;rootDirector&lt;/code&gt; will point to root level.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#Without path module
setupFilesAfterEnv: [`&amp;lt;rootDir&amp;gt;/../__tests__/setup.ts`]

#With path module
setupFilesAfterEnv: [`${rootDirector}/__tests__/setup.ts`]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;globals&lt;/strong&gt;: because &lt;strong&gt;Jest&lt;/strong&gt; can't undestand &lt;strong&gt;TS&lt;/strong&gt;, we need to install additional module &lt;code&gt;ts-test&lt;/code&gt;, and also define &lt;code&gt;ts-test&lt;/code&gt; config in this option.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;moduleNameMapper&lt;/strong&gt;: in the post &lt;a href="https://dev.to/maithanhdanh/configuration-for-tsconfig-json-3bg5"&gt;tsconfig.json&lt;/a&gt;, I use &lt;code&gt;module-alias&lt;/code&gt; to simlify importing modules, so I need to register those mappings again.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;transform&lt;/strong&gt;: it is the place for us to define pattern filename for each testing framework. In my config, I just use ts-test to test my TS modules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;testRegex&lt;/strong&gt;: this option is used to let &lt;strong&gt;Jest&lt;/strong&gt; know how our test files look like, where they are.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;To be honest, &lt;a href="https://jestjs.io/docs/mock-functions"&gt;Mock&lt;/a&gt; is the most important term in testing. If you want to follow developer journey, I suggest you fully understand this term&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://paypal.me/DantisMai"&gt;Paypal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I hope this post helps you with config testing environment for your project. I am really happy to receive your feedback on this article. Thanks for your precious time reading this.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>typescript</category>
      <category>jest</category>
    </item>
    <item>
      <title>Configuration for ESLint</title>
      <dc:creator>Dantis Mai</dc:creator>
      <pubDate>Fri, 03 Sep 2021 05:18:31 +0000</pubDate>
      <link>https://forem.com/maithanhdanh/configuration-for-eslint-b47</link>
      <guid>https://forem.com/maithanhdanh/configuration-for-eslint-b47</guid>
      <description>&lt;h2&gt;
  
  
  What and Why ESLint
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;ESLint&lt;/strong&gt; is a code analyzer, it will prevent errors by finding and fixing problems in our codebase from variable to syntax&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  My configuration
&lt;/h3&gt;

&lt;p&gt;I just use the default configuration from command &lt;code&gt;eslint --init&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "env": {
    "browser": true,
    "es2021": true
  },
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": 12,
    "sourceType": "module"
  },
  "plugins": ["@typescript-eslint"],
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "prettier"
  ],
  "rules": {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  To use
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Just as my post about &lt;a href="https://dev.to/maithanhdanh/configuration-for-prettier-14g1"&gt;prettier&lt;/a&gt;, we need to install &lt;a href="https://www.npmjs.com/package/eslint" rel="noopener noreferrer"&gt;ESLint&lt;/a&gt; with flag &lt;code&gt;--save-dev&lt;/code&gt;. You can reach to the first step of part &lt;strong&gt;To Use&lt;/strong&gt; in the last post to get an answer for question &lt;strong&gt;why we need the flag&lt;/strong&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# for npm
npm install --save-dev eslint 

# for yarn
yarn add --dev eslint 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;After installing the package, we initialize the configuration file for the project.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# for npm
$ npx eslint --init

# for yarn
$ yarn run eslint --init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Then, it will ask us a lot of questions to generate a suitable config.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcupn02mix42r5ub2dj0l.PNG" alt="init process"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Notes:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Because I've already installed &lt;code&gt;@typescript-eslint\eslint-plugin&lt;/code&gt; and &lt;code&gt;@typescript-eslint\parser&lt;/code&gt;, I selected &lt;strong&gt;No&lt;/strong&gt; for the question &lt;code&gt;Would you like to install them now with npm&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ESLint&lt;/strong&gt; also supports pretty much formats of the configuration file. &lt;a href="https://eslint.org/docs/user-guide/configuring/configuration-files#configuration-file-formats" rel="noopener noreferrer"&gt;Configuartion Files&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Other Options
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;ESLint&lt;/strong&gt; is a great tool for us, and well worth for our digging into the &lt;a href="https://eslint.org/docs/user-guide/configuring/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;. To understand more how it behaves, you can test ESLint on &lt;a href="https://eslint.org/demo" rel="noopener noreferrer"&gt;demo&lt;/a&gt;. By clicking on &lt;code&gt;Rules Configuration&lt;/code&gt;, you can change the configuration.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2fz0n1seesc94mdp72ga.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2fz0n1seesc94mdp72ga.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After enjoy while playing around, &lt;strong&gt;ESLint&lt;/strong&gt; allows us to download the current config.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiaewee0oeg6iytusy66d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiaewee0oeg6iytusy66d.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://paypal.me/DantisMai" rel="noopener noreferrer"&gt;Paypal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Now, we already have &lt;code&gt;tsconfig&lt;/code&gt;, &lt;code&gt;prettier&lt;/code&gt; and &lt;code&gt;eslint&lt;/code&gt;, I hope they can you guys with your current projects. I am really happy to receive your feedback on this article. Thanks for your precious time reading this.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>eslint</category>
    </item>
    <item>
      <title>Configuration for prettier</title>
      <dc:creator>Dantis Mai</dc:creator>
      <pubDate>Wed, 01 Sep 2021 17:29:05 +0000</pubDate>
      <link>https://forem.com/maithanhdanh/configuration-for-prettier-14g1</link>
      <guid>https://forem.com/maithanhdanh/configuration-for-prettier-14g1</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbam2h89e435j5iifv9ne.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbam2h89e435j5iifv9ne.gif" alt="prettier"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What and Why prettier?
&lt;/h2&gt;

&lt;p&gt;Prettier is a code formatter, which supports many kinds of language from Programming languages (JXS, TS), to Style sheets (CSS, SCSS), and also Serialization languages (YAML).&lt;/p&gt;

&lt;p&gt;As we can see in the gif above, it will take a lot of time to arrange those lines, and even more for HTML. &lt;code&gt;Prettier&lt;/code&gt; is the light from heaven, just saving the file everything will be in order &lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  My configuration
&lt;/h3&gt;

&lt;p&gt;My beloved configuration is below&lt;/p&gt;

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

{
  "singleQuote": true,
  "trailingComma": "all",
  "useTabs": false,
  "tabWidth": 2,
  "overrides": [
    {
      "files": "*.yaml",
      "options": {
        "tadWidth": 2,
        "printWidth": 40,
        "singleQuote": true
      }
    }
  ]
}


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  To use
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;First of all, we need to install &lt;a href="https://www.npmjs.com/package/prettier" rel="noopener noreferrer"&gt;Prettier&lt;/a&gt; with flag &lt;code&gt;--save-dev&lt;/code&gt;, because it is just useful for development, but not production. Without &lt;code&gt;--save-dev&lt;/code&gt;, our production package will containts many unused modules (&lt;a href="https://stackoverflow.com/questions/18875674/whats-the-difference-between-dependencies-devdependencies-and-peerdependencies" rel="noopener noreferrer"&gt;reference about dependencies vs devdependencies&lt;/a&gt;)
```
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  npm
&lt;/h1&gt;

&lt;p&gt;npm i --save-dev prettier&lt;/p&gt;
&lt;h1&gt;
  
  
  yarn
&lt;/h1&gt;

&lt;p&gt;yarn add --dev prettier&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Create 2 files `.prettierrc`, `.prettierignore` in our root level, the former is for configuration and the latter is for ignoring directories. Usually, I ignore `build` and `coverage`, which is generated from build production package and test result corresponding.
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a2x74kcrk7v3nl2p6pph.png)
- Done!!

_Notes:_ Instead of `.prettierrc`, `prettier` also supports a wide range of types. Please take a look at [Configuration File](https://prettier.io/docs/en/configuration.html).

##Other options
You can find more interesting ways to use it in [prettier documentation](https://prettier.io/docs/en/options.html), such as lint-staged, pre-commit, and so on.

I usually due with CloudFormation, so besides a general configuration, I `overrides` it with my favorite style for `.yaml`. You can find your own one while [playing around](https://prettier.io/playground/) with it.
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xbaqumw7c2ykkwgxbfxi.png)

[Paypal](https://paypal.me/DantisMai).

_I hope this post helps you find your style in your developer journey. I am really happy to receive your feedback on this article. Thanks for your precious time reading this._


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

&lt;/div&gt;

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