<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Tuan</title>
    <description>The latest articles on Forem by Tuan (@tuannguyen_talan).</description>
    <link>https://forem.com/tuannguyen_talan</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%2F1232194%2F9d997edf-bd40-41e0-b35b-518eeffc125b.png</url>
      <title>Forem: Tuan</title>
      <link>https://forem.com/tuannguyen_talan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/tuannguyen_talan"/>
    <language>en</language>
    <item>
      <title>Refactor "switch" statements in case have large sets of "case" clauses</title>
      <dc:creator>Tuan</dc:creator>
      <pubDate>Sat, 09 Mar 2024 04:15:48 +0000</pubDate>
      <link>https://forem.com/tuannguyen_talan/refactor-switch-statements-in-case-have-large-sets-of-case-clauses-4cbm</link>
      <guid>https://forem.com/tuannguyen_talan/refactor-switch-statements-in-case-have-large-sets-of-case-clauses-4cbm</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;

public class SwitchRefactor {

    // Define actions for each case
    private static final Map&amp;lt;String, Consumer&amp;lt;String&amp;gt;&amp;gt; ACTION_MAP = new HashMap&amp;lt;&amp;gt;();

    static {
        ACTION_MAP.put("case1", SwitchRefactor::actionForCase1);
        ACTION_MAP.put("case2", SwitchRefactor::actionForCase2);
        // Add more cases as needed
    }

    // Method for executing action for case 1
    private static void actionForCase1(String param) {
        System.out.println("Executing action for case 1 with parameter: " + param);
    }

    // Method for executing action for case 2
    private static void actionForCase2(String param) {
        System.out.println("Executing action for case 2 with parameter: " + param);
    }

    // Method for executing actions based on the given case
    public static void executeAction(String caseValue, String param) {
        Consumer&amp;lt;String&amp;gt; action = ACTION_MAP.get(caseValue);
        if (action != null) {
            action.accept(param);
        } else {
            System.out.println("No action found for case: " + caseValue);
        }
    }

    public static void main(String[] args) {
        // Example usage
        String caseValue = "case1";
        String param = "example";
        executeAction(caseValue, param); // Output: Executing action for case 1 with parameter: example
    }
}

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

&lt;/div&gt;



</description>
      <category>java</category>
      <category>cleancode</category>
      <category>switch</category>
    </item>
    <item>
      <title>Dùng useReducer thay thế cho useState</title>
      <dc:creator>Tuan</dc:creator>
      <pubDate>Sat, 27 Jan 2024 15:26:08 +0000</pubDate>
      <link>https://forem.com/tuannguyen_talan/dung-usereducer-thay-the-cho-usestate-5edf</link>
      <guid>https://forem.com/tuannguyen_talan/dung-usereducer-thay-the-cho-usestate-5edf</guid>
      <description>&lt;h2&gt;
  
  
  Lý do
