<?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: Le Xuan Kha (Leo)</title>
    <description>The latest articles on DEV Community by Le Xuan Kha (Leo) (@khaleo).</description>
    <link>https://dev.to/khaleo</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%2F572562%2F2b7e10ff-d4ea-45ad-bd26-88264cd5e5ab.jpg</url>
      <title>DEV Community: Le Xuan Kha (Leo)</title>
      <link>https://dev.to/khaleo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/khaleo"/>
    <language>en</language>
    <item>
      <title>Golang Design Patterns - Proxy</title>
      <dc:creator>Le Xuan Kha (Leo)</dc:creator>
      <pubDate>Tue, 04 Feb 2025 04:29:43 +0000</pubDate>
      <link>https://dev.to/khaleo/golang-design-patterns-proxy-2ni9</link>
      <guid>https://dev.to/khaleo/golang-design-patterns-proxy-2ni9</guid>
      <description>&lt;h2&gt;
  
  
  I. Proxy - Structural Pattern
&lt;/h2&gt;

&lt;p&gt;The Proxy is a familiar Design Pattern for developers, used to represent an original resource. The Proxy provides functionalities similar to the original resource but with high customizability.&lt;/p&gt;

&lt;p&gt;The Proxy acts as a substitute for the original resource, hiding complex details or adding necessary features such as access control, caching, or load balancing.&lt;/p&gt;

&lt;h2&gt;
  
  
  II. Real-world Example
&lt;/h2&gt;

&lt;p&gt;The system frequently needs to query user information from a main database. However, directly querying the main database can increase latency and reduce system performance. Therefore, we use a Proxy that acts as a cache to temporarily store frequently queried data.&lt;/p&gt;

&lt;p&gt;The Proxy checks the cache, and if the data exists in the cache, it returns it immediately. Otherwise, it queries the main database and updates the cache.&lt;/p&gt;

&lt;p&gt;This use case introduces the mechanism of a Proxy for searching users (User) between the MainDB (main database) and the Stack (cache) to improve performance.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Definition of User:&lt;br&gt;
A User only has an ID attribute (int), representing a user entity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Shared Interface:&lt;br&gt;
The UserFinder interface defines the Find(ID int) method to search for a user by their ID. Both MainDB and Stack adhere to this interface.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Main Database (MainDB):&lt;br&gt;
The main database where users are stored. UsersDB provides the Find function to search for a user and the Add function to add a new user.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Proxy (UserFinderProxy):&lt;br&gt;
The Proxy is a middle layer that uses the Stack (cache memory) for faster access before searching in the MainDB.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;When a User is not in the Stack, the Proxy checks the MainDB.&lt;/li&gt;
&lt;li&gt;If the user is found, the Proxy saves the User in the Stack to optimize subsequent queries.&lt;/li&gt;
&lt;li&gt;The Stack has a capacity-limiting mechanism and auto-updates when full.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The class diagram for the above scenario would be depicted as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fnnjj9i4u581ez2gfb74s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fnnjj9i4u581ez2gfb74s.png" alt="Proxy Class Diagram" width="523" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  III. Implementation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Definition of the Interface User entity:
&lt;/li&gt;
&lt;/ul&gt;

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

