<?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: Brian Hannaway</title>
    <description>The latest articles on DEV Community by Brian Hannaway (@briansdevblog).</description>
    <link>https://dev.to/briansdevblog</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%2F157330%2Ffd12634b-0701-4ca6-bd17-fcad4afd42f2.png</url>
      <title>DEV Community: Brian Hannaway</title>
      <link>https://dev.to/briansdevblog</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/briansdevblog"/>
    <language>en</language>
    <item>
      <title>Running Multiple Spring Boot Services with Docker Compose</title>
      <dc:creator>Brian Hannaway</dc:creator>
      <pubDate>Tue, 25 Aug 2020 22:18:46 +0000</pubDate>
      <link>https://dev.to/briansdevblog/running-multiple-spring-boot-services-with-docker-compose-5c2g</link>
      <guid>https://dev.to/briansdevblog/running-multiple-spring-boot-services-with-docker-compose-5c2g</guid>
      <description>&lt;p&gt;In this post we’ll look at how Docker Compose makes it easier to configure and run multiple containers in your local environment.&lt;/p&gt;

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

&lt;p&gt;First up, you don’t need Docker compose to run multiple containers. You can do this just fine by manually starting and stopping the containers yourself, as shown previously in this &lt;a href="https://www.briansdevblog.com/2016/08/docker-multi-container-app/"&gt;post&lt;/a&gt;.  However, as the number of containers in your application grows,  it becomes more cumbersome to manage each container manually.&lt;/p&gt;

&lt;p&gt;Docker compose simplifies things by allowing you to configure a multi container application in a single YAML file. You can start and stop all containers in the application with a single command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample App Code
&lt;/h2&gt;

&lt;p&gt;I’ve created a sample app for this post which you can pull from &lt;a href="https://github.com/briansjavablog/boot-microservices-docker-compose"&gt;Github&lt;/a&gt;. It contains the following&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2 Spring Boot applications

&lt;ul&gt;
&lt;li&gt;Bank Account Service – exposes a REST API for creating and reading bank simple account details&lt;/li&gt;
&lt;li&gt;Config Service – exposes a REST API with application configuration for the Bank Account Service&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;2 Dockerfiles – to define the container images for the above services&lt;/li&gt;
&lt;li&gt;A Docker compose file defining the multi container application&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Aside form the Docker side of things, I wont go into any detail on the Boot services. If you want more info you can check out this previous &lt;a href="https://dev.to/briansjavablog/configuring-micro-services-spring-cloud-config-server-579m-temp-slug-867372"&gt;post&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bank Account Service Dockerfile
&lt;/h2&gt;

&lt;p&gt;We’ll begin defining a Docker image for the Bank Account Service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# MAINTAINER Brian HannawayFROM openjdk:8-jre-alpine
WORKDIR /app
# Add wait script to the image - script pulled from https://github.com/ufoscout/docker-compose-wait/releases/download/2.7.3/wait /wait
COPY /scripts/wait /app/RUN chmod +x /app
RUN apk --no-cache add curl
COPY /target/bank-account-service-0.0.1-SNAPSHOT.jar /app/
CMD ./wait &amp;amp;&amp;amp; java -jar bank-account-service-0.0.1-SNAPSHOT.jar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;FROM openjdk:8-jre-alpine&lt;/code&gt; tells Docker to use the openjdk:8-jre-alpine base image.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;WORKDIR /app&lt;/code&gt; tells Docker to create a new working directory in the image called &lt;em&gt;/app&lt;/em&gt;.  All further commands will run from this directory.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;COPY /scripts/wait /app/&lt;/code&gt; tells Docker to copy the  &lt;code&gt;wait&lt;/code&gt; script from the &lt;em&gt;scripts&lt;/em&gt; directory on the host to the &lt;em&gt;/app&lt;/em&gt; directory in the image. I’ll explain the purpose of the &lt;em&gt;wait&lt;/em&gt; script in detail later.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;RUN chmod +x /app&lt;/code&gt; makes the contents of the &lt;em&gt;/app&lt;/em&gt; directory executable&lt;/p&gt;

