Book Review - Atomic Habits

Atomic Habits Last month I finished the book Atomic Habits. I have read a few other books on building great and quitting bad habits such as The Power of Habit by Charles Duhigg which was also a great book. But what makes atomic habits a great book to read is that it gives you step by step instructions! It’s a practical book. Everything James Clear, the author, claims is based on scientific facts. After convincing the reader by providing those facts, he then offers some great techniques to either building a good or quitting bad habits. In this post I’m going to describe my own perception of this book.

The book elaborates that human behaviors are the result of plenty of small (atomic) habits. Our habits made us what we are! Habits differ from goals. Goals are things we are going to achieve but habits are actually behaviors that we are going to institutionalize in ourselves.

Who do you want to become

To be able to either build or quit a habit, you should first ask an important question from yourself: What kind of person I want to become? Then, you should ask another question accordingly. For example, if you want to become a healthy person, which is habit not a goal, you should then ask this important question: What are the characteristics of a healthy person? These could be some answers

  • A healthy person’s weight is ideal.
  • A healthy person exercise regularly.
  • A healthy person doesn’t eat or drink junk foods.
  • A healthy person sleeps well.

When answers completed you now know how to become that kind of person!

The four stages of habit

Any habit has the following 4 stages: Atomic Habits

So, as shown in the above image, to make a good habit, you must answer the following question:

  • How can I make it obvious? (Cue)
  • How can I make it more attractive? (Craving)
  • How can I make it easier? (Response)
  • How can I make it more enjoyable? (Reward)

Consequently, if you want to quit a bad habit you should act the opposite:

  • How can I make it invisible? (Cue)
  • How can I make it less attractive? (Craving)
  • How can I make it more difficult? (Response)
  • How can I make it unpleasant? (Reward)

Understand your current habits

Sometimes you don’t know what habits (no matter bad or good) you have. To understand you current habits create a list of all things you do during a typical day. Then mark each one with + for good ones, - for bad one, or = for neutral tasks. Here is an example:

Task Symbol
Wake up =
Check social media -
Shower +
Coffee =
Walk to work +

When I did it myself, I realized that some of my current habits are completely useless! For example, every morning after I wake up, I was instantly check my phone for any new notifications. Then without understanding it, I was checking Instagram and Twitter.

After understanding your current status, sort them by the value they’re adding to your life. By doing this, you will understand which task adds real value to your life and which doesn’t. You then understand that some of your habits needs change. You may want to quit some of bad ones like the one I’ve mentioned about myself, and replace them by good habits. But how? As mentioned above, the four stages will help you.

Build new habits

Here are some notes I’ve taken from the book for building new habits.

Stage 1: Make it obvious

The first stage is to make a habit clear! There are some techniques mentioned in the book to help you do it:

Bind it with space and time

Bind the habit you’re going to build to a space and time. For example if you want to learn a new language, you can do the following: I will learn French everyday 6PM at home. By binding time and space to a habit, you give it an identity.

Connecting habits

Connect habits you want to build with the ones you already have. For example if you want to read more books, you may want to connect it to your every morning coffee: I will read books for 30 minutes while drinking my morning coffee.

Environment change

Change the environment to make good habits more obvious and bad ones invisible. This is a really good one. Let’s imaging you want to learn playing guitar. So you should change your home’s environment by placing your guitar somewhere you see. In the meantime, if you get distracted by TV, place the remote control somewhere you can’t access easily; maybe in the TV drawer. Environment change was the biggest lesson for me. Because when you don’t see the signs of a bad habit you will probably won’t do that.

Stage 2: Make it attractive

One key point for building a new habit is that you should keep that very attractive all the time. If a new habit gets boring you will stop doing that. Scientifically, you should keep you dopamine level as high as possible so your brain enjoy the process doing that habit. Here are some techniques:

Packing habits

The packing technique means combining habits you want to make with the ones you already have. For example if you want to do more exercises, you can buy an indoor bicycle and do some cardio while watching Netflix.

The imitation pattern

Our brain uses an imitation pattern to make habits more enjoyable. We typically enjoy doing things that the following groups do:

  • Our family (especially parents)
  • Famous people and celebrities
  • Close friends and communities we are in

For example, in a family, if parents read books, children will probably read as well because book reading is a value in that family. As an another example, if you’re participated in a hiking group in which all other participants love hiking and mountain climbing, then you probably will do it more frequently and with joy.