type User struct {
    ID int
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Definition of the Interface:
&lt;/li&gt;
&lt;/ul&gt;

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

type UserFinder interface {
    Find(ID int) (User, error)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Definition of Database
&lt;/li&gt;
&lt;/ul&gt;

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

import "fmt"

type UsersDB []User

func (u *UsersDB) Find(ID int) (User, error) {
    for _, user := range *u {
        if user.ID == ID {
            return user, nil
        }
    }
    return User{}, fmt.Errorf("user not found")
}

func (u *UsersDB) Add(user User) *UsersDB {
    fmt.Println("Adding to database: ", user)
    *u = append(*u, user)
    return u
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Definition of Proxy:
&lt;/li&gt;
&lt;/ul&gt;

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

import "fmt"

type UsersStack []User

func (u *UsersStack) Find(ID int) (User, error) {
    for _, user := range *u {
        if user.ID == ID {
            return user, nil
        }
    }
    return User{}, fmt.Errorf("user not found")
}

func (u *UsersStack) Add(user User) *UsersStack {
    *u = append(*u, user)
    return u
}

type UserFinderProxy struct {
    MainDB   UsersDB
    Stack    UsersStack
    Capacity int
}

func (u *UserFinderProxy) Find(ID int) (User, error) {
    user, err := u.Stack.Find(ID)
    if err == nil {
        fmt.Println("Found in stack: ", user)
        return user, nil
    }

    user, err = u.MainDB.Find(ID)
    if err != nil {
        return User{}, err
    }

    fmt.Println("Found in mainDB: ", user)
    u.AddToStack(user)
    return user, nil
}

func (u *UserFinderProxy) AddToStack(user User) error {
    fmt.Println("Adding to stack: ", user)
    if len(u.Stack) &amp;gt;= u.Capacity {
        u.Stack = append(u.Stack[1:], user)
    } else {
        u.Stack.Add(user)
    }
    return nil
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Run the application:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/*
        Example Proxy
    */
    fmt.Println("*** Example Proxy ***")

    mainDB := proxy.UsersDB{}

    user1 := proxy.User{ID: 1}
    user2 := proxy.User{ID: 2}
    user3 := proxy.User{ID: 3}

    mainDB.Add(user1).Add(user2).Add(user3)

    proxy := proxy.UserFinderProxy{
        MainDB:   mainDB,
        Stack:    proxy.UsersStack{},
        Capacity: 2,
    }

    proxy.Find(1)
    proxy.Find(2)
    proxy.Find(3)
    proxy.Find(2)
    proxy.Find(1)

    fmt.Print("*** End of Proxy ***\n\n\n")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fqzbipq85yca7nv09l5ug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fqzbipq85yca7nv09l5ug.png" alt="Output" width="364" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  IV. Explain the example above
&lt;/h2&gt;

&lt;p&gt;This example illustrates how the Proxy pattern works through querying users (User) from the main database (MainDB) while using a stack-based cache (Stack) to optimize repeated search operations. Below is the step-by-step explanation:&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;1. Initializing the Main Database (MainDB)&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;mainDB&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UsersDB&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="n"&gt;user1&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;user2&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;user3&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;mainDB&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;A main database (&lt;code&gt;MainDB&lt;/code&gt;) is initialized, which holds a list of users (&lt;code&gt;UsersDB&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Three users with IDs &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, and &lt;code&gt;3&lt;/code&gt; are added to the &lt;code&gt;MainDB&lt;/code&gt;. Any query will be able to find these users if searched directly in &lt;code&gt;MainDB&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Log results:&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;Adding to database:  {1}
Adding to database:  {2}
Adding to database:  {3}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;2. Initializing the Proxy with MainDB and Stack&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;proxy&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserFinderProxy&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;MainDB&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;mainDB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Stack&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UsersStack&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="n"&gt;Capacity&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;UserFinderProxy&lt;/code&gt; is created with the following components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MainDB:&lt;/strong&gt; The primary database that stores all the users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stack:&lt;/strong&gt; A cache layer that is initially empty.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capacity:&lt;/strong&gt; The maximum number of users that the &lt;code&gt;Stack&lt;/code&gt; can hold (set to &lt;code&gt;2&lt;/code&gt; here).&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;3. Searching for Users&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;First Search: &lt;code&gt;proxy.Find(1)&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Proxy checks for ID &lt;code&gt;1&lt;/code&gt; in the Stack but finds nothing (Stack is initially empty).&lt;/li&gt;
&lt;li&gt;Proxy switches to searching in the &lt;code&gt;MainDB&lt;/code&gt; and finds the user with ID &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The proxy adds this user to the Stack for faster future queries.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Log results:&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;Found in mainDB:  {1}
Adding to stack:  {1}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  &lt;strong&gt;Second Search: &lt;code&gt;proxy.Find(2)&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Proxy checks for ID &lt;code&gt;2&lt;/code&gt; in the Stack but does not find it.&lt;/li&gt;
&lt;li&gt;Proxy searches the &lt;code&gt;MainDB&lt;/code&gt;, finds the user with ID &lt;code&gt;2&lt;/code&gt;, and adds it to the Stack.&lt;/li&gt;
&lt;li&gt;The Stack now contains two users: &lt;code&gt;{1, 2}&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Log results:&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;Found in mainDB:  {2}
Adding to stack:  {2}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  &lt;strong&gt;Third Search: &lt;code&gt;proxy.Find(3)&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Proxy checks for ID &lt;code&gt;3&lt;/code&gt; in the Stack but does not find it.&lt;/li&gt;
&lt;li&gt;Proxy searches the &lt;code&gt;MainDB&lt;/code&gt; and finds the user with ID &lt;code&gt;3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Stack&lt;/code&gt;, already at full capacity (&lt;code&gt;2&lt;/code&gt;), operates on a FIFO (First In, First Out) mechanism:

&lt;ul&gt;
&lt;li&gt;It removes the oldest user (User with ID &lt;code&gt;1&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Then, it adds the new user (&lt;code&gt;3&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The Stack now contains &lt;code&gt;{2, 3}&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Log results:&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;Found in mainDB:  {3}
Adding to stack:  {3}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  &lt;strong&gt;Fourth Search: &lt;code&gt;proxy.Find(2)&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Proxy checks for ID &lt;code&gt;2&lt;/code&gt; in the Stack and finds it directly.
&lt;/li&gt;
&lt;li&gt;No need to query the &lt;code&gt;MainDB&lt;/code&gt;—the search is instant.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Log results:&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;Found in stack:  {2}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  &lt;strong&gt;Fifth Search: &lt;code&gt;proxy.Find(1)&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Proxy checks for ID &lt;code&gt;1&lt;/code&gt; in the Stack but does not find it (it was removed earlier).&lt;/li&gt;
&lt;li&gt;Proxy searches the &lt;code&gt;MainDB&lt;/code&gt; and finds the user with ID &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Stack&lt;/code&gt;, at capacity, removes the oldest user (User with ID &lt;code&gt;3&lt;/code&gt;) and adds the new user (&lt;code&gt;1&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The Stack now contains &lt;code&gt;{2, 1}&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Log results:&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;Found in mainDB:  {1}
Adding to stack:  {1}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;4. End of Example&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Final State:&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stack:&lt;/strong&gt; Contains &lt;code&gt;{2, 1}&lt;/code&gt; (the two most recently queried users).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MainDB:&lt;/strong&gt; Remains unchanged, containing all users &lt;code&gt;{1, 2, 3}&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Final Log:&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;*** End of Proxy ***
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;For each query, the Proxy first checks the Stack to quickly locate the User.&lt;/li&gt;
&lt;li&gt;If the User is not found in the Stack, the Proxy searches the MainDB and adds the result to the Stack for optimized future searches.&lt;/li&gt;
&lt;li&gt;The Stack has a capacity limit, and when it is exceeded, the oldest User is removed (FIFO – First In, First Out).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Advantages of this approach:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduces the number of accesses to the MainDB when Users are queried repeatedly.&lt;/li&gt;
&lt;li&gt;Improves system performance by utilizing the cache (Stack) for faster lookups.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  V. Conclusion
&lt;/h2&gt;

&lt;p&gt;We do not always need to use the Proxy design pattern to address similar problems. In some cases, direct access to the database might suffice if the problem is not complex or performance optimization is not required. In other situations, you might consider using the Decorator pattern or other optimization techniques.&lt;/p&gt;

&lt;p&gt;The most important thing is to choose the solution that best fits your specific problem.&lt;/p&gt;

&lt;p&gt;Thank you for taking the time to read this article! 😊&lt;/p&gt;

&lt;h2&gt;
  
  
  VI. References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Go Design Patterns (Mario Castro Contreras)&lt;/li&gt;
&lt;li&gt;Full source code for Go design patterns: available &lt;a href="//github.com/khaaleoo/golang-design-patterns"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>designpatterns</category>
      <category>proxypattern</category>
      <category>go</category>
      <category>caching</category>
    </item>
    <item>
      <title>Building a personal blog with Next.js and Notion</title>
      <dc:creator>Le Xuan Kha (Leo)</dc:creator>
      <pubDate>Fri, 21 Jun 2024 07:18:11 +0000</pubDate>
      <link>https://dev.to/khaleo/building-a-personal-blog-with-nextjs-and-notion-49mo</link>
      <guid>https://dev.to/khaleo/building-a-personal-blog-with-nextjs-and-notion-49mo</guid>
      <description>&lt;p&gt;In this article, we will together build the fastest blog for yourself with Next.js and Notion.&lt;/p&gt;

&lt;h1&gt;
  
  
  I. Prerequisites
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://www.notion.so/" rel="noopener noreferrer"&gt;Notion&lt;/a&gt; is certainly no stranger to everyone. It is an AI-powered workspace that helps users easily plan, take notes, and integrate with many other applications, making it very convenient.&lt;/p&gt;

&lt;p&gt;In terms of the idea, we will use Notion as a CMS to manage post information, and Next.js to display that information for users while leveraging SSR to improve SEO and security.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Knowledge of Next.js&lt;/li&gt;
&lt;li&gt;Personal Notion account&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  II. Create a database and access token in Notion
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Select a page in Notion to store the database. &lt;/li&gt;
&lt;li&gt;Add a new element and choose Database - Full page: 
&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%2Fgc991nlae586foenou5q.png" alt="Add a new element and choose Database"&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create the following fields for the database, specifying their type and purpose as follows (these fields are for demo purposes, you can modify them later):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Title: Already created as Name, change it to Title&lt;/li&gt;
&lt;li&gt;Tags (Multi-select): Topic tags&lt;/li&gt;
&lt;li&gt;Description (Text): Brief description of the post&lt;/li&gt;
&lt;li&gt;PresentativeMedia (Files &amp;amp; media): To store the featured image for the post&lt;/li&gt;
&lt;li&gt;Slug (Text): Used as the post's URL&lt;/li&gt;
&lt;li&gt;Status (Status): Post status, including Draft, Published 
&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%2Fjmmiczosz9ace6pk3g17.png" alt="Create fields for the database"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, you can access notion-integration to generate a secret token linked to your personal Notion account, which will be used to create the above database. Remember to select only the Read permission: Read content, as shown in the image 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%2Fxtmbw7oq8eonj76mswkv.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%2Fxtmbw7oq8eonj76mswkv.png" alt="notion-integration"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After creating the notion-integration, the next step is to allow this integration to access the database. In the Connect to section, choose the integration you just created (I just created for-show-sample), as shown in the image 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%2F1on93m0uwl35pg20t5st.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%2F1on93m0uwl35pg20t5st.png" alt="allow this integration to access the database."&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  III. Create sample records in database
&lt;/h1&gt;

&lt;p&gt;Based on the created database structure, we will create some sample records as follows. Note that the status of the posts should be changed to &lt;strong&gt;Published&lt;/strong&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%2Fw957uqgmjnphfzueo2tq.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%2Fw957uqgmjnphfzueo2tq.png" alt="Create sample records"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  IV. Using notion-nextjs-mini-kit
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;You can follow the instructions to clone and run the NextJs source code on your machine &lt;a href="https://github.com/khaaleoo/notion-nextjs-mini-kit" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As per the installation instructions, you will need to replace 2 environment variables.&lt;br&gt;
&lt;code&gt;NOTION_TOKEN=&lt;br&gt;
NOTION_DATABASE_ID=&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
With:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Notion token is the token generated from Step II.&lt;/li&gt;
&lt;li&gt;To get the database ID from the database we created, simply open the database page in the browser and copy the string as shown in the image.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run the NextJs application above and you will see the results as follows&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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%2Fpst3txm8j7xv7ru5dse4.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%2Fpst3txm8j7xv7ru5dse4.png" alt="Result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  V. Create content for the page
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create content for the pages based on the data created in the previous database.&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%2Fkgf4nuwsklw5z2i3stbu.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%2Fkgf4nuwsklw5z2i3stbu.png" alt="Create content for the page"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Publish the posts (select share -&amp;gt; publish)&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%2Fj1yr1cfq4csobpu4ja99.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%2Fj1yr1cfq4csobpu4ja99.png" alt="Publish the posts"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Return to our website, click on one of the previous posts to see the results 🎉&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%2Fkkxmaeubpopy7xxv7co6.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%2Fkkxmaeubpopy7xxv7co6.png" alt="see the results"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  VI. Conclusion
&lt;/h1&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;notion-nextjs-mini-kit: &lt;a href="https://github.com/khaaleoo/notion-nextjs-mini-kit" rel="noopener noreferrer"&gt;https://github.com/khaaleoo/notion-nextjs-mini-kit&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On this guide, I have shown you how to quickly create a personal blog using NextJs and Notion as a database. If you have any questions or contributions, please leave a comment below. Thank you everyone.&lt;/p&gt;

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

</description>
      <category>notion</category>
      <category>nextjs</category>
      <category>cms</category>
      <category>seo</category>
    </item>
    <item>
      <title>Security Risk - Timing Attack - Challenging but Entirely Feasible</title>
      <dc:creator>Le Xuan Kha (Leo)</dc:creator>
      <pubDate>Fri, 21 Jul 2023 08:31:33 +0000</pubDate>
      <link>https://dev.to/khaleo/security-risk-timing-attack-challenging-but-entirely-feasible-1cd6</link>
      <guid>https://dev.to/khaleo/security-risk-timing-attack-challenging-but-entirely-feasible-1cd6</guid>
      <description>&lt;p&gt;Timing Attack is one of the techniques that hackers exploit by leveraging server-side computations to adjust attack payloads accordingly. &lt;/p&gt;

&lt;p&gt;In this article, I will present the most common example of this type of attack and discuss prevention methods using Golang.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  I. Timing Attack
&lt;/h2&gt;

&lt;p&gt;Timing Attack is a type of side-channel attack in which hackers exploit information obtained from the real-time execution time of a specific logic within a system to gradually deduce the final result. It can be considered a form of manual brute force, as it employs a similar method to deduce the result, but the difference lies in the fact that the hacker needs to invest more effort in analyzing the existing data to determine the next input.&lt;/p&gt;

&lt;p&gt;Hackers always attempt to take advantage of programming oversights in commonly used logical code segments, which are often trivialized. They also target vulnerabilities present in popular open-source libraries commonly used by developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  II. Real-world Example
&lt;/h2&gt;

&lt;p&gt;For developers, there are cases where it is necessary to authenticate requests from clients or server-to-server communication. There are various ways to implement this, typically using JWT, OAuth2, OpenID Connect, or third-party authentication services like Google, Facebook, AWS Cognito, etc. One of the common and easy-to-implement methods is using an API key.&lt;/p&gt;

&lt;p&gt;However, API keys can still be compromised through several attack vectors, one of which is Timing Attack.&lt;/p&gt;

&lt;h2&gt;
  
  
  III. Preventing Timing Attacks
&lt;/h2&gt;

&lt;p&gt;While it may be tempting to resort to extreme measures like disconnecting from the internet or using an "invulnerable" application to deter hackers, these approaches are impractical. We cannot completely eliminate the risk of a system being attacked, but by understanding the techniques involved, we can make the hacker's path more difficult.&lt;/p&gt;

&lt;p&gt;Let's use Golang as an example for the situation mentioned above. When using an API key, there will undoubtedly be a logic section that performs a comparison between the API key sent with the request and the key stored on the server. Typically, developers use the default comparison operator (e.g., "==") for this purpose, which may seem simple. However, in reality, this can be exploited by hackers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;      &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;
    &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1e8&lt;/span&gt;
    &lt;span class="n"&gt;bound&lt;/span&gt;  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;copyStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;changedIndex&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;changedIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;changedIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;changedIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;formatString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Itoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"."&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;bound&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;copyStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;endTime&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Since&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Differences at Index: %s, time execute: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;formatString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;endTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;CompareConstantTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;subtle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConstantTimeCompare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above compares two strings of equal length, but if there is a difference at any index, the == operator stops the comparison and returns the result immediately. This timing discrepancy can be exploited by hackers to deduce the correct API key by observing the different execution times for incorrect and partially correct matches.&lt;/p&gt;

&lt;p&gt;We used &lt;strong&gt;subtle.ConstantTimeCompare&lt;/strong&gt; function in the above code to ensure a constant-time comparison. It returns 1 if the two strings are equal, 0 if they are different, and immediately returns 0 if the lengths of the strings are not the same. By using this method, we eliminate timing discrepancies, making it harder for attackers to deduce information based on the time taken for the comparison.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Length of chars: %s&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;formatString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Normal comparison: using equal operator"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Compare&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Constant time comparison: using subtle.ConstantTimeCompare"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CompareConstantTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the result:&lt;/p&gt;

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

&lt;p&gt;In regular string comparison, the execution time increases as the differences between the strings move towards the end. However, with ConstantTimeCompare, the execution time remains nearly the same, regardless of where the differences occur in the strings.&lt;/p&gt;

&lt;h2&gt;
  
  
  IV. Conclusion
&lt;/h2&gt;

&lt;p&gt;In reality, the execution time can be influenced by various factors like network latency, different threads, and more. Achieving precise results may require conducting multiple trials to minimize any discrepancies. While Timing Attacks are challenging to execute successfully due to these complexities, they are still possible.&lt;/p&gt;

&lt;p&gt;Using ConstantTimeCompare does come with a time cost, so it's best to employ it only when truly necessary. In cases where security and protection against Timing Attacks are critical, it's worth the investment.&lt;/p&gt;

&lt;p&gt;Thank you all for reading this article.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Rate Limiter in System Design. Part 2 - Commonly Used Algorithms</title>
      <dc:creator>Le Xuan Kha (Leo)</dc:creator>
      <pubDate>Wed, 28 Jun 2023 18:10:54 +0000</pubDate>
      <link>https://dev.to/khaleo/rate-limiter-in-system-design-part-2-commonly-used-algorithms-45bp</link>
      <guid>https://dev.to/khaleo/rate-limiter-in-system-design-part-2-commonly-used-algorithms-45bp</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/khaleo/rate-limiter-in-system-design-part-1-concepts-and-applications-1b6n"&gt;Part 1&lt;/a&gt;, I provided a general introduction at the conceptual level. In this Part 2, I will discuss the most commonly used algorithms when building a Rate Limiter system. Each algorithm has its own advantages and disadvantages, so let's explore them together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Leaky Bucket
&lt;/h2&gt;

&lt;p&gt;Conceptually, the Leaky Bucket algorithm operates as follows. The server utilizes a fixed-sized bucket and the bottom of the bucket has a hole (output) to hold a certain number of tokens. In this context, a token represents a request sent to the server.&lt;/p&gt;

&lt;p&gt;Tokens are sent to the server by the user (client), and the server acts as the agent that allows tokens to enter or exit the bucket.&lt;/p&gt;

&lt;p&gt;To facilitate visualization, you can refer to the accompanying illustration below:&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%2Fmtt118gy3pkr2j1ip43i.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%2Fmtt118gy3pkr2j1ip43i.png" alt="Leaky Bucket Sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Leaky Bucket algorithm is not overly complex to implement and maintain on a server or load balancer. Memory management is also relatively straightforward as everything can be configured from the beginning. Due to its high accuracy and efficient resource utilization, many large-scale systems utilize the Leaky Bucket algorithm as a Rate Limiter, with &lt;a href="https://www.nginx.com/blog/rate-limiting-nginx/" rel="noopener noreferrer"&gt;NGINX&lt;/a&gt; being a notable example.&lt;/p&gt;

&lt;p&gt;Despite its many advantages, the Leaky Bucket algorithm also has some drawbacks:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Burstiness&lt;/strong&gt;: One drawback of the Leaky Bucket algorithm is that it does not handle sudden or bursty loads of requests well. When a large number of requests arrive at the same time, the algorithm has to process all of them within the same time frame. This can lead to overload and decreased system performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Delayed response:&lt;/strong&gt; The Leaky Bucket algorithm can result in delayed response for access requests that occur after a prolonged "idle" interval, where no requests are being processed. In such cases, the "leak" of requests from the bucket only occurs when the next interval begins, resulting in a longer waiting time for the requests to be processed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lack of flexibility&lt;/strong&gt; in handling prioritized or urgent requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation errors&lt;/strong&gt;: If there is a mistake in implementing the algorithm and the bucket is not handled correctly, some requests may be accepted and processed even though the request rate has exceeded the set limit. This can allow a large number of requests to flood the system, causing overload and potentially making the server unstable or slow.&lt;/p&gt;

&lt;p&gt;It's important to consider these limitations and evaluate whether the Leaky Bucket algorithm is suitable for specific use cases or if alternative rate limiting algorithms should be employed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixed Window Counter
&lt;/h2&gt;

&lt;p&gt;The Fixed Window Counter algorithm (abbreviated as FWC) differs from the Leaky Bucket algorithm as it is based on time rather than using a dynamically allocated capacity to control requests. FWC divides time into equal intervals, and each interval has its own counter. When a request arrives, based on the timestamp, the request is allocated to the predefined interval, and the corresponding counter operates (e.g., increments by 1).&lt;/p&gt;

&lt;p&gt;When the counter reaches a certain threshold, the request is denied execution and either needs to wait or retry in the next time interval.&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%2Fyz7c5s7oa2l4epw07182.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%2Fyz7c5s7oa2l4epw07182.png" alt="Fixed Window Counter Sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the Fixed Window Counter algorithm, we have the following complexities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Space Complexity: O(1) for storing the counter for each window.&lt;/li&gt;
&lt;li&gt;Time Complexity: O(1) for performing operations like Get and incrementing the counter, as they are simple operations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Fixed Window Counter algorithm offers several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Easy implementation: The algorithm is relatively simple to implement, as it involves dividing time into fixed intervals and maintaining counters for each interval.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lower memory usage: The algorithm requires minimal memory usage, as it only needs to store the counters for each window.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compatibility with built-in concurrency technologies: The Fixed Window Counter algorithm can leverage built-in concurrency technologies such as Redis, which provides efficient support for distributed and concurrent operations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, there are still several drawbacks to the Fixed Window Counter algorithm:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Lack of flexibility: Due to its reliance on pre-defined configurations, the algorithm lacks the ability to scale up dynamically when needed. Developers have to manually adjust the configurations for each campaign or when there is a sudden increase in request volume.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inherited issues from previous windows: The algorithm does not effectively address situations where a previous window exceeds the request limit. Subsequent windows may not be able to compensate for the excess requests, as the algorithm lacks the ability to dynamically adjust the capacity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inability to prioritize or handle urgent requests: The Fixed Window Counter algorithm treats all requests within a window equally and does not differentiate or prioritize urgent requests. This limitation may not be suitable for scenarios where certain requests require immediate processing.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sliding Window Log &amp;amp; Sliding Window Counter
&lt;/h2&gt;

&lt;p&gt;In the two aforementioned algorithms, although they are easy to implement, each has its own limitations. Sliding Window Log &amp;amp; Counter (SWLC) algorithm is used to mitigate some of these challenges.&lt;/p&gt;

&lt;p&gt;The Sliding Window Log &amp;amp; Counter algorithm (SWLC) stores and operates based on the executing agent. When a request is sent to the server, the system identifies the request based on specific criteria such as tokens, IP addresses, etc.&lt;/p&gt;

&lt;p&gt;SWLC commonly utilizes an SLA (Service Level Agreement) table, where it logs all user actions. It is a simple key-value structure, with the key consisting of the (token, IP) combination and the value representing the requested data sent by the user.&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%2F01naqusptyclun19am6a.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%2F01naqusptyclun19am6a.png" alt="Sliding Window Log &amp;amp; Sliding Window Counter Sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Sliding Window Log &amp;amp; Counter algorithm described in the diagram above sets a maximum limit of 2 requests per user within each window. The counter will track and reject any third request from the same user within the same time window.&lt;/p&gt;

&lt;p&gt;At its basic level, the Sliding Window Log &amp;amp; Counter algorithm has the following complexities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Space Complexity: O(number of requests read by the server in one window). The server needs to perform this task to identify the user/IP associated with each request.&lt;/li&gt;
&lt;li&gt;Time Complexity (Sliding Window Log): O(number of requests read by the server in one window)&lt;/li&gt;
&lt;li&gt;Time Complexity (Sliding Window Counter): O(1). This is a key difference between Sliding Window Counter (SWC) and Sliding Window Log (SWL). SWC only stores the current window (without the need to look back at previous windows).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The advantages of this algorithm include addressing the drawbacks of the two algorithms mentioned earlier and combining the three elements of quantity, agent, and time mentioned in Part 1. So, what are the disadvantages of this algorithm?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Difficult to implement: Combining all three factors certainly adds complexity to the implementation.&lt;/li&gt;
&lt;li&gt;Resource consumption: It requires significant memory usage for storing all users within a window.&lt;/li&gt;
&lt;li&gt;Complexity increases with the number of requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Here are some commonly used algorithms for building a Rate Limiter system. If there are any other algorithms or better ones, please let me and everyone else know!&lt;/p&gt;

&lt;p&gt;Thank you all&lt;/p&gt;

&lt;h2&gt;
  
  
  See more
&lt;/h2&gt;

&lt;p&gt;Part 1: &lt;a href="https://dev.to/khaleo/rate-limiter-in-system-design-part-1-concepts-and-applications-1b6n"&gt;Rate Limiter in System Design. Part 1 - Concepts and Applications&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ratelimiter</category>
      <category>systemdesign</category>
      <category>leakybucket</category>
      <category>fixedwindowcounter</category>
    </item>
    <item>
      <title>Rate Limiter in System Design - Part 1: Concepts and Applications</title>
      <dc:creator>Le Xuan Kha (Leo)</dc:creator>
      <pubDate>Mon, 26 Jun 2023 09:09:35 +0000</pubDate>
      <link>https://dev.to/khaleo/rate-limiter-in-system-design-part-1-concepts-and-applications-1b6n</link>
      <guid>https://dev.to/khaleo/rate-limiter-in-system-design-part-1-concepts-and-applications-1b6n</guid>
      <description>&lt;h1&gt;
  
  
  What is Rate Limiter
&lt;/h1&gt;

&lt;p&gt;In the simplest terms, a Rate Limiter restricts the number of access requests to a resource on a system from an agent (such as a user, browser, or another server) within a specific time frame.&lt;/p&gt;

&lt;p&gt;Based on several rate limiting techniques, when a violation or a defined threshold is reached, those requests will be blocked from accessing the system.&lt;/p&gt;

&lt;p&gt;The three key elements emphasized here are: quantity, agent, and time, which are also the core concepts of a Rate Limiter. These elements will be the focus of today's article.&lt;/p&gt;

&lt;h1&gt;
  
  
  Rate Limiters in Practical Examples
&lt;/h1&gt;

&lt;p&gt;Surely, you may have encountered or witnessed one of the following situations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;"The PIN for the card has been entered incorrectly more than 5 times. Please contact the bank to unlock the card."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In some applications, when you enter the wrong password multiple times, you receive a notification similar to: "The number of requests exceeds the allowed limit".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Typically, IP addresses from somewhere are easily blocked by foreign e-commerce websites due to previous attacks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When you request an OTP (One-Time Password) too many times within a minute, you have to wait until the designated time has passed before requesting a new OTP message.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are examples of practical situations where rate limiters or similar mechanisms are implemented to control and manage access, ensure security, and prevent abuse or unauthorized usage.&lt;/p&gt;

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

&lt;p&gt;If you pay close attention, you will notice that examples 1 and 2 are related to the quantity factor, example 3 addresses the agent factor, and finally, we have the time factor. These are indeed the core elements of a Rate Limiter, and a proper Rate Limiter typically combines all three of these factors together.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why do we need Rate Limiters?
&lt;/h1&gt;

&lt;p&gt;While the necessity of Rate Limiters depends on the specific system, in small to medium-scale environments, it may not be as critical for certain tasks. However, as systems grow larger in scale, it becomes increasingly important to consider and prioritize Rate Limiters. Here are some reasons why:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;: One of the primary reasons to implement Rate Limiters is to enhance security. They help mitigate various types of attacks, including Denial-of-Service (DoS) and Distributed Denial-of-Service (DDoS) attacks. Rate Limiters can also protect against brute force attacks, credential stuffing attacks, web scraping, and other malicious activities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resource Balancing&lt;/strong&gt;: Rate Limiters ensure that server resources are not overloaded and that resources are allocated fairly and reasonably to each user on the system. By controlling the rate of access, Rate Limiters help prevent resource exhaustion and ensure a smooth and efficient operation of the system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost Savings&lt;/strong&gt;: Having controlled access to resources can contribute to minimizing the overall system costs. By preventing excessive usage and optimizing resource allocation, Rate Limiters can help reduce infrastructure expenses and mitigate the need for additional resources due to uncontrolled growth.&lt;/p&gt;

&lt;p&gt;In summary, Rate Limiters are crucial for larger-scale systems as they play a significant role in maintaining security, balancing resource utilization, and optimizing costs.&lt;/p&gt;

&lt;h1&gt;
  
  
  Some commonly used algorithms in Rate Limiters include:
&lt;/h1&gt;

&lt;p&gt;Leaky Bucket: The Leaky Bucket algorithm regulates the rate of requests by imagining a bucket that can hold a certain number of tokens. Tokens are added to the bucket at a fixed rate, and each request consumes a token. If the bucket is full and a request arrives, it is considered to be overflowing and can be limited or discarded.&lt;/p&gt;

&lt;p&gt;Fixed Window Counter: This algorithm counts the number of requests within a fixed time window. If the count exceeds a predefined threshold, subsequent requests can be limited or blocked until the next window starts.&lt;/p&gt;

&lt;p&gt;Sliding Window Log: The Sliding Window Log algorithm maintains a log of request timestamps within a sliding time window. It calculates the number of requests within the window and compares it against a defined limit. If the limit is exceeded, requests can be limited or rejected.&lt;/p&gt;

&lt;p&gt;Sliding Window Counter: Similar to the Fixed Window Counter, this algorithm counts the number of requests within a sliding time window. However, it allows more flexibility by continuously sliding the window instead of using fixed time intervals.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://dev.to/khaleo/rate-limiter-in-system-design-part-2-commonly-used-algorithms-45bp"&gt;Part 2&lt;/a&gt; of the article, I will provide detailed explanations of these algorithms. Stay tuned!&lt;/p&gt;

&lt;p&gt;Thank you all for reading the article.&lt;/p&gt;

</description>
      <category>ratelimiter</category>
      <category>systemdesign</category>
      <category>leakybucket</category>
      <category>distributedsystems</category>
    </item>
  </channel>
</rss>