&lt;p&gt;&lt;code&gt;COPY /target/bank-account-service-0.0.1-SNAPSHOT.jar /app/&lt;/code&gt; copies the service JAR from the target directory on the host to the &lt;em&gt;/app&lt;/em&gt; directory in the image&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CMD ./wait &amp;amp;&amp;amp; java -jar bank-account-service-0.0.1-SNAPSHOT.jar&lt;/code&gt; runs the  &lt;code&gt;wait&lt;/code&gt; script, followed by the bank account service. The service won’t run until the &lt;code&gt;wait&lt;/code&gt; script has finished.&lt;/p&gt;

&lt;h2&gt;
  
  
  Config Service Dockerfile
&lt;/h2&gt;

&lt;p&gt;Next we’ll define the Config Service Docker image. Its a slightly simpler version of the image we created for the Bank Account Service above. We’ll simply create a working directory, copy in the service JAR and run it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM openjdk:8-jre-alpine
MAINTAINER Brian Hannaway
WORKDIR /app
COPY /target/config-server-0.0.1-SNAPSHOT.jar /app/
ENTRYPOINT ["java", "-jar", "config-server-0.0.1-SNAPSHOT.jar"]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Defining the Docker Compose File
&lt;/h2&gt;

&lt;p&gt;Now that we’ve defined Dockerfiles for the Bank Account and Config services, the next step to create a docker-compose file that describes how we’ll uses these images to run containers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: "3"

services: 
   config-service: 
      image: config-service 
      container_name: config-service 
      networks: 
         - micro-service-network 
      ports: 
         - 8888:8888 

   bank-service: 
      image: bank-service 
      container_name: bank-service 
      networks: 
         - micro-service-network 
      ports: 
         - 8080:8080 
      environment: 
         WAIT_HOSTS: config-service:8888

networks: micro-service-network:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;version: "3"&lt;/code&gt; tells Docker that we’re using version 3 of the docker-compose file format. At the time of writing version 3 is the latest and recommended version. The docker-compose format version you use will be dictated by the version of Docker you’re running. I’m running Docker version 19.03.12 which means that I should be using version 3. If you want to check what version of docker-compose is compatible with your Docker version, check out this &lt;a href="https://docs.docker.com/compose/compose-file/compose-versioning/#compatibility-matrix"&gt;compatibility matrix&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Services Definition
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;services&lt;/code&gt; section defines the containers that make up your application. Each service definition contains all the configuration required to start a container from an image. The information in each service definition is what you’d typically supply on the command line, running a container manually.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;config-service: 
   image: config-service 
   container_name: config-service 
   networks: 
      - micro-service-network 
   expose: - "8888"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Config Service
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;config-service&lt;/code&gt; section defines all the configuration docker needs to run the config-service container&lt;/p&gt;