&lt;/h2&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%2Fu6qabo9kfp1esar8usbg.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%2Fu6qabo9kfp1esar8usbg.png" alt="Image description" width="800" height="539"&gt;&lt;/a&gt;&lt;br&gt;
Source: &lt;a href="https://www.frontendmag.com/tutorials/usereducer-vs-usestate/"&gt;https://www.frontendmag.com/tutorials/usereducer-vs-usestate/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Cách bình thường, với useState
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function useUndo(initialPresent) {
  const [state, setState] = React.useState({
    past: [],
    present: initialPresent,
    future: [],
  })

  const canUndo = state.past.length !== 0
  const canRedo = state.future.length !== 0

  const undo = React.useCallback(() =&amp;gt; {
    setState(currentState =&amp;gt; {
      const {past, present, future} = currentState

      if (past.length === 0) return currentState

      const previous = past[past.length - 1]
      const newPast = past.slice(0, past.length - 1)

      return {
        past: newPast,
        present: previous,
        future: [present, ...future],
      }
    })
  }, [])

  const redo = React.useCallback(() =&amp;gt; {
    setState(currentState =&amp;gt; {
      const {past, present, future} = currentState

      if (future.length === 0) return currentState

      const next = future[0]
      const newFuture = future.slice(1)

      return {
        past: [...past, present],
        present: next,
        future: newFuture,
      }
    })
  }, [])

  const set = React.useCallback(newPresent =&amp;gt; {
    setState(currentState =&amp;gt; {
      const {present, past} = currentState
      if (newPresent === present) return currentState

      return {
        past: [...past, present],
        present: newPresent,
        future: [],
      }
    })
  }, [])

  const reset = React.useCallback(newPresent =&amp;gt; {
    setState(() =&amp;gt; ({
      past: [],
      present: newPresent,
      future: [],
    }))
  }, [])

  return [state, {set, reset, undo, redo, canUndo, canRedo}]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Refactor với useReducer
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const UNDO = 'UNDO'
const REDO = 'REDO'
const SET = 'SET'
const RESET = 'RESET'

function undoReducer(state, action) {
  const {past, present, future} = state
  const {type, newPresent} = action

  switch (type) {
    case UNDO: {
      if (past.length === 0) return state

      const previous = past[past.length - 1]
      const newPast = past.slice(0, past.length - 1)

      return {
        past: newPast,
        present: previous,
        future: [present, ...future],
      }
    }

    case REDO: {
      if (future.length === 0) return state

      const next = future[0]
      const newFuture = future.slice(1)

      return {
        past: [...past, present],
        present: next,
        future: newFuture,
      }
    }

    case SET: {
      if (newPresent === present) return state

      return {
        past: [...past, present],
        present: newPresent,
        future: [],
      }
    }

    case RESET: {
      return {
        past: [],
        present: newPresent,
        future: [],
      }
    }
  }
}

function useUndo(initialPresent) {
  const [state, dispatch] = React.useReducer(undoReducer, {
    past: [],
    present: initialPresent,
    future: [],
  })

  const canUndo = state.past.length !== 0
  const canRedo = state.future.length !== 0
  const undo = React.useCallback(() =&amp;gt; dispatch({type: UNDO}), [])
  const redo = React.useCallback(() =&amp;gt; dispatch({type: REDO}), [])
  const set = React.useCallback(
    newPresent =&amp;gt; dispatch({type: SET, newPresent}),
    [],
  )
  const reset = React.useCallback(
    newPresent =&amp;gt; dispatch({type: RESET, newPresent}),
    [],
  )

  return [state, {set, reset, undo, redo, canUndo, canRedo}]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>react</category>
    </item>
    <item>
      <title>Sử dụng Builder Pattern cho function có nhiều filter params trong Java</title>
      <dc:creator>Tuan</dc:creator>
      <pubDate>Thu, 21 Dec 2023 09:32:21 +0000</pubDate>
      <link>https://forem.com/tuannguyen_talan/su-dung-builder-pattern-cho-function-co-nhieu-filter-params-trong-java-11mo</link>
      <guid>https://forem.com/tuannguyen_talan/su-dung-builder-pattern-cho-function-co-nhieu-filter-params-trong-java-11mo</guid>
      <description>&lt;p&gt;Nếu hàm chứa quá nhiều biến dùng để filter, đặc biệt dùng cho các api filter/sort của list thì việc sử dụng Builder Pattern giúp code đọc vào dễ hiểu và dễ maintain hơn.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class FilterParams {
    private String param1;
    private int param2;

    private FilterParams(Builder builder) {
        this.param1 = builder.param1;
        this.param2 = builder.param2;
    }

    // Getter methods
    // ...

    public static class Builder {
        private String param1;
        private int param2;

        public Builder param1(String param1) {
            this.param1 = param1;
            return this;
        }

        public Builder param2(int param2) {
            this.param2 = param2;
            return this;
        }

        public FilterParams build() {
            return new FilterParams(this);
        }
    }
}

public void processWithFilters(FilterParams filters) {
    // Process based on the filters
}

// Usage:
FilterParams filters = new FilterParams.Builder()
        .param1("value1")
        .param2(123)
        .build();
processWithFilters(filters);

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Đơn giản code hơn với annotation &lt;a class="mentioned-user" href="https://dev.to/builder"&gt;@builder&lt;/a&gt; và @Getter của lombok
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import lombok.Builder;
import lombok.Getter;

@Getter 
@Builder 
public class FilterParams {
   String param1;
   int param2;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>java</category>
      <category>cleancode</category>
    </item>
    <item>
      <title>Cách gì làm tôi hiểu sâu hơn về Java/Java Spring Boot</title>
      <dc:creator>Tuan</dc:creator>
      <pubDate>Tue, 19 Dec 2023 09:09:51 +0000</pubDate>
      <link>https://forem.com/tuannguyen_talan/cach-gi-lam-toi-hieu-sau-hon-ve-javajava-spring-boot-p14</link>
      <guid>https://forem.com/tuannguyen_talan/cach-gi-lam-toi-hieu-sau-hon-ve-javajava-spring-boot-p14</guid>
      <description>&lt;p&gt;Vì tôi đang code bằng IDE VSCode, nên khi bắt đầu tiếp xúc và làm với Java Spring Boot, tôi đã cài 2 thứ khiến tôi dễ hiểu, tiếp cận nhanh hơn với Java cũng như code được clean hơn khi đi từ NodeJS qua.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Java format
&lt;/h2&gt;

&lt;p&gt;Trong file settings.json, cài đặt như sau để IDE auto format code khi saved&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"java.format.settings.url": "https://raw.githubusercontent.com/google/styleguide/gh-pages/eclipse-java-google-style.xml",
  "java.format.settings.profile": "GoogleStyle",
  "[java]": {
      "editor.formatOnSave": true,
      "editor.defaultFormatter": "redhat.java",
      "editor.tabSize": 2
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Java checker (important) - SonarLint
&lt;/h2&gt;

&lt;p&gt;Install &lt;a href="https://marketplace.visualstudio.com/items?itemName=SonarSource.sonarlint-vscode"&gt;https://marketplace.visualstudio.com/items?itemName=SonarSource.sonarlint-vscode&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SonarLint có các cảnh bảo về clean code, security, design pattern,... một cách chi tiết rõ ràng. Từ đó tôi hiểu được sâu và rõ hơn về Java Spring Boot&lt;/p&gt;

&lt;p&gt;Ví dụ:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cMnlQw8U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jum9g4oel7kj9oht6r8n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cMnlQw8U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jum9g4oel7kj9oht6r8n.png" alt="Image description" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WIoo5HlI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m746ijtsow5q2kerrq1y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WIoo5HlI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m746ijtsow5q2kerrq1y.png" alt="Image description" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>learning</category>
      <category>cleancode</category>
      <category>springboot</category>
    </item>
    <item>
      <title>4 cách để nâng cao tốc độ load APIs, và áp dụng vào Java Spring Boot</title>
      <dc:creator>Tuan</dc:creator>
      <pubDate>Sat, 16 Dec 2023 13:24:04 +0000</pubDate>
      <link>https://forem.com/tuannguyen_talan/4-cach-de-nang-cao-toc-do-load-apis-va-thu-ap-dung-vao-java-spring-boot-51po</link>
      <guid>https://forem.com/tuannguyen_talan/4-cach-de-nang-cao-toc-do-load-apis-va-thu-ap-dung-vao-java-spring-boot-51po</guid>
      <description>&lt;h2&gt;
  
  
  1. Pagination
&lt;/h2&gt;

&lt;p&gt;Đối với các apis response trả về là một mảng, và số lượng dữ liệu lớn được dùng trong các table, list, option,... thì câu lệnh query &lt;strong&gt;phải&lt;/strong&gt; sử dụng phân trang, không được lấy hết tất cả.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java Spring Boot &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Với JPA và Hibernate&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;List&amp;lt;Post&amp;gt; posts = entityManager.createQuery(
    "select p " +
    "from Post p " +
    "left join fetch p.comments " +
    "order by p.createdOn", Post.class)
.setFirstResult(10)
.setMaxResults(10)
.getResultList();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Với Java Spring Boot đó chưa phải là tất cả, nếu bạn có hàng ngàn record và khi sử dụng &lt;em&gt;join fetch&lt;/em&gt; thì khi dùng cú pháp phía trên hệ thống sẽ warning như sau:&lt;br&gt;
&lt;code&gt;HHH000104: firstResult/maxResults specified with collection fetch; applying in memory!&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Và đặc biệt phải chú ý đến vấn đề &lt;em&gt;Hibernate N+1 problem&lt;/em&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;:( ngay từ đầu sao không nói vậy đi!!! Đến khi xảy ra vấn đề hiệu năng mới nói&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tại sao lại có cảnh báo về HHH000104 và nó có ảnh hưởng đến tốc độ query cũng như response, câu trả lời chắc chắn là có.&lt;br&gt;
Thực tế Hibernate sẽ biên dịch thành native sql query như sau:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT p.id AS id1_0_0_,
       c.id AS id1_1_1_,
       p.created_on AS created_2_0_0_,
       p.title AS title3_0_0_,
       c.created_on AS created_2_1_1_,
       c.post_id AS post_id4_1_1_,
       c.review AS review3_1_1_,
       c.post_id AS post_id4_1_0__,
       c.id AS id1_1_0__
FROM post p
LEFT OUTER JOIN post_comment c ON p.id=c.post_id
ORDER BY p.created_on
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Không hề có từ khoá nào liên quan đến limit, offset hoặc row_number,...&lt;br&gt;
Hibernate query lấy hết data với các điều kiện, sau đó mới tiến hành &lt;em&gt;Deserialization&lt;/em&gt; vào các entity/model/dto, dẫn tới việc query xuống database rất lâu&lt;/p&gt;

&lt;p&gt;Có 2 cách giải quyết được vấn đề này:&lt;br&gt;
&lt;strong&gt;- Cách 1:&lt;/strong&gt; dùng 2 câu query&lt;/p&gt;

&lt;p&gt;Chỉ select post.id để lấy list id thoả mãn điều kiện cần.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;List&amp;lt;Long&amp;gt; postIds = entityManager.createQuery("""
    select p.id
    from Post p
    where p.title like :titlePattern
    order by p.createdOn
    """, Long.class)
.setParameter(
    "titlePattern",
    "High-Performance Java Persistence %"
)
.setMaxResults(5)
.getResultList();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Có được list post id thì tiến hành query post có id nằm trong list đó&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;List&amp;lt;Post&amp;gt; posts = entityManager.createQuery("""
    select distinct p
    from Post p
    left join fetch p.comments
    where p.id in (:postIds)
    order by p.createdOn
    """, Post.class)
.setParameter("postIds", postIds)
.setHint(
    QueryHints.HINT_PASS_DISTINCT_THROUGH,
    false
)
.getResultList();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cách này thì nên chú ý về giới hạn mảng postIds trong câu lệnh &lt;strong&gt;in&lt;/strong&gt; nhá, vì nó có giới hạn đấy.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;- Cách 2:&lt;/em&gt; Nếu sử dụng Oralce Database có thể sử dụng &lt;a href="https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions043.htm"&gt;DENSE_RANK&lt;/a&gt;&lt;br&gt;
Cách này mình chưa áp dụng, nên các bạn muốn áp dụng và xem chi tiết thì tham khảo tại &lt;a href="https://vladmihalcea.com/fix-hibernate-hhh000104-entity-fetch-pagination-warning-message/"&gt;đây&lt;/a&gt; nhá.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ngoài N+1, pagination thì đối với Java Spring Boot Hibernate JPA, có rất nhiều vấn đề liên quan đến hiệu năng nữa như là spring.jpa.open-in-view, Hikari: Connection is not available, request timeout after 30000ms, EntityGraph,... Nếu các bạn quan tâm thì có thể comment nhé :D&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;2. Async Logging&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Việc backend tiến hành ghi logs để monitor lỗi, thông tin, debug là điều tất nhiên, tuy nhiên nếu log không được ghi bất đồng bộ thì cũng ảnh hưởng đến hiệu năng đấy, và vấn đề này thường được bỏ qua khi xem xét hiệu năng.&lt;/p&gt;

&lt;p&gt;Vì đối với 1 hệ thống lớn thì số lượng request nhiều, để logs được ghi bất đồng bộ và thay vào đó dành thời gian hay chỗ để giải quyết các logic và response trả về sẽ giảm tải độ trễ của APIs&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java Spring Boot &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nếu sử dụng logback.xml thì có thể config tương tự như sau&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;configuration&amp;gt;
  &amp;lt;property name="LOG_PATTERN"
    value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" /&amp;gt;

  &amp;lt;appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"&amp;gt;
    &amp;lt;encoder&amp;gt;
      &amp;lt;pattern&amp;gt;
        ${LOG_PATTERN}
      &amp;lt;/pattern&amp;gt;
    &amp;lt;/encoder&amp;gt;
  &amp;lt;/appender&amp;gt;

  &amp;lt;appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"&amp;gt;
    &amp;lt;file&amp;gt;
      ./logs/application.log
    &amp;lt;/file&amp;gt;
    &amp;lt;encoder&amp;gt;
      &amp;lt;pattern&amp;gt;
        ${LOG_PATTERN}
      &amp;lt;/pattern&amp;gt;
    &amp;lt;/encoder&amp;gt;

    &amp;lt;rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"&amp;gt;
      &amp;lt;fileNamePattern&amp;gt;
        ./logs/archive/application-%d{yyyy-MM-dd}-%i.log.zip
      &amp;lt;/fileNamePattern&amp;gt;
      &amp;lt;maxFileSize&amp;gt;10MB&amp;lt;/maxFileSize&amp;gt;
      &amp;lt;maxHistory&amp;gt;100&amp;lt;/maxHistory&amp;gt;
    &amp;lt;/rollingPolicy&amp;gt;
  &amp;lt;/appender&amp;gt;

  &amp;lt;appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"&amp;gt;
    &amp;lt;appender-ref ref="ROLLING_FILE" /&amp;gt;
  &amp;lt;/appender&amp;gt;

  &amp;lt;appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"&amp;gt;
    &amp;lt;appender-ref ref="CONSOLE" /&amp;gt;
  &amp;lt;/appender&amp;gt;

  &amp;lt;root level="INFO"&amp;gt;
    &amp;lt;appender-ref ref="ROLLING_FILE" /&amp;gt;
    &amp;lt;appender-ref ref="CONSOLE" /&amp;gt;
  &amp;lt;/root&amp;gt;
&amp;lt;/configuration&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Caching
&lt;/h2&gt;

&lt;p&gt;Kỹ thuật này cực kỳ cải thiện tốc độ load và có nhiều phương thức để áp dụng như Redis, hoặc nếu dùng Java Spring Boot thì framework này cũng đã hỗ trợ sẵn&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.baeldung.com/spring-cache-tutorial"&gt;https://www.baeldung.com/spring-cache-tutorial&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cơ chế cơ bản của cache là tạo và lưu trữ data vào bộ nhớ trong (in-memory) dựa vào key và có 1 thời gian hết hạn.&lt;/p&gt;

&lt;p&gt;Thông thường ở lần gọi đầu tiên sẽ không được nhanh vì cache chưa có nên sẽ query trực tiếp vào database, ở các lần tiếp theo mới nhanh được.&lt;/p&gt;

&lt;p&gt;Vì thế mình hay viết các scheduler/cron-job/cron-tab để đầu giờ sáng hằng ngày hệ thống sẽ fetch và tạo cache trước cho các api query dữ liệu lớn hay được dùng như list, chart, thống kê,...&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Payload compress
&lt;/h2&gt;

&lt;p&gt;Nôm na hiểu là sẽ tối ưu dung lượng lúc &lt;em&gt;Deserialization&lt;/em&gt; và lúc response cho client.&lt;/p&gt;

&lt;p&gt;Và sẽ có một vài cách:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;gzip response &lt;/li&gt;
&lt;li&gt;sử dụng kỹ thuật DTO cho từng APIs thay vì dùng full column trong entity hoặc model&lt;/li&gt;
&lt;li&gt;sử dụng tên ngắn cho các fields (cách này không khuyến khích, vì các fields trả về khó hiểu nghĩa)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Với Java Spring Boot, các bạn có thể tham khảo tại &lt;a href="https://www.baeldung.com/json-reduce-data-size"&gt;đây&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cảm ơn các bạn đã theo dõi và đọc bài viết.&lt;/p&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://thorben-janssen.com/pagination-jpa-hibernate/"&gt;https://thorben-janssen.com/pagination-jpa-hibernate/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/spring-cache-tutorial"&gt;https://www.baeldung.com/spring-cache-tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/json-reduce-data-size"&gt;https://www.baeldung.com/json-reduce-data-size&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>performance</category>
      <category>springboot</category>
    </item>
  </channel>
</rss>
