<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ting Zhou</title>
    <description>The latest articles on DEV Community by Ting Zhou (@tingzhou13).</description>
    <link>https://dev.to/tingzhou13</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%2F254302%2F347f1d84-342d-4f3d-a994-da7909b62af6.png</url>
      <title>DEV Community: Ting Zhou</title>
      <link>https://dev.to/tingzhou13</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tingzhou13"/>
    <language>en</language>
    <item>
      <title>My understanding of SOLID principles</title>
      <dc:creator>Ting Zhou</dc:creator>
      <pubDate>Mon, 16 Aug 2021 16:24:50 +0000</pubDate>
      <link>https://dev.to/tingzhou13/my-understanding-of-solid-principles-4ln6</link>
      <guid>https://dev.to/tingzhou13/my-understanding-of-solid-principles-4ln6</guid>
      <description>&lt;p&gt;SOLID is made up of 5 design principles which is supposed to avoid unnecessary complexity. That being said, some things are unavoidably complex.&lt;/p&gt;

&lt;h2&gt;
  
  
  S: Single Responsibility Principle
&lt;/h2&gt;

&lt;p&gt;A class should have a single responsibility&lt;/p&gt;

&lt;p&gt;This was slightly confusing for me because I'm wondering how to define the scope of responsibility. We can understand it as the class needing to manage one well-defined aspect of the application.&lt;/p&gt;

&lt;p&gt;Say you have an employee at a hotel that wears many hats - Chef, Receptionist, and Cleaner. If we were to create a class Employee which encompasses all of these roles, the responsibility wouldn't be very well defined.&lt;/p&gt;