&lt;p&gt;&lt;code&gt;image&lt;/code&gt; tells compose which image to use to run the container.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;container_name&lt;/code&gt; is the name given to the container when it starts. If we don’t specify a name, compose will derive one based on the name of the compose file and the image name. For example, if I omit the name attribute for the &lt;code&gt;config-service&lt;/code&gt; and run &lt;code&gt;docker-compose up&lt;/code&gt; , I can see that the containers derived name is &lt;code&gt;boot-microservices-docker-compose_config-service_1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cT75-wLs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://www.briansdevblog.com/wp-content/uploads/2020/08/containerDerivedName.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cT75-wLs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://www.briansdevblog.com/wp-content/uploads/2020/08/containerDerivedName.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Generally its a good idea to give your containers a meaningful name. You’ll see later that we need to reference &lt;code&gt;config-service&lt;/code&gt; from the &lt;code&gt;bank-service&lt;/code&gt;. We’ll do this using the name specified in &lt;code&gt;container_name&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;networks&lt;/code&gt; defines the networks that the &lt;code&gt;config-service&lt;/code&gt; container will join when it starts. In this instance it will join  &lt;code&gt;micro-service-network&lt;/code&gt;, which we’ll define later.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;expose&lt;/code&gt; lists the ports that are exposed on the container. The ports are exposed on either the default network or any network the container is attached to. The ports are not exposed to the host machine. To do this you’ll need to use the  &lt;code&gt;ports&lt;/code&gt; attribute and supply the appropriate mappings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bank Service
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;bank-service&lt;/code&gt; definition is very similar to what we’ve already defined, with the &lt;code&gt;image&lt;/code&gt;, &lt;code&gt;container_name&lt;/code&gt;, &lt;code&gt;networks&lt;/code&gt; and  &lt;code&gt;expose&lt;/code&gt; attributes being similar to those defined for the &lt;code&gt;config-service&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bank-service:
   image: bank-service 
   container_name: bank-service 
   networks: 
      - micro-service-network 
   expose: - "8080" 
   environment: 
      WAIT_HOSTS: config-service:8888
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;environment&lt;/code&gt; attribute is used to specify a list of environment variables for the container. In the &lt;code&gt;bank-service&lt;/code&gt; we specify the environment variable &lt;code&gt;WAIT_HOSTS&lt;/code&gt; and give it the value &lt;code&gt;config-service:8888&lt;/code&gt;. In short, this  is required to control container start up order and ensure that the &lt;code&gt;config-service&lt;/code&gt; is up and running before the &lt;code&gt;bank-service&lt;/code&gt; starts. I’ll explain this in detail later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Networks Definition
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;networks&lt;/code&gt; section allows you define a network for your services. For our application we defined a network called &lt;code&gt;micro-service-network&lt;/code&gt;.   When you run &lt;code&gt;docker-compose up&lt;/code&gt;, each container that starts will be added to the &lt;code&gt;micro-services-network&lt;/code&gt; and will be visible to every other container in the application. Containers can reference one another via their host name, which is the same as the service name.  So in our sample application, the &lt;code&gt;banks-service&lt;/code&gt; is able to access the &lt;code&gt;config-service&lt;/code&gt; as &lt;code&gt;config-service:8888.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If we don’t explicitly define a &lt;code&gt;network&lt;/code&gt;, Docker will create one by default and add all services in the compose file to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the Application
&lt;/h2&gt;

&lt;p&gt;Running the &lt;code&gt;docker-compose up&lt;/code&gt; command will&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create a bridge network called &lt;code&gt;micro-service-network&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;start a container using the &lt;code&gt;config-service&lt;/code&gt; image. The container will expose port 8888 on &lt;code&gt;micro-service-network&lt;/code&gt; and will be accessible to other containers via host name &lt;code&gt;config-service&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;start a container using the &lt;code&gt;bank-service&lt;/code&gt; image. The container will expose port 8080 on &lt;code&gt;micro-service-network&lt;/code&gt; and will be accessible to other containers via host name &lt;code&gt;bank-service&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It takes approximately 20 seconds for both the  &lt;code&gt;bank-service&lt;/code&gt; and &lt;code&gt;config-service&lt;/code&gt; to start. If you run &lt;code&gt;docker container ls&lt;/code&gt; you should see the two containers that have just been created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vJusGJ-h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://www.briansdevblog.com/wp-content/uploads/2020/08/containers_running.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJusGJ-h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://www.briansdevblog.com/wp-content/uploads/2020/08/containers_running.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Service Dependencies &amp;amp; Startup Order
&lt;/h2&gt;

&lt;p&gt;Its common to have dependencies between containers, such that a container A requires container B to be running before container A can start. Compose allows you to handle this scenario to a certain degree, by defining the startup order using the &lt;code&gt;depends_on&lt;/code&gt; attribute. For example, the compose file below defines a &lt;code&gt;web&lt;/code&gt; service and a &lt;code&gt;db&lt;/code&gt; service, where &lt;code&gt;web&lt;/code&gt; is dependent on &lt;code&gt;db&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3'

services: 
   web: 
      image: myWebApp 
      depends_on: 
         - db 
      db: 
         image: postgres
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the above example, compose will start the containers in dependency order, so &lt;code&gt;db&lt;/code&gt; will be started before &lt;code&gt;web&lt;/code&gt;. Although &lt;code&gt;depends_on&lt;/code&gt; sets the order in which containers are started, it does not guarantee that Postgres, inside the &lt;code&gt;db&lt;/code&gt; container is fully operational before the  &lt;code&gt;web&lt;/code&gt; container starts.&lt;/p&gt;