Turn force into opportunity

One of the reasons we stop doing habits is because we’re doing them by force. But in order to stick to a habit, we must change our mindset about it. For example, if you plan to build a habit of waking up early, instead of tell yourself that I must force myself to wake up early every morning, you should make yourself aware of the benefits waking up early gives you. For example, if I wake up early, I would have more time doing what I love to and get more things.

Stage 3: Make it easier

The easier it gets, the more you do it.

Redo, Redo, and Redo

What make things easier to do? The answer is very simple: redo, redo, and redo. Repeating is the main step toward building a new habit. Every time you do a habit, it will get easier for you because the brain doesn’t have to think about it. The more you do something, the easier it gets.

Embrace new habits

Some people don’t try new things because they afraid to fail. Accepting the fact that you will fail sometimes will help you doing that as soon as possible and prevent procrastination. You need to start doing whatever is in your mind. The best way to learn a new thing is practice it over and over again; not planning and not acting.

Deal with difficult habits

Some habits cannot become any easier. For this kind of habits, the book offers to make the first two minutes of doing that habit easy. The more the first parts of a habit become easier, the more you probably do it.

Make bad habits difficult

For bad habits, you must make them as much difficult as possible. For example, if you want to play less video games, place you console’s HDMI cable in somewhere hard to reach, so it will be much harder to start playing instantly.

Section 4: Make is satisfying

It’s as clear as sunshine that if you enjoy what you do, you will do in again and again and again. In this part of Atomic Habits, James Clear, the author, suggests some techniques to make your habits enjoyable.

Make your progress visible

Making progress while doing something is enjoyable and motivating; but, sometimes the process is hidden. For example, when losing weight, the first day you stick to a diet plan could have no visual effect on you but you have definitely progressed. One way to make the process enjoyable is by making hidden progresses visible. This is why calorie counter applications have such huge effect on people who are willing to lose weight. Because they see a visual progress from day one.

Find companions

I was going hiking almost every week with my friends. Nowadays, because of the COVID-19 pandemic I have to go alone. Because of this, I lost my willpower to go hiking every week. I skipped some weeks and to tell you the truth, I went hiking just once in the previous month. When you find some companions, they encourage you and boost your willpower to stick to a habit.

Conclusion

I believe when you read a book especially a self-improvement one, you should apply it to your own life if you find it interesting and practical. That’s why I have tried to apply this book and some other self-help books I find useful for myself. I believe if you can evolve good habits in yourself, it will change your life. For example, if you can institutionalize waking up early every morning and stick to it, it will change all aspects of your life.

When you want to build a new habit or quit a bad one, the following table could be very useful:

  Good habits Bad habits
Law #1 Make it obvious Make in invisible
Law #2 Make it attractive Make it unattractive
Law #3 Make it easy Make it difficult
Law #4 Make it satisfying Make it unpleasant

I highly recommend this book to everyone who care about productivity and will to change.

File upload using Gin

This post is my third post covering concepts of Gin , the HTTP web framework for Go. My previous post are:

In the RESTful era, most of our requests and responses’ payloads are JSON. However, in some cases, you may want to upload a file instead. In this post I’m going to describe how to receive and save an uploaded file using Gin framework.

The most common way to upload a file in a web browser is via the html file upload element (<input type="file" />). To be able to let the server know that you’re uploading a file, the request’s Content-Type header must be set to multipart/form-data. Here’s an example function for sending a file to a server using ReactJS and Axios:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import Axios from 'axios';

uploadFile = (file) => {
    const formData = new FormData();
    formData.append('file', file);
    Axios.post("https://example.com/upload", formData, {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
      })
      .then((resp) => {
        if (resp.status === 200) {
          console.log('File uploaded')
        }
      })
}

If everything goes fine, the file will be sent to the server. Now it’s time to get the file and save it some where in our server. Fortunately, Gin provides a very simply way to receive files. Gin’s Context argument (which all route handlers must have) has a FromFile method which helps you receive files from a multi-part content. Please take a look the following example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import (
    "net/http"
    "path/filepath"

    "github.com/gin-gonic/gin"
    "github.com/google/uuid" // To generate random file names
)