&lt;p&gt;If we need to change how the food is cooked, the class has to be modified. If we need to change how the room is clean, the class has to be modified.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Employee {
  cookFood() {}
  serveGuest() {}
  cleanRoom() {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead, we can define 3 classes relating to the food (chef), guests (receptionist), and housekeeping (cleaner).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Chef extends Employee {
  cookFood() {}
}

class Receptionist extends Employee {
  serveGuest() {}
}

class Cleaner extends Employee {
  cleanRoom() {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  O: Open/Closed Principle
&lt;/h2&gt;

&lt;p&gt;Classes should be open for extension, but closed for modification.&lt;/p&gt;

&lt;p&gt;In this context, extension means to extend the class by creating a new sub-class, modification means to modify the existing class.&lt;/p&gt;

&lt;p&gt;If we wanted to introduce a Station Chef who's in charge of cooking the omelette at the breakfast buffet line, we could either extend or modify.&lt;/p&gt;

&lt;p&gt;This is how it would look like if we were to modify.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Chef extends Employee {
  cookFood() {}
  cookOmelette() {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem with doing so would be potentially introducing bugs to the Chef class. Other parts of the application that use the Chef class might also fail.&lt;/p&gt;

&lt;p&gt;Instead, we can extend, creating a new sub-class StationChef which inherits Chef.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Chef extends Employee {
  cookFood() {}
  cookOmelette() {}
}

class StationChef extends Chef {
  cookOmelette() {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  L: Liskov Substitution
&lt;/h2&gt;

&lt;p&gt;The child class needs to be able to perform the same actions as the parent class.&lt;/p&gt;

&lt;p&gt;If StationChef extends Chef, objects of Chef can be replaced with objects of Chef.&lt;/p&gt;

&lt;p&gt;Can't think of an example using this chef analogy, but a good one I found &lt;a href="https://stackoverflow.com/a/584732"&gt;here&lt;/a&gt; is on how a square should not be a subclass of a rectangle.&lt;/p&gt;

&lt;h2&gt;
  
  
  I: Interface Segregation
&lt;/h2&gt;

&lt;p&gt;A class should not need to implement methods it does not need.&lt;/p&gt;

&lt;p&gt;Say we want to give some chefs the ability to clean, and we do so by adding this method into the Chef interface. Later on, we have a HeadChef, which we don't expect to clean.&lt;/p&gt;

&lt;p&gt;However, we are forced to implement the method cleanKitchen for the head chef.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface Chef {
  cookFood(): void;
  cleanKitchen(): void;
}

class HeadChef implements Chef {
  cookFood() {}
  cleanKitchen() {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead, we could break the interface down, and avoid having to implement the cleanKitchen method in HeadChef.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface ChefCook {
  cookFood(): void;
}

interface ChefClean {
  cleanKitchen(): void;
}

class HeadChef implements ChefCook {
  cookFood() {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  D: Dependency Inversion
&lt;/h2&gt;

&lt;p&gt;High level modules should not depend on low level modules. Both should depend on abstraction.&lt;/p&gt;

&lt;p&gt;Abstractions should not depend on details. Details should depend on abstractions.&lt;/p&gt;

&lt;p&gt;I have no idea what the second line meant.&lt;/p&gt;

&lt;p&gt;Say we want the Chef to log every item that was cooked using the logger.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Chef {
  private logger;
  constructor() {
    this.logger = new Logger();
  }

  cookFood(foodName) {
    this.logger.log(foodName);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, our high level module is Chef, and low level module is Logger.&lt;/p&gt;

&lt;p&gt;I can clearly see that Chef and Logger are now tightly coupled. Scenario: I want to add a new feature to Logger that is used in the Chef class. If I decide to follow the Open/Closed principle, I would add a subclass, say ChildLogger. This means that my Chef class will also need to change to use the new ChildLogger, which also means that the Chef class (high level module) is dependant on the Logger class (low level module).&lt;/p&gt;

&lt;p&gt;However, if I had used dependency inversion, and followed the Liskov principle, I will no longer need to change the Chef class, because a ChildLogger is a type of Logger.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Chef {
  private logger;
  constructor(logger: Logger) {
    this.logger = logger;
  }

  cookFood(foodName) {
    this.logger.log(foodName);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What about the abstractions and details part? Note that the above example does not violate this rule, but I will continue explaining using this analogy.&lt;/p&gt;

&lt;p&gt;The abstraction here is that my logger will record the foodName passed to it. The details will be how this foodName will be stored. It could be sending a SMS to the CEO, or just being recorded in a computer.&lt;/p&gt;

&lt;p&gt;When we say that abstraction should not depend on details, we always expect the logger to log the foodName, no matter what the implementation of logger.log is.&lt;/p&gt;

&lt;p&gt;When we say that details should depend on abstractions, the very name of the method, log, implies that the data is being logged somewhere. In that case, we should not expect the method, log, to perform any other unrelated operations, such as calling another chef to cook the food.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Docker Basics</title>
      <dc:creator>Ting Zhou</dc:creator>
      <pubDate>Sun, 15 Aug 2021 08:23:06 +0000</pubDate>
      <link>https://dev.to/tingzhou13/docker-basics-4k6</link>
      <guid>https://dev.to/tingzhou13/docker-basics-4k6</guid>
      <description>&lt;p&gt;Penning down my learnings when going through the &lt;a href="https://docs.docker.com/get-started/"&gt;official docker getting started tutorial&lt;/a&gt;. Repository &lt;a href="https://github.com/tingzhouu/docker-basics"&gt;here&lt;/a&gt; for reference.&lt;/p&gt;

&lt;p&gt;The purpose of Docker is to be machine-agnostic, where anyone with the source code will be able to run the application.&lt;/p&gt;

&lt;p&gt;Docker allows us to create images, which we can then run in a container that Docker creates on our machine.&lt;/p&gt;

&lt;p&gt;Creating an image&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CkHbJErG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/19mvnilvdy8mrfd53hyd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CkHbJErG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/19mvnilvdy8mrfd53hyd.png" alt="Docker Build Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Running an image in a Docker container&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--F_ucIBBK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jkm24vmcjbdvpbco8g12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F_ucIBBK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jkm24vmcjbdvpbco8g12.png" alt="Docker Run Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To demonstrate, we have an express app running on port 3000, with an endpoint &lt;code&gt;GET /&lt;/code&gt; that returns &lt;code&gt;"Hello World!"&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Dockerfile
&lt;/h2&gt;

&lt;p&gt;The Dockerfile contains instructions on creating and running the image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Dockerfile, this line is a comment.
FROM node:12-alpine
COPY . my-wonderful-app
RUN cd my-wonderful-app &amp;amp;&amp;amp; npm install
CMD ["node", "my-wonderful-app/app.js"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What does every line do?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  FROM
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;FROM node:12-alpine&lt;/code&gt; | &lt;code&gt;FROM &amp;lt;parent_image&amp;gt;:&amp;lt;image_version&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FROM&lt;/code&gt; specifies the parent image from which we are building, as specified &lt;a href="https://docs.docker.com/engine/reference/builder/#format"&gt;here&lt;/a&gt;. In this case, our parent image is &lt;code&gt;node&lt;/code&gt;, using the version &lt;code&gt;12-alpine&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What happens if we don't have this line: We will not be able to run any &lt;code&gt;node&lt;/code&gt; or &lt;code&gt;npm&lt;/code&gt; commands when inside the container.&lt;/p&gt;

&lt;h4&gt;
  
  
  COPY
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;COPY . my-wonderful-app&lt;/code&gt; | &lt;code&gt;COPY &amp;lt;source_directory&amp;gt;:&amp;lt;destination_directory_in_docker_container&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;COPY&lt;/code&gt; copies files from the current directory in the machine to the directory inside the docker container, more info &lt;a href="https://docs.docker.com/engine/reference/builder/#copy"&gt;here&lt;/a&gt;. This command is run when building the docker image.&lt;/p&gt;

&lt;p&gt;In this case, we are copying the files from the current directory where the Dockerfile is, into the folder &lt;code&gt;my-wonderful-app&lt;/code&gt; in the docker container.&lt;/p&gt;

&lt;p&gt;What happens if we don't have this line: Our docker container will not contain our source code.&lt;/p&gt;

&lt;h4&gt;
  
  
  RUN
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;RUN cd my-wonderful-app &amp;amp;&amp;amp; npm install&lt;/code&gt; | &lt;code&gt;RUN &amp;lt;command&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;RUN&lt;/code&gt; executes the command provided. This command is run when building the docker image. More information &lt;a href="https://docs.docker.com/engine/reference/builder/#run"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this case, we are changing the directory to &lt;code&gt;my-wonderful-app&lt;/code&gt; and running &lt;code&gt;npm install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What happens if we don't have this line: Our app in the docker container will not have a &lt;code&gt;node_modules&lt;/code&gt; folder.&lt;/p&gt;

&lt;h4&gt;
  
  
  CMD
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;CMD ["node", "my-wonderful-app/app.js"]&lt;/code&gt; | &lt;code&gt;CMD ["executable","param1","param2"]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CMD&lt;/code&gt; provides instructions on running the container. More information &lt;a href="https://docs.docker.com/engine/reference/builder/#cmd"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this case, we are executing the command &lt;code&gt;node my-wonderful-app/app.js&lt;/code&gt; when running the container.&lt;/p&gt;

&lt;p&gt;What happens if we don't have this line: Our app will not be run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build image
&lt;/h2&gt;

&lt;p&gt;Now that we have the instructions that Docker needs, we can build the image by running &lt;code&gt;docker build -t myapp-image .&lt;/code&gt; More info on the &lt;code&gt;docker build&lt;/code&gt; command &lt;a href="https://docs.docker.com/engine/reference/commandline/build/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  -t
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;-t &amp;lt;image_name:image_tag&amp;gt;&lt;/code&gt; | &lt;code&gt;-t myapp-image&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-t&lt;/code&gt; provides a name to the image. This allows us to identify the image more easily when we want to run the image. If the &lt;code&gt;image_tag&lt;/code&gt; is not provided, the tag will be set to &lt;code&gt;latest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;What happens if we don't have this line: Not crucial, we can still run the image by its id.&lt;/p&gt;

&lt;h3&gt;
  
  
  PATH
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;.&lt;/code&gt; | &lt;code&gt;PATH&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here, we specify &lt;code&gt;.&lt;/code&gt; as our path as we are pointing to our current directory&lt;/p&gt;

&lt;p&gt;What happens if we don't have this line: The command won't run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run image
&lt;/h2&gt;

&lt;p&gt;After the image has been built, we can run the image. Docker will create a container in which the image will run. Run &lt;code&gt;docker -d -p 1234:3000 run myapp-image&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  -d
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;-d&lt;/code&gt; specifies that we run this image in detached mode, meaning run it in the background.&lt;/p&gt;

&lt;p&gt;What happens if we don't have this line: The terminal used to run the command will be monitoring the image that is run.&lt;/p&gt;

&lt;h3&gt;
  
  
  -p
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;-p &amp;lt;MACHINE_PORT&amp;gt;:&amp;lt;CONTAINER_PORT&amp;gt;&lt;/code&gt; | &lt;code&gt;-p 1234:3000&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-p&lt;/code&gt;, which stands for publish, exposes a port on the local machine to a port on the container.&lt;/p&gt;

&lt;p&gt;In this case, we are exposing port 1234 on the local machine to port 3000 on the docker container. Earlier, we specified in our app to run on port 3000.&lt;/p&gt;

&lt;p&gt;Since the app is running on the container, the app will be using the container's port 3000. Making a call to &lt;code&gt;localhost:1234&lt;/code&gt; will be redirected to the container's port 3000.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I know it works
&lt;/h2&gt;

&lt;p&gt;Open &lt;code&gt;localhost:1234&lt;/code&gt; on the browser. You should see &lt;code&gt;"Hello World!"&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker Compose
&lt;/h2&gt;

&lt;p&gt;It would be very tedious to keep running the build and run commands, especially when there are more containers. That is where docker-compose comes in.&lt;/p&gt;

&lt;p&gt;Instead of running the build and run commands, we can specify them in a &lt;code&gt;docker-compose.yaml&lt;/code&gt; file instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# docker-compose.yaml, this line is a comment.
version: "3.7"

services:
  favourite-app:
    build:
      context: .
    ports:
      - 1234:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What does every line do?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  version
&lt;/h4&gt;

&lt;p&gt;This is the version we specify to be compatible with the docker engine. The latest version is most commonly used, which can be found from the compatibility matrix &lt;a href="https://docs.docker.com/compose/compose-file/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this case, we are using &lt;code&gt;"3.7"&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  services
&lt;/h4&gt;

&lt;p&gt;These are the services that make up our application. One service will take up one container. Docker will create and run all the services that have been specified here. Examples of other services could be a database where we use the mongodb image.&lt;/p&gt;

&lt;p&gt;In this case, we only have 1 service.&lt;/p&gt;

&lt;h4&gt;
  
  
  service_name:
&lt;/h4&gt;

&lt;p&gt;This name will be reflected in the container name in the following format: &lt;code&gt;&amp;lt;folder_name&amp;gt;_&amp;lt;service_name&amp;gt;_&amp;lt;number&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In this case, the folder name is &lt;code&gt;myapp&lt;/code&gt;, the service name is &lt;code&gt;favourite_app&lt;/code&gt;. The name of the container will be &lt;code&gt;myapp_favourite-app_1&lt;/code&gt;. However, I don't know why there needs to be the number.&lt;/p&gt;

&lt;h4&gt;
  
  
  build:context:
&lt;/h4&gt;



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

&lt;/div&gt;



&lt;p&gt;This is to specify where our Dockerfile is, which is needed to create and run the image.&lt;/p&gt;

&lt;p&gt;In this case, our Dockerfile is at the current directory, which is why we use &lt;code&gt;.&lt;/code&gt; as the context.&lt;/p&gt;

&lt;h4&gt;
  
  
  ports:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ports:
    - 1234:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the publish flag that is used in the &lt;code&gt;docker run&lt;/code&gt; command, which has been explained above.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I know it works
&lt;/h2&gt;

&lt;p&gt;Run &lt;code&gt;docker-compose up -d&lt;/code&gt; in the terminal. After the container is up and running, open &lt;code&gt;localhost:1234&lt;/code&gt; on the browser. You should see &lt;code&gt;"Hello World!"&lt;/code&gt;.&lt;/p&gt;

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