&lt;p&gt;We have a similar problem in our sample application because &lt;code&gt;bank-service&lt;/code&gt; tries to call &lt;code&gt;config-service&lt;/code&gt; on startup. If &lt;code&gt;config-service&lt;/code&gt; isn’t fully stood up and available to take requests on port 8888, &lt;code&gt;bank-service&lt;/code&gt; will fail. Using the &lt;code&gt;depends_on&lt;/code&gt; attribute to start the &lt;code&gt;config-service&lt;/code&gt; first, won’t guarantee that the &lt;code&gt;config-service&lt;/code&gt; is fully operational before &lt;code&gt;bank-service&lt;/code&gt; calls it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introducing docker-compose-wait
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/ufoscout/docker-compose-wait/"&gt;docker-compose-wait&lt;/a&gt; is a great command line utility that solves the problem described above. When defining the &lt;code&gt;bank-service&lt;/code&gt; earlier we made docker-compose-wait available to the image by copying the &lt;code&gt;wait&lt;/code&gt; script into the &lt;code&gt;app&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Add wait script to the image - script pulled from https://github.com/ufoscout/docker-compose-wait/releases/download/2.7.3/wait /waitCOPY /scripts/wait /app/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We then told Docker to run the &lt;code&gt;wait&lt;/code&gt; script along with the JAR when starting the container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CMD ./wait &amp;amp;&amp;amp; java -jar bank-account-service-0.0.1-SNAPSHOT.jar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When we defined &lt;code&gt;bank-service&lt;/code&gt; in the docker-compose file, we included a &lt;code&gt;WAIT_HOSTS&lt;/code&gt; environment variable that referenced &lt;code&gt;config-service&lt;/code&gt; on port 8888. When we run  &lt;code&gt;docker-compose up&lt;/code&gt;, the &lt;code&gt;wait&lt;/code&gt; script pings &lt;code&gt;config-service&lt;/code&gt; on port 8888. It will not allow &lt;code&gt;bank-service&lt;/code&gt; container to start until &lt;code&gt;config-service&lt;/code&gt; is up and running on port 8888.&lt;/p&gt;

&lt;p&gt;We can see this in action in the log snippets below. The &lt;code&gt;wait&lt;/code&gt; script checks if  &lt;code&gt;config-service&lt;/code&gt; is available on port 8888, initially reporting that it isn’t available.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PJhyx40H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://www.briansdevblog.com/wp-content/uploads/2020/08/docker-compose-wait-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PJhyx40H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://www.briansdevblog.com/wp-content/uploads/2020/08/docker-compose-wait-1.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Eventually &lt;code&gt;config-service&lt;/code&gt; bootstraps and is up and running on port 8888. The &lt;code&gt;wait&lt;/code&gt; script then reports &lt;em&gt;Host config-service:8888 is now available&lt;/em&gt; and the &lt;code&gt;bank-service&lt;/code&gt; container is started.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MCx2RQgx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://www.briansdevblog.com/wp-content/uploads/2020/08/docker-compose-wait-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MCx2RQgx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://www.briansdevblog.com/wp-content/uploads/2020/08/docker-compose-wait-2.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this post we looked at how docker-compose makes it easy to manage multiple containers in a simple single node environment. This is particularly useful for development environments and automated test environments. If you want to manage multiple containers in a multi node environment, then Docker Swarm is a better bet. We’ll look at Swarm in another post soon.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://www.briansdevblog.com/2020/08/running-multiple-spring-boot-services-with-docker-compose/"&gt;Running Multiple Spring Boot Services with Docker Compose&lt;/a&gt; appeared first on &lt;a href="https://www.briansdevblog.com"&gt;briansdevblog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>dockercompose</category>
      <category>devops</category>
      <category>springboot</category>
    </item>
    <item>
      <title>Be Nice – Comment your Code</title>
      <dc:creator>Brian Hannaway</dc:creator>
      <pubDate>Fri, 30 Aug 2019 10:47:05 +0000</pubDate>
      <link>https://dev.to/briansdevblog/be-nice-comment-your-code-2klm</link>
      <guid>https://dev.to/briansdevblog/be-nice-comment-your-code-2klm</guid>
      <description>&lt;p&gt;I’ve always been a fan of commenting code. To me, it’s a no brainer, the sensible thing to do, and a fundamental part of building software that’s easy to understand and maintain. Not everyone agrees though. Some argue that comments are unnecessary and simply shine a light on code that isn’t as expressive as it should be.  In this post I’ll try to counter those arguments and tell you why I think quality comments are an important part of building software that easier to understand and maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Helping Others Understand Your Code