func saveFileHandler(c *gin.Context) {
    file, err := c.FromFile("file")

    // The file cannot be received.
    if err != nil {
        c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
            "message": "No file is received",
        })
        return
    }

    // Retrieve file information
    extension := filepath.Ext(file.Filename)
    // Generate random file name for the new uploaded file so it doesn't override the old file with same name
    newFileName := uuid.New().String() + extension

    // The file is received, so let's save it
    if err := c.SaveUploadedFile(file, "/some/path/on/server/" + newFileName); err != nil {
        c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{
            "message": "Unable to save the file",
        })
        return
    }

    // File saved successfully. Return proper result
    c.JSON(http.StatusOK, gin.H{
        "message": "Your file has been successfully uploaded."
    })
}

As you can see in the above code, saveFileHandler is responsible for receiving and saving the file to the server. In line 10, we try to receive the uploaded file with the name file; then we check if the file is received successfully. To avoid conflicts, in line 23, we change the file name to a random string (UUID in this case). Finally, we attempt to save the file using Gin’s SaveUploadedFile method and check if the save is saved. To handle errors, we return proper responses if any errors occurred. If every goes well and we could save the file to our path, we return the 200 OK response to the client.

The above is a general example. You may want to validate the file you receive. In some cases, you just need to receive image files; so, file types should be validated. In addition, you may want to resize the received image before saving it.

How to enable CORS support in Gin

It’s about 3 months that I’m trying to do some real work in Go and my HTTP framework of choice is Gin.

After developing some REST APIs, I decided to create a frontend application to actually use them. When it comes to frontend development I usually choose ReactJS. Maybe I should write about why I like ReactJS over other frontend frameworks in the future ;)

When a client especially a web-based client wants to access an API, the server decides which clients are allowed to send requests. This is done by using called CORS which stands for Cross-origin resource sharing.

Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources on a web page to be requested from another domain outside the domain from which the first resource was served.

For more information about CORS please check this Wikipedia article

You can manually add the required headers to each response using Gin’s Header method if you want:

1
2
3
4
5
6
7
8
9
10
func CustomHeaderAPI(c *gin.Context) {
    // Add CORS headers
    c.Header("Access-Control-Allow-Origin", "http://example.com")
    c.Header("Access-Control-Allow-Methods", "PUT, POST, GET, DELETE, OPTIONS")

    // Prepare response
    c.JSON(http.StatusOK, gin.H{
        "message": "this response has custom headers"
    })
}

But it would be a pain in the neck to add the following lines of code to each API. To make things easier Gin supports middleware functions.

What are middleware functions? This is a good definition I found on the web:

Middleware functions are functions that have access to the request object ( req ), the response object ( res ), and the next function in the application’s request-response cycle.

You may create a middleware yourself to enable CORS support; but, we don’t want to reinvent the wheel! A group of nice people in the community has developed a library to enable CORS support in Gin. It’s called CORS gin’s middleware.

To install it:

1
go get github.com/gin-contrib/cors

After installed, simply import it:

1
import "github.com/gin-contrib/cors"

And start using it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
 "time"

 "github.com/gin-contrib/cors"
 "github.com/gin-gonic/gin"
)

func main() {
 router := gin.Default()
 // CORS for https://foo.com and https://github.com origins, allowing:
 // - PUT and PATCH methods
 // - Origin header
 // - Credentials share
 // - Preflight requests cached for 12 hours
 router.Use(cors.New(cors.Config{
  AllowOrigins:     []string{"https://foo.com"},
  AllowMethods:     []string{"PUT", "PATCH"},
  AllowHeaders:     []string{"Origin"},
  ExposeHeaders:    []string{"Content-Length"},
  AllowCredentials: true,
  AllowOriginFunc: func(origin string) bool {
   return origin == "https://github.com"
  },
  MaxAge: 12 * time.Hour,
 }))
 router.Run()
}

The above configuration is the most complete example of what capabilities the library gives you. However, you may don’t want to use them all. In fact, most of the projects’ CORS configuration are identical. To make it even simpler, cors package also has something called DefaultConfig which returns a generic default configuration mapped to localhost. In my opinion, the best way to use this library is to add your custom configurations to the DefaultConfig’s result. For example, here is my own configuration for a project:

1
2
3
4
5
6
7
8
9
10
11
12
router := gin.Default()
corsConfig := cors.DefaultConfig()