&lt;/h2&gt;

&lt;p&gt;As developers, we spend a considerable amount of time reading and trying to understand other peoples code. At times this can be a difficult and frustrating task. Most of us have been in a situation where we’re neck-deep in legacy code with no documentation, no unit tests and not a comment in sight. Chances are the guy who wrote it isn’t around anymore and we’re left to our own devices to figure out WTF is going on. Not much fun, is it?&lt;/p&gt;

&lt;p&gt;These experiences should remind us that as developers we have a responsibility to go beyond implementing functional requirements and write code that’s &lt;em&gt;easy to read, understand and maintain&lt;/em&gt;. A code base that’s easy to understand, makes life easier for your future self and those coming behind you. It allows developers with varying levels of technical ability and domain knowledge to jump into your code and become productive with the least amount of pain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comments – Just One Piece of the Puzzle
&lt;/h2&gt;

&lt;p&gt;When it comes to crafting code that’s easy to understand and maintain there are a number of important pieces in the puzzle. Based on my own experience I’d order these as follows.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;good structure – classes with a single responsibility, functions that do one thing&lt;/li&gt;
&lt;li&gt;descriptive naming – classes, functions and variables should have clear, descriptive names&lt;/li&gt;
&lt;li&gt;unit test coverage – unit tests describe how a component &lt;em&gt;should&lt;/em&gt; behave. As well as testing expected behaviour they act as a form of component specification&lt;/li&gt;
&lt;li&gt;comments – comments provide important information that can’t easily be expressed by the code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You might be surprised that comments are at the bottom of the list. That’s not to play down the importance of comments, but rather to highlight the importance of the other factors. Emphasis should always be placed on writing well structured, expressive code that’s easy to understand. Think of comments as the icing on the cake, that exist to provide the reader with information that can’t easily be expressed by the code itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Think about Your Audience
&lt;/h2&gt;

&lt;p&gt;Over the lifetime of a system, developers with varying levels of technical ability, experience and domain knowledge will work on the code. At one end of the spectrum, you may have very experienced tech lead/architect level guys, while at the other end you may have graduate developers fresh out of college. The point is, you don’t know exactly who’ll be working on your code in the future or what level of expertise they’ll have. With this in mind, you should make your comments accessible and useful to as broad a range of readers as possible. If you’re an experienced tech lead with strong domain knowledge, you shouldn’t comment your code assuming that the guy coming behind you will know as much as you do. Instead, write your comments with less experienced developers in mind.&lt;/p&gt;

&lt;p&gt;You could argue that this runs the risk of comments that are too obvious, especially for more experienced developers. While this &lt;em&gt;is&lt;/em&gt; a risk it’s important to remember that when we describe a comment as &lt;em&gt;obvious&lt;/em&gt; we’re being subjective. Something that’s obvious to a tech lead with 15 years experience may be anything but obvious to a junior developer.&lt;/p&gt;

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

&lt;p&gt;There are essentially 2 things you’ll want other developers to grasp when they’re looking at your code. &lt;em&gt;What&lt;/em&gt; the code is doing and &lt;em&gt;why&lt;/em&gt; it’s doing it. Let’s take a closer look.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comments that explain &lt;em&gt;What&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Well written code in many cases will be self-documenting. Your &lt;em&gt;aim&lt;/em&gt; should be to make your code as expressive as possible, therefore reducing the need for comments that describe &lt;em&gt;what&lt;/em&gt; the code does. However, there are times when describing &lt;em&gt;what&lt;/em&gt; the code does is useful.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When the business logic is complex you should use comments to describe your intent. Yes, you still want to make the code as self-descriptive as possible but comments add value in this instance by describing &lt;em&gt;what&lt;/em&gt; you’re &lt;em&gt;trying&lt;/em&gt; to achieve. As we all know, what the code does and what it’s meant to do is not always the same thing &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2EAkP1Kt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s.w.org/images/core/emoji/12.0.0-1/72x72/1f642.png" alt="🙂"&gt;
&lt;/li&gt;
&lt;li&gt;Some code simply isn’t expressive. Take regular expressions as an example. Yes, you can give a regex a descriptive name but it might not help the reader understand the pattern that’s being resolved. In this instance, comments that describe the pattern and provide sample matches are really useful.  Complex SQL is another example of code that doesn’t tend to be very expressive. Some simple comments can help guide the reader by describing the intent of the statement.&lt;/li&gt;
&lt;li&gt;Domain concepts can be difficult to describe. It sounds straight forward, but naming things &lt;em&gt;well&lt;/em&gt; can be very tricky, especially in a complex domain. I’ve spent quite a bit of time working in life assurance and pensions. I sometimes find it difficult to encapsulate the purpose of a class, function or variable in a simple name. In these situations, I’ll come up with the most descriptive name possible and then add a comment to describe in plain English, what the class, method or variable represents in business terms.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Comments that explain &lt;em&gt;Why&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Comments that explain &lt;em&gt;why&lt;/em&gt; your code does something are very important because this information can’t be derived from the code. Below are a few examples of when it’s important to explain &lt;em&gt;why&lt;/em&gt; you’ve chosen to do something.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Design Decisions – Comments that explain &lt;em&gt;why&lt;/em&gt; you’ve made design decisions are important, especially if you’ve implemented some kind of pattern that you expect other developers to leverage in the future. A guiding hand can help point people in the right direction by showing them the most appropriate way to extend existing functionality.  Making it clear &lt;em&gt;why&lt;/em&gt; you’ve done something also reduces the chances of someone refactoring your code in the future and inadvertently breaking a pattern you’ve put in place.&lt;/li&gt;
&lt;li&gt;Workarounds – we sometimes have to work around problems caused by external factors we have little or no control over. Perhaps data received from an external system needs to be tweaked in certain instances before it can be processed. Workarounds like this, while not ideal are a reality of enterprise development, especially where legacy systems are involved. Comments help by explaining the root of the problem and why we need to work around it.  Comments provide other developers with context and reduce the chances of someone removing the workaround because they don’t understand it.&lt;/li&gt;
&lt;li&gt;Edge cases – We sometimes write logic that has to handle peculiar edge cases. These scenarios aren’t usually intuitive and are therefore an excellent candidate for comments. Logic that handles quirky scenarios often seems more complicated than it needs to be. Comments are a good way to explain the edge cases and why you’ve implemented the solution you have.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conversational Comments
&lt;/h2&gt;

&lt;p&gt;I try to keep my comments informal and conversational. Imagine one of your teammates is sat beside you and you’re explaining how some part of your code works. You’d explain in simple terms, making it as easy as possible for your teammate to understand. I think comments should read the same way by using simple language to get the point across. Remember, comments are there to provide information that the code can’t, so make them as easy to digest as you can.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quality Over Quantity
&lt;/h2&gt;

&lt;p&gt;Like most things in life, there should be an emphasis on quality over quantity. Comments should be used thoughtfully, to tell the reader something that can’t be easily expressed by the code. Well structured, expressive code with a sprinkling of useful comments is much better than poorly written code with a ton of comments explaining what each and every line does.&lt;/p&gt;

&lt;p&gt;Avoid superfluous comments that echo something clearly described by the code. Comments, like code, evolve over time and need to be maintained. Avoiding superfluous comments reduces the maintenance overhead and helps the reader focus on the comments that are important.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoid Comment Rot
&lt;/h2&gt;

&lt;p&gt;Comment rot is when the code is updated but the accompanying comments are not. This leads to comments that are out of date and often contradictory to the code they’re supposed to describe.  Comment rot is often cited as a major downside to commenting code but I think this argument is weak. While I agree that comment rot is a bad thing and something to be avoided, it’s not a good enough reason to stop commenting your code. The best way to avoid comment rot is obvious…..update comments when you update the code. Like most good practice this requires a combination of developer discipline and governance in the form of code reviews.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Comments aren’t a substitute for well structured, expressive code but they can help by providing information that isn’t easily expressed by the code itself. Code that’s easier to read, understand and maintain, ultimately translates to greater productivity with more features being shipped, and I’ll bet that’s what keeps your boss happy.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://www.briansdevblog.com/2019/08/the-importance-of-comments-for-maintainable-code/"&gt;Be Nice – Comment your Code&lt;/a&gt; appeared first on &lt;a href="https://www.briansdevblog.com"&gt;briansdevblog&lt;/a&gt;.&lt;/p&gt;

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