corsConfig.AllowOrigins = []string{"https://example.com"}
// To be able to send tokens to the server.
corsConfig.AllowCredentials = true

// OPTIONS method for ReactJS
corsConfig.AddAllowMethods("OPTIONS")

// Register the middleware
router.Use(cors.New(corsConfig))

Please support the library by star them on Github: https://github.com/gin-contrib/cors

I Hope it helps.

How to use custom HTTP methods in Go Gin framework

The Gin framework is probably the most popular Go framework for creating RESTful APIs. It lets you create a web app in a matter of minutes.

When it comes to RESTful APIs, HTTP methods and status codes become very important. It’s a best practice to divide your APIs’ functionalities with different HTTP methods. For example, the method POST is used when want to add something to the database while the verb PUT is used for updating an entity.

By some conventions, some developers prefer to use custom verbs like LIST, ASSIGN, LOGIN, and etc. as well. For instance, if a list of all categories need to be retrieved, instead of using the GET method, LIST can be used. Gin supports the most common HTTP methods by default. These methods are GET, POST, PUT, DELETE, HEAD, PATCH, and OPTIONS.

Here is an example of a very simple web API using Gin:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import (
 "net/http"

 "github.com/gin-gonic/gin"
)

func main() {
 router := gin.Default()
 router.GET("/hello", sayHello)
 router.Run(":3000")
}

func sayHello(c *gin.Context) {
 c.JSON(http.StatusOK, gin.H{
  "message": "Hello!!",
 })
}

But what if you want to use some custom HTTP methods? In this case Gin provides a some lower level method called Handle. Please take a look at the following example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
 "net/http"

 "github.com/gin-gonic/gin"
)

func main() {
 router := gin.Default()
 router.GET("/hello", sayHello)
 router.Handle("LIST", "/get", getList)
 router.Run(":3000")
}

func sayHello(c *gin.Context) {
 c.JSON(http.StatusOK, gin.H{
  "message": "Hello!!",
 })
}

func getList(c *gin.Context) {
 // Gets the list of all categories
}

As you can see in the above example, instead of using the built-in methods, you can use the Handle method to use custom HTTP verbs. the Handle method takes three arguments instead of two, and the first argument is the method name in string. Using this you can have whatever method you prefer.

Hope it helps.

How to fix VSCode's Go extension high CPU usage

Writing Go code could be much easier if you use an IDE or text-editor plugin. Fortunately, there are some very good plugins for my text-editors of choice:

  • vim-go plugin for VIM which provides Golang language support
  • and Go extension for VSCode which provides the same functionality in Visual Studio Code.

The VSCode Go plugin however has an issue (or maybe misconfiguration): When using Go modules, the extension causes high CPU load!

The problem

To be able to solve a problem we must first identify exactly what the problem is. When writing code in any language, VSCode is constantly running process(es) in background to be able to suggest autocompletion, intellisense, auto imports, and etc.

By default, the VSCode’s Go plugin uses gocode tool to be able to provide autocompletion which is, as far as I understood, very slow and CPU intensive. This is an screenshot of macOS activity monitor when writing Go code in VSCode:

GoCode high CPU load

The solution

To be able to provide autocompletion, the Go team provided gopls.

gopls (pronounced: “go please”) is the official language server for the Go language.

I’m not sure why the extension is not using the Go’s default gopls tool for autocompletion. Maybe because the Go extension for VSCode was originally developed by Microsoft; but, recently it is maintained by the Go team at Google. As written in Go extension page:

This is the new home for the VS Code Go extension. We just migrated from Microsoft/vscode-go. Learn more about our move on the Go blog.

Maybe they change it in future.

The good news is that you can change the configuration! All we need to do is to tell VSCode to use the gopls language server instead of gocode tool. To make coding in Go more enjoyable, I suggest to turn formatOnSave and organizeImports on as well.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
"go.useLanguageServer": true,
"go.buildOnSave": "off",
"[go]": {
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
        "source.organizeImports": true,
    },
    "editor.snippetSuggestions": "none",
},
"[go.mod]": {
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
        "source.organizeImports": true,
    },
},
"gopls": {
    "usePlaceholders": true
}

Note: In some cases, gopls tool may not be installed. If so, you can install it manually:

go get -u golang.org/x/tools/gopls

I saw a significant performance increase After switching to gopls and it became more enjoyable to write Go code. I hope you experience the same.