<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Duy Hiếu's Blog]]></title><description><![CDATA[Welcome to my blog. I'm Duy Hieu - Technical Leader at FPT Software. I created this blog to share my stories.]]></description><link>https://phamduyhieu.com</link><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Apr 2026 07:11:50 GMT</lastBuildDate><atom:link href="https://phamduyhieu.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Review Singapore sau 5 tháng]]></title><description><![CDATA[1. Sạch
Phải công nhận là Sing sạch, đi đâu cũng thấy có người đang quét dọn, tỉa cành, gom rác, cắt cỏ,… Chi phí để duy trì môi trường cảnh quan chắc cũng không hề nhỏ.
2. Giao thông công cộng
Bên này chủ yếu đi bằng tàu điện (MRT) và xe bus, chi ph...]]></description><link>https://phamduyhieu.com/review-singapore-sau-5-thang</link><guid isPermaLink="true">https://phamduyhieu.com/review-singapore-sau-5-thang</guid><category><![CDATA[singapore]]></category><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Tue, 03 Feb 2026 16:04:37 GMT</pubDate><content:encoded><![CDATA[<h1 id="heading-1-sach">1. Sạch</h1>
<p>Phải công nhận là Sing sạch, đi đâu cũng thấy có người đang quét dọn, tỉa cành, gom rác, cắt cỏ,… Chi phí để duy trì môi trường cảnh quan chắc cũng không hề nhỏ.</p>
<h1 id="heading-2-giao-thong-cong-cong">2. Giao thông công cộng</h1>
<p>Bên này chủ yếu đi bằng tàu điện (MRT) và xe bus, chi phí đi lại cũng khá rẻ, đi gần thì 1 đô, xa cỡ 2 chục cây số cũng chỉ hết tầm 2 đô. Đa số sử dụng phương tiện công cộng nên ít khi thấy tắc đường.</p>
<h1 id="heading-3-do-an">3. Đồ ăn</h1>
<p>Đồ ăn ở Sing dở òm, nhiều cay nóng, dầu mỡ. Ở đây nhiều gia đình có thói quen ra Foodcourt - các khu ăn uống bình dân mua đồ ăn chứ không nấu ở nhà.<br />Tôi thì không nhá nổi đồ Foodcourt nên toàn tự nấu buổi tối.</p>
<h1 id="heading-4-chi-phi-sinh-hoat">4. Chi phí sinh hoạt</h1>
<p>Giá nhà khá đắt đỏ trong khi giá sinh hoạt khá rẻ so với thu nhập. Tôi thuê 1 phòng common mà giá đã là 1200 SGD ~ 25 triệu VND. Tiền ăn 1 tháng tầm 500 SGD, chi tiêu lặt vặt nữa tổng là khoảng 2000 SGD 1 tháng.</p>
<h1 id="heading-5-van-hoa-lam-viec">5. Văn hoá làm việc</h1>
<p>Mọi người làm việc khá tập trung, ai lo việc người đó, ít có kiểu buôn dưa lê trong giờ làm việc. Công ty thường cũng không có các group ăn chơi như ở Việt Nam, hết giờ là đóng máy đi về, ít khi tụ tập. Chắc có lẽ vì thế mà năng suất họ cao hơn mặt bằng chung ở Đông Nam Á :D</p>
<h1 id="heading-6-thoi-tiet">6. Thời tiết</h1>
<p>Sing được thiên nhiên ưu đãi cho thời tiết cực kỳ dễ chịu, không có bão gió gì. Thời tiết chia thành hai mùa khô và mùa mưa, nhưng nhìn chung thì khá ôn hoà. Nắng cũng không gay gắt như mùa hè ở Việt Nam, mưa thì chốc nhát. Chắc nhờ vậy mà vô số cây cổ thụ còn giữ được nguyên vẹn với tán rất rộng, chứ ở Việt Nam thì một trận bão là đổ hết.</p>
<h1 id="heading-7-cong-dong-nguoi-viet">7. Cộng đồng người Việt</h1>
<p>Cộng đồng người Việt bên này khá đông, tuy không bằng đội Ấn Độ hay Mã Lai, nhưng cũng cảm thấy đỡ lạc lõng cho những ai mới sang định cư.</p>
<p>Tôi được nhiều anh chị đi trước nâng đỡ, từ việc ôn phỏng vấn như nào, deal lương, tìm nhà, đi lại, ăn ở, mua bán,… Tôi cảm thấy rất may mắn khi được các tiền bối chia sẻ, giúp đỡ những ngày chân ướt chân ráo sang đây.</p>
<h1 id="heading-8-phong-tuc-cua-nguoi-goc-hoa">8. Phong tục của người gốc Hoa</h1>
<p>Người Hoa chiếm khoảng 75% dân số Sing (theo Wiki), nên khi bước chân xuống sân bay là tôi cứ tưởng đang ở Trung Quốc.</p>
<p>Người gốc Hoa vẫn giữ phong tục đốt hương, hoá vàng ngày rằm và mùng một. Dưới sân chung cư nào cũng có một khu để hoá vàng mã.</p>
<p>Họ vẫn giữ phong tục ăn tết cổ truyền, trong đó nổi bật nhất là các hoạt động trang trí nhà cửa, chơi cây cảnh (chủ yếu thấy chơi quất) và đi thăm họ hàng trong khoảng 10 ngày đầu tiên của năm mới. Tuy nhiên, họ thường đi vào buổi tối do kỳ nghỉ tết chỉ kéo dài 2,5 ngày.</p>
<p>Khi gia đình có người qua đời, họ cũng tổ chức đám ma trong khoảng 3-4 ngày liền, mắc rạp ngay dưới sân chung cư, nhưng tuyệt đối không có kèn trống.</p>
]]></content:encoded></item><item><title><![CDATA[Domain Driven Design - Healthcare Platform Example]]></title><description><![CDATA[In the previous article, I covered the basic concepts and introduced a 5-step process for applying DDD in practice. Today, I will bring you a bigger challenge. In this article, we will work through an example by designing a healthcare platform.
I. He...]]></description><link>https://phamduyhieu.com/domain-driven-design-healthcare-platform-example</link><guid isPermaLink="true">https://phamduyhieu.com/domain-driven-design-healthcare-platform-example</guid><category><![CDATA[DDD]]></category><category><![CDATA[#Domain-Driven-Design]]></category><category><![CDATA[software development]]></category><category><![CDATA[software architecture]]></category><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Tue, 18 Mar 2025 16:08:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1742313912412/1f973d4b-48e9-4f0b-bea8-b5e09f88768f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the previous article, I covered the basic concepts and introduced a 5-step process for applying DDD in practice. Today, I will bring you a bigger challenge. In this article, we will work through an example by designing a <strong>healthcare platform</strong>.</p>
<h1 id="heading-i-healthcare-platform-requirements">I. Healthcare Platform Requirements</h1>
<h2 id="heading-1-scenario">1. Scenario</h2>
<p>General Hospital A has been providing City X‘s citizens with a wide range of healthcare services. Its routine operations rest on its Data Center on-premises with a legacy healthcare platform composed of heterogeneous monolithic, SOA apps that were designed and built up 2 decades ago. The growing population results in the high demand on the high load, high quality and multi-specialties of healthcare services.</p>
<p>With the as-is legacy healthcare platform, its day-to-day operations undergo a series of pain-points, incidents, and limitations including inflexible business functionalities, slow response time under high load (even saturation), API management, resilience, observability, maintainability, expandability, deployability… To address these shortcomings of the as-is platform, the hospital hires a multi-national IT consulting firm who advises the Hospital Leader Board to modernize their as-is healthcare platform by capitalizing on advantages and strengths of cloud computing, Microservices as a trendy architectural style, Intelligent Analytics. <strong>As a SA, you are tasked with architecting a MSA-based healthcare platform for Hospital Leader Board and development teams with requirements below.</strong></p>
<h2 id="heading-2-business-specification">2. Business Specification</h2>
<p>The healthcare platform manages information about <strong>patients</strong> (demographics, medical history, insurance data). It also manages <strong>Electronic Medical Records (EMR)</strong> including medical tests (blood, urine...), imaging studies (X-ray, CT/MRI scans, Ultrasound...). It allows patients to <strong>online schedule appointments</strong> with doctors in advance. Patients can follow the normal medical procedure by online booking doctors, or offline registering for examinations, paying service bills in advance. Receptionists receive patients' requests and arrange appointments with doctors. On appointment days, patients go into the hospital, show up at Examination Department, doctors examine patients, request medical tests, if necessary. Based on symptoms, test results, doctor will diagnose diseases, decide on treatments (surgery, medication, therapies), prescribe medicine. Patients pay bills for additional service fees, if any, deposit money in case they undergo inpatient treatments and monitoring. Patients can also claim insurance if available. The healthcare provider provides emergency, check-up services, inpatient and outpatient treatment services to the City's citizens.</p>
<h2 id="heading-3-technical-specificaiton">3. <strong>Technical Specificaiton</strong></h2>
<p>The platform integrates with External Identity Provider, External Payment Gateway, External Insurer, Internal Accounting and Logistic systems. It supports both web browsers and mobiles as clients.</p>
<h1 id="heading-ii-requirement-analysis">II. Requirement Analysis</h1>
<p>We need to design a <strong>new MSA-based healthcare platform to replace the legacy system</strong> (on-premises, monolithic + SOA):</p>
<ul>
<li><p>Capable of handling thousands of concurrent users</p>
</li>
<li><p>Capitalizing on advantages and strengths of cloud computing, microservices and cloud app best practices.</p>
</li>
<li><p>Implement data replication and data recovery strategies to prevent data loss</p>
</li>
<li><p>Utilize distributed systems principles to ensure high availability and fault tolerance</p>
</li>
<li><p>Maintain data consistency across microservices</p>
</li>
</ul>
<p>Therefore, we need to <strong>decompose the Healthcare Platform as the whole business domain into corresponding subdomains/bounded contexts.</strong></p>
<h2 id="heading-functional-requirements">Functional Requirements</h2>
<ul>
<li><p>Manages:</p>
<ul>
<li><p>Patient information (demographics, medical history, insurance data)</p>
</li>
<li><p>Electronic Medical Records (EMR) including medical tests (blood, urine...), imaging studies (X-ray, CT/MRI scans, Ultrasound...)</p>
</li>
</ul>
</li>
<li><p>Allows patients to online schedule appointments with doctors in advance</p>
</li>
<li><p>Patients can pay service bills, claim insurance</p>
</li>
<li><p>Receptionists receive patients' requests, arrange appointments with doctors</p>
</li>
<li><p>Receptionists/Doctors handle medical procedures, store medical history,... into the system</p>
</li>
<li><p>Provides emergency, check-up services, inpatient and outpatient treatment services to the City's citizens.</p>
</li>
<li><p>Integrates with External services (Identity Provider, Payment Gateway, Insurer), Internal services (Accounting, Logistic, Resource Management).</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742292067678/86404f70-3a48-4450-98a5-7058ba29f36c.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<p><em>Notes: We must clarify the scope of the new platform with customers. For instance,</em> <strong><em>Resource Management, Pharmacy Management</em></strong> <em>might not be explicitly mentioned in the requirements, but it's important to confirm whether it should be included.</em></p>
<h2 id="heading-non-functional-requirements">Non-functional Requirements</h2>
<ul>
<li><p>Capable of handling thousands of concurrent users</p>
</li>
<li><p>Data replication and data recovery</p>
</li>
<li><p>High availability with minimal latency</p>
</li>
<li><p>The system should be scalable and efficient</p>
</li>
<li><p>Data encryption for all layers, end-to-end encryption</p>
</li>
</ul>
<h1 id="heading-iii-subdomain-decomposition">III. Subdomain Decomposition</h1>
<p>I often apply the <a target="_blank" href="https://en.wikipedia.org/wiki/4%2B1_architectural_view_model"><strong>4+1 Architectural View Model</strong></a> for my architectural designs, providing comprehensive perspectives for stakeholders with 5 different views. I'll share details about this model and complete designs for our healthcare platform in another article. In this article, I'll focus only on the <strong>Logical View</strong>, including our <strong>subdomain decomposition process</strong>. Btw, I will skip Ubiquitous Language table creation since I'm the only one working on the project 😂</p>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/4%2B1_Architectural_View_Model.svg/1920px-4%2B1_Architectural_View_Model.svg.png" alt="undefined" /></p>
<h2 id="heading-1-eventstorming-workshop">1. EventStorming Workshop</h2>
<p>To clearly decompose the entire domain, we first need to review the main business process:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742311790515/5c07adce-5780-4737-8c83-cf118d86c93a.png" alt class="image--center mx-auto" /></p>
<p>I simulated an <a target="_blank" href="https://phamduyhieu.com/domain-driven-design#heading-32-event-storming-workshop"><strong>EventStorming</strong></a> workshop and identified all key events and created a following <strong>Big Picture</strong>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742312058068/5d701307-b33e-48bd-9b3c-133c64e02db0.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-2-identify-bounded-contexts">2. Identify Bounded Contexts</h2>
<p>From the above Big Picture, I can identify natural boundaries between subdomains.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742312121209/bb15a9be-caa9-4403-9721-749051690278.png" alt class="image--center mx-auto" /></p>
<p>Finally, I categorized subdomains into the following three groups:</p>
<h3 id="heading-core-subdomains">Core Subdomains</h3>
<ul>
<li><p><strong>Treatment Service</strong>: manages medical process during patient’s examination, inpatient &amp; outpatient treatments</p>
</li>
<li><p><strong>EMR (Electronic Medical Records)</strong>: manages Electronic Medical Records (EMR) including medical tests (blood, urine...), imaging studies (X-ray, CT/MRI scans, Ultrasound...)</p>
</li>
<li><p><strong>Patient Management</strong>: manages patient information, medical check history,…</p>
</li>
<li><p><strong>Emergency Services</strong>: emergency and urgent care services</p>
</li>
<li><p><strong>Check-up Services</strong>: handle check-up processes, check-up services for personal/enterprises</p>
</li>
</ul>
<h3 id="heading-supporting-subdomains">Supporting Subdomains</h3>
<ul>
<li><p><strong>Reception Service</strong>: manages patient reception, registration, guidance</p>
</li>
<li><p><strong>Appointment Scheduling</strong>: manages appointments with doctors (online and offline registration)</p>
</li>
<li><p><strong>Billing &amp; Payment</strong>: handles payments and bills/invoices for medical services</p>
</li>
<li><p><strong>Insurance Management</strong>: handles patients claims, manages insurance information</p>
</li>
</ul>
<h3 id="heading-generic-subdomains">Generic Subdomains</h3>
<ul>
<li><p><strong>Account management</strong>: handle the authentication/authorization with external Identity Provider, manage accounts, roles,…</p>
</li>
<li><p><strong>Notification</strong>: handles notification services (SMS, email, mobile notifications)</p>
</li>
<li><p><strong>Reporting/Analytics</strong>: manages/generates reports and dashboards for monitoring and data-driven decisions.</p>
</li>
</ul>
<h2 id="heading-3-identify-context-map"><strong>3. Identify Context Map</strong></h2>
<p>As I mentioned in the <a target="_blank" href="https://phamduyhieu.com/domain-driven-design#heading-4-identify-context-map">previous post</a>, I only use upstream/downstream relationship for Context Map to keep it simple and more readable. Integration patterns like Anti-Corruption Layer (ACL), Open Host Service (OHS),… with more details might be defined in the architecture design.</p>
<p>As this is our example, I didn’t have any workshops with business team (very important) but relied on my knowledge of healthcare systems and my experience with the <a target="_blank" href="https://play.google.com/store/apps/details?id=com.viettel.yttm.yhn.patient.release&amp;hl=en">My HMUH</a> mobile app.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742349885079/fe295662-cccc-4350-b475-391bace9583b.png" alt class="image--center mx-auto" /></p>
<p>In complex domains, it can be challenging to capture every relationship between subdomains on a single Context Map. Therefore, it's a good idea to split it into multiple maps.</p>
<p>Importantly, building Context Map will reveal any conflicts or redundancies in the business flow, helping to refine the design before proceeding to detailed development.</p>
<h1 id="heading-iv-conclusion">IV. Conclusion</h1>
<p>Phew… We've went through an interesting example of applying DDD to a healthcare platform design, exploring how to break down complex medical processes into subdomains and identify Context Map between them. It took me a lot of time to complete the DDD series.</p>
<p>Once again, I hope this helps everyone get a good start with DDD and be ready to handle larger projects. If you find it useful, feel free to share.</p>
<h1 id="heading-references">References</h1>
<ul>
<li>Mr Dung Ho - Presales Consultants, Solution Architect - FPT Software</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Domain Driven Design Introduction]]></title><description><![CDATA[I. Why DDD matters? A Bigger Picture
Over the years, as business needs have grown increasingly complex, our application systems have evolved - from monoliths to SOA, and now to microservices. This evolution demands a rational approach to component de...]]></description><link>https://phamduyhieu.com/domain-driven-design</link><guid isPermaLink="true">https://phamduyhieu.com/domain-driven-design</guid><category><![CDATA[DDD]]></category><category><![CDATA[#Domain-Driven-Design]]></category><category><![CDATA[software development]]></category><category><![CDATA[Architecture Design]]></category><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Thu, 06 Mar 2025 02:09:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741226840967/14360736-4716-4026-ba35-ab67c8131625.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-i-why-ddd-matters-a-bigger-picture">I. Why DDD matters? A Bigger Picture</h1>
<p>Over the years, as business needs have grown increasingly complex, our application systems have evolved - from <strong>monoliths</strong> to <strong>SOA</strong>, and now to <strong>microservices</strong>. This evolution demands a rational approach to component decomposition and integration.</p>
<p>Many companies, including the one where I previously worked, have experienced systems ballooning over time due to improper decomposition, leading to tightly coupled data and components. This often leads to problems such as <strong>domain leaks, inconsistent data, overly large codebases, and frequent system failures.</strong></p>
<p><img src="https://miro.medium.com/v2/resize:fit:1500/1*xu1Ge_Cew0DHdSU6ETcpLQ.png" alt /></p>
<p>Source: <a target="_blank" href="https://medium.com/startlovingyourself">https://medium.com/startlovingyourself</a></p>
<p>Domain-Driven Design (DDD) emerges as a systematic approach for large-scale projects with complex domains. By promoting <strong>clear boundaries</strong> between subdomains and a <strong>shared language</strong> between business and technical teams, DDD helps to avoid the pitfalls of past systems. It ensures every component is self-contained, with clearly defined responsibilities that accurately represent the specific business processes they support.</p>
<h1 id="heading-ii-what-is-ddd">II. What is DDD?</h1>
<p>Domain Driven Design (DDD) is a development philosophy defined by <strong>Eric Evans</strong> in his seminal work Domain‐Driven Design: <em>Tackling Complexity in the Heart of Software (Addison‐Wesley Professional, 2003).</em></p>
<p>DDD is an approach to software development that enables teams to effectively manage the construction and maintenance of software for <strong>complex problem domains</strong>. The main idea is splitting out the whole business domain into <strong>subdomains</strong> and microservices correspond to these subdomains.</p>
<p>For example, in designing a logistics system, you might divide the domain into subdomains such as <strong>Order, Warehouse management</strong>, <strong>Shipment</strong>, <strong>Routing, Address,…</strong></p>
<p>Importantly, DDD can be applied to both monolithic and microservices architectures.</p>
<h1 id="heading-iii-step-by-step-ddd-process">III. Step-by-Step DDD Process</h1>
<p>DDD is very difficult to start, especially for newcomers. The DDD books are quite academic and verbose, which can be overwhelming. Therefore, I have summarized it into a 5-step process to help those new to DDD practice it as easily as possible. This guide takes you from understanding the requirements all the way to being ready for coding.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742226412773/f64be5f9-edf5-4007-bd33-b125931d5fd5.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-1-identify-problem-space-and-business-domain">1. Identify problem space and business domain</h2>
<h3 id="heading-11-do-assessment"><strong>1.1. Do assessment</strong></h3>
<p>Start by asking</p>
<ul>
<li><p>What <strong>business problem</strong> am I trying to solve?</p>
</li>
<li><p>Who are the <strong>primary users</strong> of the system?</p>
</li>
<li><p>Is this project a new system or a legacy migration?</p>
</li>
<li><p>What parts of the current system should be preserved, and what needs to be rebuilt?</p>
</li>
<li><p>Which parties need to be integrated?</p>
</li>
<li><p>What <strong>pain points</strong> exist with the current system?</p>
</li>
<li><p>What is the project’s <strong>goals</strong>, <strong>timeline</strong> and <strong>budget</strong>?</p>
</li>
<li><p>…</p>
</li>
</ul>
<p>This is a very important step. A wrong scope or a misunderstanding of resource constraints can lead to many consequences - redesign, rework, missed deadlines - and can also diminish the organization's credibility with its customers (especially in outsourcing).</p>
<p>Let's clarify the <strong>goal</strong>, <strong>timeline</strong>, and <strong>budget</strong> very carefully with the customers or your boss, because you will need to <strong>adjust the design to fit these constraints</strong>.</p>
<h3 id="heading-12-talk-to-the-domain-expertsba"><strong>1.2. Talk to the domain experts/BA</strong></h3>
<p>We must involve people who know the business well - Product Owners, BA, managers - to get real insights and confirmation. Remember: <strong>Never Assume!</strong></p>
<h2 id="heading-2-build-a-ubiquitous-language">2. Build a Ubiquitous Language</h2>
<p>Ubiquitous Language is a <strong>shared vocabulary</strong> between domain experts and developers. It ensures every term used in the code, documentation, and conversations accurately reflects business concepts.</p>
<p><strong>Example (Online Store System):</strong></p>
<p>Terms like Product, SKU, Category, Cart, Order, Checkout, Support Ticket,… should have precise definitions, ensuring clear communication between domain experts and developers.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Term</strong></td><td><strong>Definition</strong></td><td><strong>Notes/Examples</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Product</td><td>An item or service offered for sale in the system, with detailed attributes such as name, description, price, and images.</td><td>E.g., a smartphone, a computer</td></tr>
<tr>
<td>SKU</td><td>Stock Keeping Unit – a unique identifier for a specific product variant used for inventory tracking and sales management</td><td>Each color/size variant may have a different SKU</td></tr>
<tr>
<td>Category</td><td>A classification that groups similar products together based on shared characteristics or type, facilitating browsing and organization.</td><td>E.g., Electronics, Clothing, Home Appliances</td></tr>
<tr>
<td>…</td><td>…</td><td>…</td></tr>
</tbody>
</table>
</div><p><strong>Best Practices for Shaping the Language</strong></p>
<ul>
<li><p>At the beginning of a project, we should create a dictionary of domain terms.</p>
</li>
<li><p>Ensure that you use <strong>one word</strong> for a specific concept. Don’t let the domain expert or developers have two words for something.</p>
</li>
<li><p>If you are using a term in code that the domain expert doesn’t say, you need to check it with them.</p>
</li>
<li><p>The business may use some terms proving to be too generic. The development team and domain experts need to create new terms and explicitly define the meaning of existing terms to implement the model in code.</p>
</li>
</ul>
<h2 id="heading-3-subdomain-decomposition">3. Subdomain Decomposition</h2>
<p>There are two common decomposition methods: by business capabilities and by Event Storming workshop.</p>
<h3 id="heading-31-business-capability-decomposition">3.1. Business Capability Decomposition</h3>
<p>A business capability is a service (without the aid of technologies) that generates business values to a(n) business/company/organization as well as end users.</p>
<p><em>For example, the business capabilities of an online store include:</em></p>
<ul>
<li><p><strong>Product catalog management</strong></p>
</li>
<li><p><strong>Inventory management</strong></p>
</li>
<li><p><strong>Order management</strong></p>
</li>
<li><p><strong>Delivery management</strong></p>
</li>
<li><p><strong>Customer Service</strong></p>
</li>
</ul>
<p>To identify business capabilities, we should focus on the <strong>organization’s purpose, structure, and processes</strong>. Different groups/departments within an organization might correspond to business capabilities or business capability groups.</p>
<p>This method is especially useful for large companies with clear, established organizational structures.</p>
<h3 id="heading-32-event-storming-workshop">3.2. Event Storming Workshop</h3>
<p>This approach begins by <strong>running an</strong> <a target="_blank" href="https://www.eventstorming.com"><strong>Event Storming</strong></a> <strong>workshop</strong> to map out all the key events, commands, and processes from start to finish. You can watch this <a target="_blank" href="https://www.youtube.com/watch?v=QwOrbYTaDOY">video guide</a> to learn more about <strong>Event Storming</strong> in detail. In short, there are three workshop types in EventStorming:</p>
<ul>
<li><p><strong>Big Picture</strong>: visualizes the entire business landscape by identifying <strong>key events, actors</strong> and <strong>interactions</strong> to establish a shared, high-level understanding</p>
</li>
<li><p><strong>Process Modeling</strong>: dive into specific business flows that are separated from <strong>Big Picture</strong></p>
</li>
<li><p><strong>Software Design</strong>: transform events from <strong>Process Modeling</strong> into concrete software designs (Aggregate, Entity, Value Object,…)</p>
</li>
</ul>
<p>There are also a few main concepts that you need to remember:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742201452806/f4fa5164-6d3d-4f30-b121-0eb98ec08d55.png" alt class="image--center mx-auto" /></p>
<p>To decompose subdomains, we only need to create a <strong>Big Picture</strong>. Below is a sample Big Picture for our online store system, where I identified all domain events arranged sequentially from start to finish.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742266067927/966c85dd-8722-49b0-85f0-db99dbc8c459.png" alt class="image--center mx-auto" /></p>
<p>By visualizing the business flow end to end, you not only gain a deeper understanding of how the domain operates, but you also <strong>reveal natural boundaries</strong> between subdomains. Once these boundaries become clear, you can decompose the system into <strong>distinct subdomains</strong> that reflect different parts of the business process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742206456788/2cc29ad4-2f50-4fd3-b5b1-578e2fa658ab.png" alt class="image--center mx-auto" /></p>
<p>After identifying these subdomains through Event Storming, you can classify them into <strong>three main types</strong>:</p>
<ul>
<li><p><strong>Core</strong> - key differentiator for the business and the most valuable part of the application.</p>
</li>
<li><p><strong>Supporting</strong> - related to what the business does but not a differentiator. These can be implemented in-house or outsourced.</p>
</li>
<li><p><strong>Generic</strong> - not specific to the business and are ideally implemented using third-party solutions.</p>
</li>
</ul>
<p><strong>For example, the subdomains of an online store include:</strong></p>
<ul>
<li><p><strong>Core:</strong> Product Catalog, Order Management, Customer Service</p>
<p>  → they offer differentiates your business in the market and becomes a key driver of customer loyalty and competitive advantage.</p>
</li>
<li><p><strong>Supporting</strong>: Inventory Management, Payment, Promotion</p>
<p>  → they are essential to operations but do not, by themselves, provide a unique competitive edge.</p>
</li>
<li><p><strong>Generic</strong>: Delivery Management, Notification,…</p>
<p>  → many businesses can rely on established third-party logistics solutions for delivery.</p>
</li>
</ul>
<p>This method is ideal for smaller organizations that don’t have rigid business structures but can be applied to any organization to any extent.</p>
<h2 id="heading-4-identify-context-map">4. Identify Context Map</h2>
<p>After identifying subdomains, we build <strong>Context Mapping</strong> - represents the relationships among bounded contexts (upstream, downstream, dependencies…).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741159484255/ed0801bc-5b43-4e7f-8adf-a3bde28f8cf8.png" alt class="image--center mx-auto" /></p>
<p>Source: <a target="_blank" href="https://contextmapper.org/docs/examples/">contextmapper.org/docs/examples</a></p>
<p>There are four common patterns:</p>
<ul>
<li><p><strong>Upstream/Downstream Relationship</strong></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741160448664/008359ee-9a89-4da6-9c73-373d512c33e5.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Anticorruption Layer</strong>: a layer for integration, only contains translation logic, not business logic. We use this layer to integrate with code we don’t own or can’t change.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741160494256/b7abd9a4-9237-4699-8a19-47ba16cb85dd.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Shared Kernel</strong>: uses a shared model for 2 bounded contexts (have a lot of crossover in terms of domain concepts and logic). 2 bounded contexts can be in the same subdomain</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741160561948/4fef5c12-1acf-42b1-ac6a-fabeb51f94b5.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Open Host Service:</strong> reduce duplication of ACL by exposing an API to be reused by many contexts.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741160680463/09fe6aaa-4709-40e7-9106-e6b7931dfe3b.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<p>However, after trying to draw context maps based on these patterns, I found them to be quite complex and hard to understand - especially as the number of bounded contexts increases. So, I simplified the approach by using just one type of upstream/downstream relationship, but divided it into two categories:</p>
<ul>
<li><p>Synchronous integration via API</p>
</li>
<li><p>Asynchronous integration via events</p>
</li>
</ul>
<p>By this way, everyone attending the workshop, especially the business team, can understand it easily.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742270224733/aab31a92-4056-41ee-afb6-840986aea10f.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-5-identify-ddd-artifacts">5. Identify DDD Artifacts</h2>
<p>Below are the key domain concepts that serve as the fundamental building blocks for our design after subdomain decomposition.</p>
<ul>
<li><p><strong>Aggregate</strong>: a group of related objects and treated as a single unit. It has an aggregate root that controls access to other objects. Only the root can be referenced from outside the aggregate</p>
</li>
<li><p><strong>Aggregate Root:</strong> a central entity - entry point for a aggregate, all other entities are accessed only via root</p>
</li>
<li><p><strong>Entity:</strong> a domain object that have a distinct identity</p>
</li>
<li><p><strong>Value Object:</strong> an object that contains data but don't have an identity</p>
</li>
<li><p><strong>Domain Event</strong>: An event that captures a significant change within the domain and notifies other components of the system</p>
</li>
<li><p><strong>Domain rules</strong>: business logic and constraints that govern the behavior of the domain</p>
</li>
<li><p><strong>Domain service:</strong> services/module encapsulate the domain logic that does not naturally fit within an entity/aggregate. Domain services use entities, value objects, or other domain services to execute domain-specific operations</p>
</li>
</ul>
<p>Additionally, you can define domain operations (<strong>Queries</strong> and <strong>Commands</strong>) and <strong>long-running transactions (Sagas)</strong> that coordinate processes spanning multiple aggregates.</p>
<p><strong>Example: Order Management Subdomain</strong></p>
<ul>
<li><p><strong>Aggregate root</strong>: Order</p>
</li>
<li><p><strong>Value Object</strong>: OrderItem, ShippingAddress, PaymentDetails,….</p>
</li>
<li><p><strong>Domain Event</strong>: OrderPlaced, OrderCancelled, OrderDelivered,…</p>
</li>
<li><p><strong>Domain Service</strong>: OrderValidationService (validate that the order details, check for inventory availability,… that does not fit within only Order Aggregate).</p>
</li>
</ul>
<h1 id="heading-iv-pros-and-cons-of-ddd">IV. Pros and Cons of DDD</h1>
<p>DDD is not a silver bullet. Below are its benefits and drawbacks to help determine when it’s the right approach:</p>
<h2 id="heading-advantages">Advantages</h2>
<ul>
<li><p>Enables teams to manage complex problem domains using a <strong>divide-and-conquer</strong> approach</p>
</li>
<li><p>Encourages close <strong>collaboration</strong> between technical team and domain experts to ensure the software reflects real-world business processes</p>
</li>
<li><p>Establishes <strong>clear domain boundaries</strong>, making it easier to update or replace system components without affecting others</p>
</li>
<li><p>Avoid <strong>domain leaks</strong> between components, especially in microservices</p>
</li>
</ul>
<h2 id="heading-disadvantages">Disadvantages</h2>
<ul>
<li><p>Can be complex for developers to fully understand and implement</p>
</li>
<li><p>Slower initial progress</p>
</li>
<li><p>Requires continuous refinement of the domain model</p>
</li>
<li><p>Offers less value for small or CRUD projects</p>
</li>
</ul>
<h2 id="heading-use-cases">Use cases</h2>
<ul>
<li><p><strong>Large enterprise systems with complex domains</strong> such as banking, insurance, healthcare, or logistics,…</p>
</li>
<li><p><strong>Microservices Architectures</strong> where each service aligns with a specific subdomain or business capability</p>
</li>
</ul>
<h1 id="heading-v-conclusion">V. Conclusion</h1>
<p>Phew… We've covered the key concepts of DDD along with best practices for implementation. There's so much I'd like to include in this article, but I'm concerned it might be overwhelming. Therefore, I've focused on introducing the basic concepts and best practices, leaving additional details for you to explore if you're interested.</p>
<p>Once again, I hope this helps everyone get a good start with DDD and be ready to handle larger projects.</p>
<h1 id="heading-vi-references">VI. References</h1>
<ul>
<li><p>Mr Dung Ho - Presales Consultants, Solution Architect - FPT Software</p>
</li>
<li><p><a target="_blank" href="https://www.amazon.com/Patterns-Principles-Practices-Domain-Driven-Design/dp/1118714709">Patterns, Principles, and Practices of Domain-Driven Design</a> - Scott Millett, Nick Tune</p>
</li>
<li><p><a target="_blank" href="https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215">Domain-Driven Design: Tackling Complexity in the Heart of Software</a> - Eric Evans</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[The Anatomy of a Unit Test]]></title><description><![CDATA[Behind every robust software system lies a suite of well-structured unit tests. But what defines a great unit test? In this article, we’ll examine its anatomy and best practices to ensure your tests are both reliable and effective.
I. A Bigger Pictur...]]></description><link>https://phamduyhieu.com/the-anatomy-of-a-unit-test</link><guid isPermaLink="true">https://phamduyhieu.com/the-anatomy-of-a-unit-test</guid><category><![CDATA[unit testing]]></category><category><![CDATA[mockito]]></category><category><![CDATA[junit]]></category><category><![CDATA[Java]]></category><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Thu, 20 Feb 2025 07:27:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1740061592892/d42dd21a-04bd-46ef-9240-ebb1aa455cbd.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Behind every robust software system lies a suite of well-structured unit tests. But what defines a great unit test? In this article, we’ll examine its anatomy and best practices to ensure your tests are both reliable and effective.</p>
<h1 id="heading-i-a-bigger-picture">I. A Bigger Picture</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706454128081/53d9042a-7055-43cd-a0fa-fbe00a6de0f1.png" alt class="image--center mx-auto" /></p>
<p>Over the past five years, CI/CD has become a fundamental practice for modern software engineers.</p>
<p>According to <a target="_blank" href="https://martinfowler.com/articles/continuousIntegration.html">Martin Fowler</a>:</p>
<p><em>Continuous Integration is a software development practice where each member of a team merges their changes into a codebase together with their colleagues changes at least daily. Each of these integrations is verified by an</em> <strong><em>automated build (including test) to detect integration errors as quickly as possible</em></strong>.</p>
<p>Yes, <strong><em>as quickly as possible</em></strong>. You could rely on manual testing, but it’s slow, prone to human error. To fully support Continuous Integration, <strong>automated testing</strong> is essential - something that runs and verifies your code every time you make a change.</p>
<p>Automated tests act as an early warning system, catching bugs before they reach production. With a solid suite of tests in place, you gain confidence that your changes won’t break existing functionality.</p>
<h1 id="heading-ii-testing-methodology">II. Testing Methodology</h1>
<p>In automated testing, we commonly categorize tests into three main types:</p>
<ul>
<li><p><strong>Unit Tests</strong> – Focus on testing individual components in isolation.</p>
</li>
<li><p><strong>Integration Tests</strong> – Verify interactions between multiple components or services.</p>
</li>
<li><p><strong>End-to-End (E2E) Tests</strong> – Simulate real user flows to ensure the entire system works as expected.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706454482942/0687968f-9b6c-4e6a-9f0b-74697e055419.png" alt class="image--center mx-auto" /></p>
<p>The <strong>test pyramid</strong> provides a clear guideline on how to distribute tests across different layers. At the base, you should write <strong>a lot</strong> of small, fast <strong>unit tests</strong>. In the middle, you have <strong>integration tests</strong>, which are fewer but validate interactions between components. At the top, you write only <strong>a few</strong> high-level <strong>end-to-end (E2E) tests</strong>, which ensure the system works as a whole.</p>
<p>Lower levels focus on isolated code behaviors, while higher levels validate component integration and overall system functionality.</p>
<p>In this article, I’ll focus on the foundation of the pyramid - <strong>unit tests</strong> and explore what makes them effective.</p>
<h1 id="heading-iii-what-is-a-unit-test">III. What is a unit test?</h1>
<h2 id="heading-definition">Definition</h2>
<p>A unit test is an automated test that:</p>
<ul>
<li><p><strong>Verifies</strong> a small piece of code (also known as a unit, often a method)</p>
</li>
<li><p><strong>Runs quickly</strong></p>
</li>
<li><p><strong>Executes in isolation</strong> from dependencies or external systems as databases, APIs,…</p>
</li>
</ul>
<h2 id="heading-structure">Structure</h2>
<p>A unit test follows a simple but effective pattern, often called the <strong>AAA pattern</strong>:</p>
<ul>
<li><p><strong>Arrange</strong> – prepare the dependencies and data of a scenario</p>
</li>
<li><p><strong>Act</strong> – Call the testing method and capture the return value (if any)</p>
</li>
<li><p><strong>Assert</strong> – Verify the outcome</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706455669342/da795d38-88d3-4846-be4a-2024c7d56a10.png" alt class="image--center mx-auto" /></p>
<p>And remember: <strong>never write a test without an assertion!</strong> Unless, of course, you just want to beautify your test report. 😆</p>
<h2 id="heading-naming">Naming</h2>
<p>Proper naming helps you understand what the test verifies. A good name encourages you to focus on the behavior of the code instead of the implementation details.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739980669990/5dcc8d7b-2348-4f0e-9ebe-922063d5e686.png" alt class="image--center mx-auto" /></p>
<p>You can also use a very common convention is: <strong>MethodUnderTest_Scenario_ExpectedBehavior</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739980762096/92d97dbb-6cd8-4bb8-a12f-4b775e2bc685.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-test-doubles">Test Doubles</h2>
<p>A test double is a term that describes fake dependencies in tests. There are five variations of test doubles: <strong>dummy</strong>, <strong>stub</strong>, <strong>spy</strong>, <strong>mock</strong>, and <strong>fake.</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739981118907/be9e7f8b-fdba-4cc8-b50a-1dcd8fee82d2.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p><strong>Mock:</strong> Emulates and verifies <strong>outgoing interactions</strong> - checking whether a method was called, how many times, and with what parameters. These interactions are calls the SUT (System under test) makes to its dependencies to change their state (e.g., sending an email, calling external services).</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740023840504/a21bca26-6b02-4a79-9704-ec21c69178f5.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Stub:</strong> Emulates <strong>incoming interactions</strong> by providing predefined responses/exceptions. These interactions involve the <strong>SUT</strong> calling its dependencies to <strong>retrieve</strong> input data (e.g., fetching data from a database or external system).</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740035693526/b56f88e9-552a-4d54-845f-4ccf7e75e831.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Spy:</strong> Partially mocks an object while keeping some real behavior intact.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740035800595/c4d1668e-c640-4556-ab75-6418a804d91a.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Dummy:</strong> A simple, hardcoded value (e.g., <code>null</code> or a placeholder string) used <strong>only</strong> to satisfy method parameters but never actually utilized.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740035627676/5a39db8e-7f12-4447-9d1e-ecdaa48b1eee.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Fake:</strong> A lightweight implementation of a dependency, such as an <strong>in-memory database</strong> or <strong>HashMap</strong>, used as a replacement for a real system (e.g., replacing an actual database)</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740034277066/d46451a5-203b-44f2-adb1-a49e22148d1b.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<h1 id="heading-iv-what-makes-a-good-test">IV. What makes a good test?</h1>
<h2 id="heading-1-protection-against-bugs">1. Protection against bugs</h2>
<p>A test that shows good protection against regression depends on:</p>
<p><strong>a. Amount of code executed during the test</strong></p>
<p>Generally, the larger the amount of code that gets executed, the higher the chance that the test will reveal a bug.</p>
<p><strong>b. Complexity and domain significance</strong></p>
<p>Code that represents complex business logic is more important than boilerplate code. Therefore, our tests should focus on core domain components.</p>
<h2 id="heading-2-fast-feedback">2. Fast feedback</h2>
<p>A good unit test provides <strong>fast feedback</strong>, allowing developers to catch issues early in the development cycle. When a test fails <strong>immediately</strong> after a bug is introduced, fixing it is quick and inexpensive.</p>
<p>The cost increases exponentially when the bug is not discovered early. A fast and reliable test suite helps maintain development speed while preventing costly bugs.</p>
<h2 id="heading-3-maintainability">3. Maintainability</h2>
<ul>
<li><p>Keep your unit tests small and readable.</p>
</li>
<li><p>A single test should not take a lot to arrange and too many assertions.</p>
</li>
<li><p>Independent of out-of-process dependencies: databases, APIs, message queues,…</p>
</li>
</ul>
<h2 id="heading-4-resistance-to-refactoring">4. Resistance to refactoring</h2>
<p>If a test breaks due to refactoring of underlying code <strong>without any change in behavior</strong>, it indicates poor test design.</p>
<h3 id="heading-example-scooter-configuration"><strong>Example: Scooter Configuration</strong></h3>
<p>Imagine you want to buy a <strong>scooter</strong> with:<br />✅ <strong>A blue handle</strong><br />✅ <strong>Illuminating wheels</strong><br />✅ <strong>A red bell</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739893091093/0cdbeda9-25bf-4098-83bf-53c0aff51222.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739893123196/93fbf2c7-a9c3-4fdb-bdb6-eb14b94e353e.png" alt class="image--center mx-auto" /></p>
<p>The constructor receives custom settings to configure the scooter, then configuration() method publishes the configuration for user to see.</p>
<p>Now, consider the following <strong>unit test</strong>:</p>
<ul>
<li><p>It initializes the <strong>Scooter</strong> class with custom settings.</p>
</li>
<li><p>It asserts that the <strong>Scooter</strong> contains:</p>
<ul>
<li><p>The <strong>first instance</strong> of the <code>Handle</code> class.</p>
</li>
<li><p>The <strong>second instance</strong> of the <code>Wheel</code> class.</p>
</li>
<li><p>The <strong>third instance</strong> of the <code>Bell</code> class.</p>
</li>
</ul>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739893369352/d3206be6-c15e-422a-9329-5dda6507f61a.png" alt class="image--center mx-auto" /></p>
<p><strong>The Problem</strong></p>
<p>However, the test is looking at the implementation details of the class. It will fail if</p>
<ul>
<li><p>We alter the order of part initialization to configure <strong>Wheel</strong> first, instead of <strong>Handle</strong></p>
</li>
<li><p>We refactor the code to say that <strong>Bell</strong> is a sub-part of <strong>Handle</strong></p>
</li>
</ul>
<p><strong>The Solution</strong></p>
<p>Instead of asserting the <strong>exact instance positions</strong>, a <strong>refactoring-resistant test</strong> should verify:<br />✅ The <strong>Scooter</strong> and <strong>Bell</strong> has a handle with correct <strong>color</strong>.<br />✅ The <strong>Wheels</strong> have the expected <strong>illumination</strong> feature.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739893433238/3c2656db-b31e-41a3-92f8-13ab3514c63f.png" alt class="image--center mx-auto" /></p>
<p>A better test focuses on <strong>observable behavior.</strong> Refactoring the underlying code like moving around the objects, or changing the composition won’t impact the test.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739893512491/c0f2d77c-0afe-416e-a163-809a381caec0.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-where-to-find-observable-behavior"><strong>Where to find observable behavior?</strong></h3>
<p>If you are working with Clean Architecture, the <strong>observable behavior</strong> should reside in <strong>Domain</strong> and <strong>Use case</strong> layers, where the core business logic is implemented.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739894752200/57832b87-e3c6-435f-b9ba-2b8c4af19a50.png" alt class="image--center mx-auto" /></p>
<p>If you are working with Controller-Service-Repository projects, the <strong>observable behavior</strong> should reside in the <strong>Service</strong> layers.</p>
<h1 id="heading-v-common-mistakes-in-unit-testing">V. Common Mistakes in Unit Testing</h1>
<h2 id="heading-1-no-assertions">1. No assertions</h2>
<p>A unit test without assertions is not really a test - it’s more like <strong>“just writing code for coverage”.</strong> A unit test should <strong>always assert</strong> that the code behaves as expected. If your test doesn’t verify the result, you’re not testing anything at all.</p>
<h2 id="heading-2-test-private-methods">2. Test private methods</h2>
<p>One of the most commonly asked questions is how to test a private method. The short answer: <strong>you shouldn’t</strong>.</p>
<p>Testing private methods violates an important principle mentioned earlier: <strong>test only observable behavior</strong>. Exposing private methods <strong>couples tests to implementation details</strong>, making them fragile and reducing their resistance to refactoring.</p>
<p>However, <strong>talk is cheap</strong>. Sometimes the codebase is just too bad 😆 to strictly follow this principle. That’s why <a target="_blank" href="https://github.com/powermock/powermock"><strong>PowerMock</strong></a> exists - it allows developers to <strong>mock private methods and more</strong>.</p>
<h2 id="heading-3-too-large-arrangement">3. Too large Arrangement</h2>
<p>A large arrangement section in a unit test can be a sign of problems. If your setup code is lengthy and repetitive, it makes tests harder to read and maintain.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740385393455/798d535b-aadb-42fb-b4f5-afd4fb548bcf.png" alt class="image--center mx-auto" /></p>
<p>When the arrangement code is large and repeated across multiple tests, consider <strong>refactoring</strong>:</p>
<ul>
<li><p>Use <strong>helper methods</strong> to set up commonly used objects or scenarios with parameters.</p>
</li>
<li><p>Use <strong>factories</strong> to create reusable setups.</p>
</li>
<li><p>Consider <strong>mocking</strong> or using a framework like <strong>Mockito</strong> to simplify the setup.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740385629722/63a254e3-6869-428c-afd3-2f113bd5d201.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-4-ut-contains-implementation-details">4. UT contains implementation details</h2>
<p>If you need to invoke more than one method in your act statements:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706457062337/8cc11efb-8df7-4f4a-bae7-40541977e379.png" alt class="image--center mx-auto" /></p>
<p>Please encapsulate implementation details in your code, don't couple them with unit tests.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706457150578/69ec1aaa-95c5-459f-a774-fda555d9cd53.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-5-multiple-act-statements-in-a-ut">5. Multiple act statements in a UT</h2>
<p>We should write <strong>one unit test per scenario</strong>, meaning each unit test should have <strong>only a single act statement</strong>.</p>
<p>Avoid writing tests with multiple <strong>Act</strong> statements, as shown below, as it makes the test unclear and harder to understand the scenario being tested.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739895231495/8e06c397-461a-4823-9fa8-b43b45604733.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-6-trivial-test">6. Trivial test</h2>
<p><strong>Attribute test</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739871326054/bcbd176d-bce0-4386-afd2-322e826f72be.png" alt class="image--center mx-auto" /></p>
<p><strong>Instance test</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739871346133/dade61c5-a146-4597-b234-dd3a41aced5f.png" alt class="image--center mx-auto" /></p>
<p>Such tests are insignificant to the system and lower resistance to refactoring.</p>
<h2 id="heading-7-conditional-test">7. Conditional test</h2>
<p>Separate conditions into different unit tests instead of using conditional statements within a single test.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739871472913/7ebf2dd5-af10-4ed5-bc96-c0091357e69b.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-8-stub-test">8. Stub test</h2>
<p>There is no value if we try asserting the stub data that we emulated in the <strong>Arrange</strong> phase.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739871647566/20b317e7-9db8-4eb8-ada4-35b3ab7b8a60.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-9-leaking-domain-knowledge">9. Leaking domain knowledge</h2>
<p>Don’t let your tests hold domain knowledge. Tests should focus on verifying behavior.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739871613087/9a95d321-7881-4955-9c5e-a78a2ac6a948.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739871627099/1c26f41f-4b0f-4ff9-a6a0-63f4c52b743a.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-vi-conclusion">VI. Conclusion</h1>
<p>Phewwww! We've just covered some basic concepts and practices. I hope they help you get started with unit testing and make your software more reliable.</p>
<p>This is an interesting topic and might spark some controversial discussions. If you have any comments, feel free to share!</p>
<h1 id="heading-reference">Reference</h1>
<ul>
<li><a target="_blank" href="https://www.amazon.com/Unit-Testing-Principles-Practices-Patterns/dp/1617296279">Unit Testing: Principles, Practices, and Patterns</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[2024 Recap]]></title><description><![CDATA[This is a nice feedback from my Singaporean Scrum Master for 2024.

According to Vietnamese beliefs, 2024 marked the final year of a challenging three-year period (Tam Tai) for those born in 1996, a time filled with uncertainties and difficulties.
Al...]]></description><link>https://phamduyhieu.com/2024-recap</link><guid isPermaLink="true">https://phamduyhieu.com/2024-recap</guid><category><![CDATA[personal development]]></category><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Tue, 21 Jan 2025 10:12:02 GMT</pubDate><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739456947228/a36c9a4f-b209-4fa0-ba7e-9097ead73b1a.png" alt class="image--center mx-auto" /></p>
<p><em>This is a nice feedback from my Singaporean Scrum Master for 2024.</em></p>
<hr />
<p>According to Vietnamese beliefs, 2024 marked the final year of a challenging three-year period (Tam Tai) for those born in 1996, a time filled with uncertainties and difficulties.</p>
<p>Although I don’t care about this, I have to admit that this year was indeed a tough one for me. I struggled with health issue for several months. Gastro reflux sounds very simple but had a hugh negative impact on my daily life. I visited the doctor so often that they started to recognize me immediately.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737453691050/6a49b07e-7999-42e2-92aa-72feae9b1148.jpeg" alt class="image--center mx-auto" /></p>
<p><em>“Some” of my medical examination reports in 2024</em></p>
<hr />
<p>It was positive thinking that helped me bounce back. I returned to the gym and kickboxing. I also say no with beer, alcohol and coffee. Since then, my physical and mental health have improved dramatically. Gastro reflux symptoms have significantly subsided, and I feel even healthier and stronger than I did before 2024 =)))</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737453730626/30e3297b-d901-4e82-98f9-5cdca2b62601.jpeg" alt class="image--center mx-auto" /></p>
<p>Fortunately, in the middle of the year, I had an opportunity to join a SA Level Up training course offered by FHN (a biggest <a target="_blank" href="https://cafef.vn/quan-tri/mo-hinh-moi-o-fpt-software-don-vi-phan-mem-chien-luoc-fsu-20120213105016248.chn">FSU</a> of Fsoft with 2400 members). I pursued the course with great passion, earned the excellent SA award of the course and also ranked among the Top 100 FHN 2024.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737453746634/1bfb5fbb-5614-461e-98c0-d8e65f93e5cf.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737453759414/9eb5b8ca-73d8-4571-b92d-2cb51e843b05.jpeg" alt class="image--center mx-auto" /></p>
<p>In addition, my daily work remains stable and I have received positive feedback from Singaporean customers.</p>
<p>Although I was not completely satisfied with this year, it was a year when I dedicated more time to myself and realized the importance of prioritizing my health - without it, I can do nothing.</p>
<p>Based on <a target="_blank" href="https://itviec.com/salary-reports/download/fbd9e3ed-f64f-431f-94c1-c10783a519fc?locale=vi"><strong>Vietnam IT Salary &amp; Recruitment Market 2024-2025</strong></a> of itviec, the IT market in 2025 is expected to be more optimistic than 2024. I am also looking forward to a significant turning point in my career path. I hope that both you and I will have more opportunities to grow and succeed in 2025.</p>
<p>Do the best, the rest will come!</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Hexagonal Architecture with Java Spring Boot Examples]]></title><description><![CDATA[If your software has been running for over 10 years on an outdated framework or database, and you're looking to upgrade to a modern solution but still want to keep the core business code, this is when the significance of a well-designed architecture ...]]></description><link>https://phamduyhieu.com/understanding-hexagonal-architecture-with-java-spring-boot-examples</link><guid isPermaLink="true">https://phamduyhieu.com/understanding-hexagonal-architecture-with-java-spring-boot-examples</guid><category><![CDATA[Hexagonal Architecture]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[Java]]></category><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Sun, 29 Sep 2024 15:55:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727625179956/b6d16c60-333d-4a60-83e1-9a8e87a35bf2.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If your software has been running for over 10 years on an outdated framework or database, and you're looking to upgrade to a modern solution but still want to keep the core business code, this is when the significance of a well-designed architecture becomes clear.</p>
<h2 id="heading-introduction">Introduction</h2>
<h3 id="heading-definition-of-hexagonal-architecture">Definition of Hexagonal Architecture</h3>
<p>An architectural pattern which creating loosely coupled application components that can be easily connected to their software environment by means of <strong>ports</strong> and <strong>adapters</strong>. This makes components exchangeable at any level.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727599384098/8e5e8188-60d1-4178-a0ba-7faf4e72493d.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-hexagonal-vs-clean-architecture">Hexagonal vs Clean Architecture</h3>
<p>Hexagonal or Clean architecture have the same objective, which is the <strong>separation of concerns.</strong></p>
<ul>
<li><p>Divide the software into layers</p>
</li>
<li><p>Independent of frameworks, UI, database, external services</p>
</li>
<li><p>Testable without UI, database, web server, or any other external services</p>
</li>
</ul>
<p>You can see the similarity between them.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1639930479557/EuvqfP4Vf.png?auto=compress,format&amp;format=webp" alt="image.png" class="image--center mx-auto" /></p>
<h2 id="heading-core-concepts-of-hexagonal-architecture">Core Concepts of Hexagonal Architecture</h2>
<h3 id="heading-ports">Ports</h3>
<p>Port is an interface layer that define how core domain layer interact with external components (frameworks, external services, databases,…).</p>
<ul>
<li><p><strong>Inbound ports</strong>: handle input to the core, such as user commands or requests from clients or other systems.</p>
</li>
<li><p><strong>Outbound ports</strong>: define how the core can communicate with external systems like databases or APIs.</p>
</li>
</ul>
<h3 id="heading-adapters">Adapters</h3>
<p>Adapters are the implementations of ports.</p>
<ul>
<li><p><strong>Inbound Adapters:</strong> These include things like REST controllers, CLI interfaces, or event-driven consumers that handle user input or external events.</p>
</li>
<li><p><strong>Outbound Adapters:</strong> These are responsible for communicating with external systems, such as databases, third-party services, or message brokers.</p>
</li>
</ul>
<h3 id="heading-domain-model">Domain Model</h3>
<p>This is the core domain layer where holds domain entities and business logic. It’s isolated from frameworks and external components and is the most stable part of the software.</p>
<h3 id="heading-application-services">Application Services</h3>
<p>An application service acts as a facade through which clients interact with the domain model. This is where ports are defined.</p>
<p>It control database transactions, orchestrates business operations but should not make any business decisions (should be in domain layer).</p>
<h2 id="heading-setting-up-a-java-spring-boot-project">Setting Up a Java Spring Boot Project</h2>
<h3 id="heading-prerequisites-and-tools-needed">Prerequisites and Tools Needed</h3>
<ul>
<li><p>Java 17</p>
</li>
<li><p>Spring Boot 3</p>
</li>
<li><p>Intelij or any Java IDE</p>
</li>
</ul>
<h3 id="heading-initializing-the-project">Initializing the Project</h3>
<p>We start with <a target="_blank" href="https://start.spring.io/">https://start.spring.io/</a> to create a new Spring Boot framework. I chose Springweb and Lombok dependencies only for the demo.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727601955834/24104bc2-6c34-42a4-92d2-28676452ebc7.png" alt class="image--center mx-auto" /></p>
<p>You can check the project structure on the website before downloading it to your local.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727618342279/16e65b1c-176e-4cb7-a62e-1b315ea46f0a.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-implementing-hexagonal-architecture-with-java-spring-boot">Implementing Hexagonal Architecture with Java Spring Boot</h2>
<p>I will implement a booking service where we can create a booking as a sample.</p>
<p>To implement 3 layers of the architecture, I created 3 Java modules:</p>
<ul>
<li><p><strong>Domain</strong>: store domain entities and business logic</p>
</li>
<li><p><strong>Application</strong>: store inbound and outbound <strong>ports</strong></p>
</li>
<li><p><strong>Tech Framework</strong>: includes frameworks and <strong>adapters</strong> for database, controllers, external services,…</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727605916348/4218889f-d762-4684-b71a-f257cb35d9a4.png" alt class="image--center mx-auto" /></p>
<p>In which, <strong>Application</strong> module depends on <strong>Domain</strong> module:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727607019209/aed1d736-4dbb-4db4-b538-1658e2b42b22.png" alt class="image--center mx-auto" /></p>
<p>and <strong>Tech Framework</strong> module depends on both <strong>Application</strong> and <strong>Domain:</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727607105304/6ee7eacc-456e-4fca-8159-e6933db5f404.png" alt class="image--center mx-auto" /></p>
<p>As you can see, the domain has no dependency on frameworks or external components.</p>
<h3 id="heading-developing-the-domain-layer">Developing the Domain Layer</h3>
<p>Firstly, I have a BookingDomainEntity (just a sample, ignore the attributes pls :D)</p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> java.time.LocalDateTime;
<span class="hljs-keyword">import</span> lombok.*;

<span class="hljs-meta">@Getter</span>
<span class="hljs-meta">@Setter</span>
<span class="hljs-meta">@Builder</span>
<span class="hljs-meta">@AllArgsConstructor</span>
<span class="hljs-meta">@ToString</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookingDomainEntity</span> </span>{
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">long</span> id;
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">long</span> userId;
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">long</span> totalAmount;
  <span class="hljs-keyword">private</span> String pickUpAddress;
  <span class="hljs-keyword">private</span> String dropOffAddress;
  <span class="hljs-keyword">private</span> LocalDateTime createdOn;
}
</code></pre>
<p>Secondly, I have commands for business logic. To keep it simple, I don’t use command for booking creation.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727619102148/6f7f6f6d-af12-4dfc-afa6-106603247544.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-developing-the-application-layer">Developing the Application Layer</h3>
<p>As I showed you, we have inbound and outbound ports in this layer.</p>
<p>To creat a booking, I have a <strong>BookingCommandInboundPort</strong> so that it can be called by controllers from Tech Framework layer.</p>
<pre><code class="lang-java"><span class="hljs-meta">@Slf4j</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookingCommandInboundPort</span> </span>{

  <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> BookingRepositoryOutboundPort bookingRepositoryOutboundPort;

  <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">BookingCommandInboundPort</span><span class="hljs-params">(BookingRepositoryOutboundPort bookingRepositoryOutboundPort)</span> </span>{
    <span class="hljs-keyword">this</span>.bookingRepositoryOutboundPort = bookingRepositoryOutboundPort;
  }

  <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">save</span><span class="hljs-params">(BookingDomainEntity entity)</span> </span>{
    log.info(<span class="hljs-string">"Saving BookingDomainEntity"</span>);
    bookingRepositoryOutboundPort.save(entity);
  }
}
</code></pre>
<p>And a <strong>BookingRepositoryOutboundPort</strong> for saving a new booking to database:</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">BookingRepositoryOutboundPort</span> </span>{

  <span class="hljs-function">List&lt;BookingDomainEntity&gt; <span class="hljs-title">findAll</span><span class="hljs-params">()</span></span>;

  <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">save</span><span class="hljs-params">(BookingDomainEntity entity)</span></span>;
}
</code></pre>
<p>Then the application service should look like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727621022814/14a7587a-f8d0-43a6-9c80-614e61eb366c.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-designing-the-tech-framework-layer">Designing the Tech Framework Layer</h3>
<p>Finally, we implement the outsidemost layer. The dependencies that I chose previously is for this layer. I also added <strong>mapstruct</strong> library for object mapping.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727621233180/96754493-24fd-4f5e-88db-d784106cf006.png" alt class="image--center mx-auto" /></p>
<p>We also have inbound and outbound structure similar to the application layer.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727622273570/cfbb4849-4012-45ef-ae59-e80bd074152f.png" alt class="image--center mx-auto" /></p>
<p>Firstly, I have <strong>BookingEntity</strong> and <strong>BookingRepository</strong> for persistence. To keep it simple, I don’t use database and only create a dummy entity and repository:</p>
<pre><code class="lang-java"><span class="hljs-comment">// should have @Entity in real project</span>
<span class="hljs-meta">@Data</span>
<span class="hljs-meta">@Builder</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookingEntity</span> </span>{
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">long</span> id;
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">long</span> userId;
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">long</span> totalAmount;
  <span class="hljs-keyword">private</span> String pickUpAddress;
  <span class="hljs-keyword">private</span> String dropOffAddress;
  <span class="hljs-keyword">private</span> LocalDateTime createdOn;
}

<span class="hljs-meta">@Repository</span> <span class="hljs-comment">// Dummy repository =&gt; should be an interface and extend JpaRepository</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookingRepository</span> </span>{

  <span class="hljs-function">List&lt;BookingEntity&gt; <span class="hljs-title">findAll</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> List.of(BookingEntity.builder().build());
  }

  <span class="hljs-function">BookingEntity <span class="hljs-title">save</span><span class="hljs-params">(BookingEntity entity)</span> </span>{
    <span class="hljs-comment">// dummy save method</span>
    <span class="hljs-keyword">return</span> entity;
  }
}
</code></pre>
<p>Secondly, I have a <strong>BookingRepositoryAdapter</strong> that implement <strong>BookingRepositoryOutboundPort</strong> (from application layer):</p>
<pre><code class="lang-java"><span class="hljs-meta">@Component</span>
<span class="hljs-meta">@RequiredArgsConstructor</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookingRepositoryAdapter</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">BookingRepositoryOutboundPort</span> </span>{

  <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> BookingRepository bookingRepository;
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> BookingMapper mapper;

  <span class="hljs-meta">@Override</span>
  <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;BookingDomainEntity&gt; <span class="hljs-title">findAll</span><span class="hljs-params">()</span> </span>{
    List&lt;BookingEntity&gt; entities = bookingRepository.findAll();
    <span class="hljs-keyword">return</span> mapper.toBookingDomainEntity(entities);
  }

  <span class="hljs-meta">@Override</span>
  <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">save</span><span class="hljs-params">(BookingDomainEntity entity)</span> </span>{
    <span class="hljs-comment">// Transform Aggregate Root 's states into JPA Entity 's states before saving them into database</span>
    bookingRepository.save(mapper.toBookingJPAEntity(entity));
  }
}
</code></pre>
<p>and a <strong>BookingMapper</strong> for object mapping. I strongly recommend you try <strong>Mapstruct</strong> to eliminate these mapping boilerplate code.</p>
<pre><code class="lang-java"><span class="hljs-meta">@Mapper(componentModel = "spring")</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">BookingMapper</span> </span>{

  <span class="hljs-meta">@Mapping(target = "createdOn", ignore = true)</span>
  <span class="hljs-function">BookingDomainEntity <span class="hljs-title">toBookingDomainEntity</span><span class="hljs-params">(BookingRequest request)</span></span>;

  <span class="hljs-function">BookingEntity <span class="hljs-title">toBookingJPAEntity</span><span class="hljs-params">(BookingDomainEntity entity)</span></span>;

  <span class="hljs-function">List&lt;BookingDomainEntity&gt; <span class="hljs-title">toBookingDomainEntity</span><span class="hljs-params">(List&lt;BookingEntity&gt; entities)</span></span>;
}
</code></pre>
<p>Ok finally, we need a <strong>BookingController</strong> to handle client requests:</p>
<pre><code class="lang-java"><span class="hljs-meta">@RestController</span>
<span class="hljs-meta">@RequestMapping("/api/v1/bookings")</span>
<span class="hljs-meta">@RequiredArgsConstructor</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookingController</span> </span>{

  <span class="hljs-comment">// Inbound port in application layer</span>
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> BookingCommandInboundPort bookingCommandInboundPort;

  <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> BookingMapper mapper;

  <span class="hljs-meta">@PostMapping(
      consumes = {MediaType.APPLICATION_JSON_VALUE},
      produces = {MediaType.APPLICATION_JSON_VALUE})</span>
  <span class="hljs-function"><span class="hljs-keyword">public</span> ResponseEntity&lt;BookingResponse&gt; <span class="hljs-title">createBooking</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> BookingRequest request)</span> </span>{
    bookingCommandInboundPort.save(mapper.toBookingDomainEntity(request));
    <span class="hljs-keyword">return</span> ResponseEntity.ok().build();
  }
}
</code></pre>
<p>If you are feeling lost in this architecture, you are not alone :D. The flow is quite complex and can be confusing. Don't worry, I’ve sketched out a request flow so you can better visualize the entire process we just discussed:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727625510653/5828533e-16d7-4356-ad79-5b75802de331.png" alt class="image--center mx-auto" /></p>
<p>From this perspective, it's clear that if I want to replace my Spring Boot with <a target="_blank" href="https://quarkus.io/"><strong>Quarkus</strong></a> in the future, I can retain the application and domain modules since they are not framework-dependent. This will save a lot of effort, trust me! 😊</p>
<p>You can check the full code <a target="_blank" href="https://github.com/hieubz/ddd-hexagonal-template">here</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>We've just covered the definition and a hands-on example of Hexagonal Architecture. You might not fully understand it after reading, but I recommend trying out the sample first. Then, when you come back, I believe things will be clearer for you.</p>
<p>Next time, I will implement a DDD sample in this repo and we will discuss about why we should apply Hexagonal along with DDD for our project.</p>
<p>See yaa!!!</p>
<h1 id="heading-references">References</h1>
<ul>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Hexagonal_architecture_\(software\)">https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)</a></p>
</li>
<li><p><a target="_blank" href="https://vaadin.com/blog/ddd-part-3-domain-driven-design-and-the-hexagonal-architecture">https://vaadin.com/blog/ddd-part-3-domain-driven-design-and-the-hexagonal-architecture</a></p>
</li>
<li><p><a target="_blank" href="https://www.happycoders.eu/software-craftsmanship/hexagonal-architecture/">https://www.happycoders.eu/software-craftsmanship/hexagonal-architecture/</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Database Indexing - Strategies for good indexes and high performance]]></title><description><![CDATA[In the last post, we walked through the basic concept, data structures, and supported query types of database indexes. Today, I will continue to share strategies for good indexes and high query performance.
Please bear in mind that you must practice ...]]></description><link>https://phamduyhieu.com/database-indexing-strategies-for-good-indexes-and-high-performance</link><guid isPermaLink="true">https://phamduyhieu.com/database-indexing-strategies-for-good-indexes-and-high-performance</guid><category><![CDATA[HighPerformance]]></category><category><![CDATA[MySQL]]></category><category><![CDATA[indexing]]></category><category><![CDATA[Databases]]></category><category><![CDATA[Oracle]]></category><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Sat, 06 Jan 2024 14:02:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1704549481593/bd4e5734-8315-4c17-839d-36d217b7cbcf.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In <a target="_blank" href="https://hieupd.hashnode.dev/database-indexing-data-structures-supported-queries">the last post</a>, we walked through the basic concept, data structures, and supported query types of database indexes. Today, I will continue to share strategies for good indexes and high query performance.</p>
<p>Please bear in mind that you must practice these strategies to master them. Let's create your database and try with sample data such as <a target="_blank" href="https://dev.mysql.com/doc/sakila/en/">Sakila</a>,...</p>
<h1 id="heading-i-choose-the-right-column">I. Choose The Right Column</h1>
<p>Firstly, please list all queries for that table before deciding which indexes to create.</p>
<p>Secondly, don't create the index for columns with <strong>less distinct values</strong> (low cardinality).</p>
<p><em>E.g. status, action, is_active,...</em></p>
<p>You can check the cardinality figures by <strong><em>SHOW INDEX FROM + your tables</em></strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704293721988/05c31714-0897-4775-a7da-2b8040d31158.jpeg" alt class="image--center mx-auto" /></p>
<p>However, <strong><em>if the distribution of your ‘status’ column is unbalanced =&gt; Index still works if you only search by a value with lower distribution.</em></strong></p>
<h1 id="heading-ii-create-prefix-index">II. Create Prefix Index</h1>
<p>If you need to create an index for a string/varchar column, I believe that you should create a prefix index:</p>
<ul>
<li><p>Long enough to work efficiently</p>
</li>
<li><p>Short enough to reduce the index's storage</p>
</li>
</ul>
<h3 id="heading-example">Example</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704293997459/40f4c8c8-39a6-481b-84ca-c4c466103aca.jpeg" alt class="image--center mx-auto" /></p>
<p>Let's see the <strong>customer</strong> table with an index of the <strong><em>last_name</em></strong> column here and calculate the difference between the full-length index and prefix index of the first 6 chars:</p>
<ul>
<li><p><strong>Full length:</strong> key length = 45 * 4  + 1 (store length) = <strong>181 bytes</strong></p>
</li>
<li><p><strong>Prefix index:</strong> key length = 6 * 4 + 1 (store length) = <strong>25 bytes</strong></p>
</li>
</ul>
<p>Yes, the key length is 7 times larger.</p>
<h3 id="heading-how-to-find-a-good-length">How to find a good length</h3>
<p>A good way to calculate a good prefix length is by computing the full column’s selectivity and trying to make the prefix’s selectivity close to that value.</p>
<p>E.g.: I have a <strong><em>city_demo</em></strong> table and I want to create an index for the <strong><em>city</em></strong> column.</p>
<ul>
<li><strong>Step 1</strong>: we target a selectivity near 0.0312 as full-length selectivity.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704294735024/251f2bb1-d0fb-4cc3-9985-14789a13cc5b.png" alt class="image--center mx-auto" /></p>
<ul>
<li><strong>Step 2</strong>: evaluate many different lengths in one query, which is useful on very large tables:</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704294765414/65dc2e05-b240-4d4a-9a02-37123b821748.png" alt class="image--center mx-auto" /></p>
<ul>
<li><strong>Step 3</strong>: This query shows that seven characters are good enough for my prefix index.</li>
</ul>
<h1 id="heading-iii-composite-index">III. Composite Index</h1>
<p>Sometimes, you need to query by 2 columns in the same query. Please consider creating a composite index instead of an index for each column.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704295270131/d762bfc8-b181-48e5-8cd8-51d104271a4c.jpeg" alt class="image--center mx-auto" /></p>
<p>Individual indexes on lots of columns won’t help our database improve performance for most queries.</p>
<p>For example, MySQL can cope a little with such poorly indexed tables when it employs a strategy known as <strong><em>index merge</em></strong>, which permits a query to make limited use of multiple indexes from a single table to locate desired rows. It can use both indexes, scanning them simultaneously and merging the results.</p>
<p>However, the algorithm's buffering, sorting, and merging operations use lots of CPU and memory resources. So a composite index should be your first choice.</p>
<p>Another point is When you create a composite index for multiple columns, you can use that index in a query with the <strong>first column of the index</strong>.</p>
<p>E.g: The index of (<strong>username, created_at</strong>) can be used for both queries:</p>
<ul>
<li><p>Select * from users where username=‘hieupd’ and create_at &gt; ‘2022-01-01’</p>
</li>
<li><p>Select * from users where username=‘hieupd’</p>
</li>
</ul>
<p>\==&gt; No need an index for the <strong>username</strong> column only.</p>
<h1 id="heading-iv-choose-the-order-for-composite-index">IV. Choose The Order for Composite Index</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704531315044/a25db368-b62a-4fcb-9e40-96ab532da6a3.png" alt="Composite index" class="image--center mx-auto" /></p>
<h3 id="heading-how">How?</h3>
<p>Did you decide to create a composite index? OK good!</p>
<p><strong>Now how about the order of columns?</strong></p>
<p>I asked the question to <strong>at least 30 interviewees</strong>, and only one of them could answer.</p>
<p>The answer is:</p>
<p><strong><em>Choose the column with higher selectivity as the first column (in most cases)</em></strong></p>
<p>We can check the selectivity of columns by the query <strong>count distinct / count *.</strong></p>
<h3 id="heading-pay-attention">Pay Attention!!!</h3>
<ul>
<li><p><strong>When creating an index (A, B), no need to create an index only for A</strong></p>
</li>
<li><p><strong>Should put your range condition to the right of queries</strong></p>
<p>  In B-tree, if the range condition comes first in WHERE, the second column will not be used in that index</p>
<p>  E.g.: In the above image, I have a composite B-tree index of (<strong>date_of_birth</strong>, <strong>subsidiary_id</strong>)</p>
<p>  If I query by:<br />  <code>Select * from uses when date_of_birth between ’01-Jan-71’ and ’09-Jan-71’ and subsidiary_id = 27;</code></p>
<p>  \=&gt; Our database only uses the index for the first range condition, and then <strong>scans on left nodes for the second condition</strong> (<code>subsidiary_id = 27</code>) <strong>without index</strong> <strong>supports</strong>.</p>
</li>
</ul>
<h1 id="heading-v-clustered-index">V. Clustered Index</h1>
<h3 id="heading-definition">Definition</h3>
<p>Clustered indexes aren’t a separate type of index. Rather, they’re an approach to data storage.</p>
<p>When a table has a clustered index, its rows are actually stored in the index’s leaf pages.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704533850074/bd03d8fa-b703-4a21-a08b-f43d11d44bf1.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>The <strong>leaf pages contain full rows</strong>, but the node pages contain only the indexed columns.</p>
</li>
<li><p>You <strong>can have only one clustered index per table</strong> because you can’t store the rows in two places at once.</p>
</li>
<li><p>Clustered indexes normally faster than non-clustered indexes</p>
</li>
</ul>
<p>For instance, in <strong>MySQL InnoDB</strong>, the clustered index is our <strong>primary key</strong>. If you don’t define a primary key, InnoDB will try to use a unique non-nullable index instead.</p>
<h3 id="heading-pay-attention-1">Pay Attention!!!</h3>
<ul>
<li><p>In MySQL InnoDB, choosing the right PK is very important</p>
</li>
<li><p>Should not insert PK values <strong>randomly</strong> =&gt; need to reorder data, increase Disk I/O, disk fragmentation</p>
</li>
</ul>
<h1 id="heading-vi-covering-index">VI. Covering Index</h1>
<p>Indexes need to be designed for the whole query, not just the WHERE clause.</p>
<p><strong>A Covering Index is:</strong></p>
<ul>
<li><p>An index that covers all data needed for a query (only B-tree can be used to cover indexes)</p>
</li>
<li><p>An index reduces Disk I/O and latency because no need to look up into disk.</p>
</li>
</ul>
<p>So, <strong>please query only what you need</strong>, should not query redundant data (<strong>SELECT * FROM</strong>).</p>
<p>E.g.: In MySQL InnoDB, when you issue a query that is covered by an index (an index-covered query), you’ll see “<strong>Using index</strong>” in the <strong>Extra</strong> column in <strong>EXPLAIN</strong>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704535029098/eca35c92-9d5c-4af8-8d42-25bf392a282c.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-vii-redundant-and-duplicate-index">VII. Redundant and Duplicate Index</h1>
<p>You should analyze your database indexes and remove duplicated and unused indexes. It helps our database to <strong>not need to maintain redundant indexes</strong> and <strong>reduce the impact for INSERT, UPDATE, and DELETE operations</strong>.</p>
<p>E.g.: In MySQL InnoDB, The best way to identify unused indexes is with <em>performance_schema</em> and <em>sys:</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704535585600/ae90336a-85fb-4f3f-9d95-f14ead1cfb4a.png" alt class="image--center mx-auto" /></p>
<p>Notice that if there is an index on (A, B), another index on (A) would be redundant because it is a prefix of the first index.</p>
<p>In most cases, you don’t want redundant indexes, and to avoid them you should extend existing indexes rather than add new ones. However, there are times when you’ll need redundant indexes for performance reasons. Extending an existing index might make it much larger and reduce performance for some queries.</p>
<h1 id="heading-viii-partial-index">VIII. Partial Index</h1>
<p>So far we have only discussed which columns to add to an index. With partial (PostgreSQL) or filtered (SQL Server) indexes you can also specify the rows that are indexed.</p>
<p>A partial index is useful for commonly used where conditions that use constant values - like the status code in the following example:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704537526793/33716f02-7712-4ccf-bdc0-e0d7293021ec.png" alt class="image--center mx-auto" /></p>
<p>Queries like this are very common in queuing systems to fetch all unprocessed tasks.</p>
<h3 id="heading-benefits">Benefits</h3>
<ul>
<li><p>Specify the rows that are indexed</p>
</li>
<li><p>Reduce disk space and index size</p>
</li>
</ul>
<h3 id="heading-pay-attention-2">Pay Attention!!!</h3>
<ul>
<li><p>Only Oracle, MongoDB, and PostgreSQL support</p>
</li>
<li><p>Very common in queuing systems</p>
</li>
</ul>
<h1 id="heading-ix-update-index-statistic">IX. Update Index Statistic</h1>
<p>Over time, our data and indexes can become fragmented, which might reduce performance. So, we can consider running:</p>
<ul>
<li><p><strong>ANALYZE TABLE</strong>: calculates statistics for indexes</p>
<p>  In <strong>MySQL</strong>, ANALYZE TABLE returns a result set with the columns shown in the following table.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704539314638/423ae95e-4a45-4655-961a-ae15b1ab84c5.png" alt class="image--center mx-auto" /></p>
<p>E.g.: ANALYZE TABLE <em>users</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704539385563/79355a65-640b-4fa5-90a9-60cff25a5117.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p><strong>OPTIMIZE TABLE</strong>: reorganizes the physical storage of table data and associated index data, to reduce storage space and improve I/O efficiency when accessing the table.</p>
<p>  In <strong>MySQL</strong>, OPTIMIZE TABLE returns a result set with the columns shown in the following table.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704539698525/9c7b0273-62a6-4a4f-9597-3aff7481031c.png" alt class="image--center mx-auto" /></p>
<p>  For <code>InnoDB</code> tables, <a target="_blank" href="https://dev.mysql.com/doc/refman/8.0/en/optimize-table.html"><code>OPTIMIZE TABLE</code></a> is mapped to <a target="_blank" href="https://dev.mysql.com/doc/refman/8.0/en/alter-table.html"><code>ALTER TABLE ... FORCE</code></a>, which rebuilds the table to update index statistics and free unused space in the clustered index.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704539992037/7e26cefa-9419-4e38-a0a1-de293058a031.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-pay-attention-3">Pay Attention!!!</h3>
<ul>
<li><p>Think twice before acting, especially on your Prod databases.</p>
</li>
<li><p>Need to be reviewed by database experts because it can cause <strong>downtime.</strong></p>
</li>
</ul>
</li>
</ul>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704540173558/a009ea22-a251-4750-bb79-d24f70850dc3.jpeg" alt class="image--center mx-auto" /></p>
<h1 id="heading-x-no-index">X. No Index</h1>
<p>Last but not least, <strong>indexing is not a silver bullet</strong>. Sometimes, you get stuck improving your index performance. Please stay calm and think about alternative solutions rather than trying hard with indexing, such as:</p>
<ul>
<li><p><strong>Give up :D</strong></p>
</li>
<li><p>Use suitable databases for your requirements</p>
<p>  E.g.: To support aggregate queries, please use OLAP databases instead of OLTPs.</p>
</li>
<li><p>Build temp tables for heavy queries</p>
</li>
<li><p>Partition your tables, and archive data frequently (based on data retention)</p>
</li>
<li><p>Combine multiple databases</p>
</li>
<li><p>Apply CDC (Change Data Capture) to replicate data and scale your read performance.</p>
</li>
</ul>
<h1 id="heading-xi-conclusion">XI. Conclusion</h1>
<p>We just covered 10 strategies for effective indexing and achieving high query performance. I hope this article is useful for anyone working with indexes.</p>
<p>Bear in mind that each database and its storage engines have different index implementations and support different index types. Therefore, <strong>be mindful of the database type, storage engine, and version you are using before creating/optimizing your indexes.</strong></p>
<h1 id="heading-xii-references">XII. References</h1>
<ul>
<li><p><a target="_blank" href="https://www.amazon.com/High-Performance-MySQL-Strategies-Operating/dp/1492080519">High Performance MySQL 4th edition</a></p>
</li>
<li><p><a target="_blank" href="https://www.amazon.com/Performance-Explained-Everything-Developers-about/dp/3950307826">SQL Performance Explained</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Database Indexing - Data Structures & Supported Queries]]></title><description><![CDATA[I will tell you a fact that
Most of the hard issues come from databases when your system grows.
The bigger your system, the harder your database issues. Index, schema design, partition, and replication,... are important techniques to work with databa...]]></description><link>https://phamduyhieu.com/database-indexing-data-structures-supported-queries</link><guid isPermaLink="true">https://phamduyhieu.com/database-indexing-data-structures-supported-queries</guid><category><![CDATA[MySQL]]></category><category><![CDATA[indexing]]></category><category><![CDATA[Databases]]></category><category><![CDATA[PostgreSQL]]></category><category><![CDATA[B+ Tree]]></category><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Mon, 25 Dec 2023 14:10:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1703513233530/74951cfe-c1c1-4658-9dbb-df9ec34b02be.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I will tell you a fact that</p>
<p><strong><em>Most of the hard issues come from databases when your system grows.</em></strong></p>
<p>The bigger your system, the harder your database issues. Index, schema design, partition, and replication,... are important techniques to work with databases.</p>
<p>In particular, mastering indexing is a <strong>MUST</strong> for backend engineers.</p>
<h1 id="heading-i-introduction">I. Introduction</h1>
<p>Indexes are <strong>data structures</strong> that storage engines use to find rows quickly. This is the most powerful way to improve query performance.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703407093538/8d3dc5b6-12ec-4f58-a2e5-b4b1a3638bd9.jpeg" alt class="image--center mx-auto" /></p>
<ul>
<li><p><strong>Store in a separate space with source data</strong></p>
</li>
<li><p><strong>Index Creation does not change the source data</strong></p>
<p>  Databases create a copy of the column that we create index and link to the original data</p>
</li>
<li><p><strong>Index is implemented at storage engine layer</strong></p>
<p>  Each database, storage engine supports different index types</p>
</li>
</ul>
<p>A backend engineer needs to master database indexing, or someday they headaches with database issues when their system grows x5 x10.</p>
<h2 id="heading-benefits">Benefits</h2>
<ul>
<li><p><strong>Improve the search performance of SELECT</strong></p>
</li>
<li><p><strong>Reduce server’s workload and I/O of disk</strong></p>
</li>
</ul>
<p>Notes: Index also works for UPDATE queries with WHERE when using indexes to look up the record and update</p>
<p><em>E.g. UPDATE … WHERE id = 1</em></p>
<h2 id="heading-limitation">Limitation</h2>
<ul>
<li><p><strong>More space for index (disk, memory)</strong></p>
</li>
<li><p><strong>INSERT, UPDATE, DELETE queries are slower due to index maintenance</strong></p>
</li>
<li><p><strong>Too many indexes cause a slowdown in the database server</strong></p>
</li>
<li><p><strong>Confuses when the optimizer selects an execution strategy</strong></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703407498740/92980761-ea42-45bb-bd41-d1dc8022a5da.jpeg" alt class="image--center mx-auto" /></p>
<h1 id="heading-ii-data-structure-of-index">II. Data Structure of Index</h1>
<p>There are a lot of index types. However, in terms of structure, we have 2 most common: <strong>B-tree</strong> and <strong>Hash</strong>. So I will focus on these two types in this post.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703407736610/04850d4c-7251-4584-8fb3-f9234dc75dd9.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-1-b-tree-index">1. B-tree index</h2>
<p>This is a <strong>Balanced Tree</strong> (not a binary tree). Each node contains N values and pointers to the below nodes. Leaf nodes’ values are sorted and each leaf node contains a pointer to the original table.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703408169499/8681ebc4-07b8-4d10-bc25-b636da559bd9.png" alt class="image--center mx-auto" /></p>
<p>However, in modern databases such as MySQL and PostgreSQL, when we talk about B-tree, it actually is a B+ tree.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703408363994/d2f68f99-76e1-443f-af52-1381b3b3a7c2.png" alt class="image--center mx-auto" /></p>
<p>In B+ tree, leaf nodes are connected by a <strong>DOUBLE LINKED LIST.</strong> So it works more efficiently than B-tree in the case of range queries.</p>
<p>Each leaf node is stored in a block (page) – the smallest unit of the database. Each storage engine has a different block size.</p>
<p><em>E.g. MySQL (InnoDB) has a default block size of index = 16kB.</em></p>
<h3 id="heading-a-searching-on-b-tree">a. Searching on B+-tree</h3>
<p>The below picture shows an index fragment to illustrate a search for the key "<strong>57</strong>". The tree traversal starts at the root node on the left-hand side. Each entry is processed in ascending order until a value is greater than or equal to (&gt;=) the search term (<strong>57</strong>). Then the database follows the reference to the corresponding branch node and repeats the procedure until the tree traversal reaches a leaf node.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703408691488/2496e89a-cd9a-4989-afd7-b3c8d50b83ec.png" alt class="image--center mx-auto" /></p>
<p>From leaf nodes, we have connections to the table data. Unlike the index, the table data is not sorted at all.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703408702461/6c26dbab-3d51-49ea-b98a-8006abd17989.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-b-supported-query-types">b. Supported Query Types</h3>
<p>As I said, each database or storage engine supports different index types. So within the scope of this post, let's assume that we are working with <strong>MySQL</strong> + <strong>InnoDB</strong> engine.</p>
<p>we have a composite index of 2 columns <strong>employee_id</strong> and <strong>subsidiary_id</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703408776622/b0dca80d-ed40-4ceb-bd49-33960c1be987.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p><strong>Match full value</strong></p>
<p>  Your database will use your index if you query by full values (=)</p>
<p>  <strong><em>E.g.</em></strong></p>
<ul>
<li><p><em>WHERE employee_id = 1</em></p>
</li>
<li><p><em>WHERE employee_id = 123 and subsidiary_id = 20</em></p>
</li>
</ul>
</li>
<li><p><strong>Match leftmost prefix</strong></p>
<p>  Your database can use a composite index when searching with the leading (leftmost) columns. An index with three columns can be used when searching for the first column, when searching with the first two columns together, and when searching using all columns.</p>
<p>  <strong><em>E.g.</em></strong></p>
<ul>
<li><p><strong><em>OK</em></strong>: WHERE employee_id = 1</p>
</li>
<li><p><strong><em>NOT OK</em></strong>: WHERE subsidiary_id = 20</p>
</li>
</ul>
</li>
<li><p><strong>Match range condition</strong></p>
<p>  Your database will use your index if you query by a range condition on the first column.</p>
<p>  <strong><em>E.g.</em></strong></p>
<ul>
<li><p><strong><em>OK</em></strong>: WHERE employee_id &gt;= 123 and employee_id &lt; 125</p>
</li>
<li><p><strong><em>NOT OK</em></strong>: WHERE subsidiary_id &gt; 20</p>
</li>
</ul>
</li>
<li><p><strong>Match equal in the left and range in the right column</strong></p>
<p>  <strong><em>E.g.</em></strong></p>
<ul>
<li><p><strong><em>OK</em></strong> <em>: WHERE employee_id = 123 and subsidiary_id &gt; 20</em></p>
</li>
<li><p><strong><em>NOT OK</em></strong> <em>:</em> <strong><em>WHERE employee_id &gt; 123</em></strong> <em>and subsidiary_id = 20</em></p>
<p>  <em>\==&gt; Only use index for employee_id search.</em></p>
</li>
</ul>
</li>
<li><p><strong>LIKE Operator (leftmost)</strong></p>
<p>  <strong>LIKE</strong> filters can only use the characters before the first <strong>wildcard</strong> during tree traversal. The remaining characters are just filter predicates that do not narrow the scanned index range.</p>
<p>  The more selective the prefix before the first wildcard is, the smaller the scanned index range becomes.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703430717161/e8aaeac3-a97b-4409-ab05-332d51ae8ac0.png" alt class="image--center mx-auto" /></p>
<p>  <strong><em>E.g.</em></strong></p>
<ul>
<li><p><strong><em>OK</em></strong>: WHERE name LIKE ‘<strong>WI</strong>%<strong>ND</strong>’</p>
</li>
<li><p><strong><em>NOT OK</em></strong>: WHERE name LIKE ‘%<strong>WIND</strong>%’</p>
</li>
</ul>
</li>
<li><p><strong>Covering Indexes</strong></p>
<p>  The index covers the entire query so it is also called a <em>covering index</em>. It prevents table access and runs pretty fast.</p>
<p>  <strong><em>E.g.</em></strong> <em>SELECT subsidiary_id FROM Employee WHERE employee_id &gt; 123</em></p>
</li>
<li><p><strong>Index Merge</strong></p>
<p>  There are queries where a single index cannot do a perfect job.</p>
<p>  <strong><em>E.g.</em></strong> <em>queries with two or more independent range conditions</em></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703431530226/8b75c0d8-80c2-4189-9037-157931e1c9b7.png" alt class="image--center mx-auto" /></p>
<p>  You can of course accept the filter predicate and use a multi-column index nevertheless. That is the best solution in many cases anyway.</p>
<p>  But what I want to say here is we have another option: two separate indexes, one for each column. Then the database must scan both indexes first and then combine the results.</p>
</li>
<li><p><strong>Sorting/Group By</strong></p>
<p>  Your database will use your index in case of ordering or grouping because index data is sorted.</p>
<p>  <strong><em>E.g.</em></strong> <em>Select id, name FROM users ORDER BY id DESC limit 10</em></p>
</li>
<li><p><strong>Function Indexes</strong></p>
<p>  You must use the same function of your query to create the index.</p>
<p>  <strong><em>E.g.</em></strong></p>
<p>  <em>Your query is:</em></p>
<p>  <strong><em>SELECT</em></strong> <em>id, fullname</em> <strong><em>FROM</em></strong> <em>users</em> <strong><em>WHERE UPPER</em></strong>(fullname) = <strong><em>UPPER</em></strong>(‘Pham Duy Hieu’)</p>
<p>  \=&gt; You need to create an index with the <strong>UPPER</strong> function:</p>
<p>  <strong><em>CREATE INDEX</em></strong> <em>idx_name on users (<strong><strong>UPPER</strong></strong>(fullname))</em></p>
</li>
</ul>
<h3 id="heading-c-index-with-null-values">c. Index with NULL values</h3>
<p>When we create the index for <strong>Nullable columns</strong>, MySQL needs 1 byte to detect null/non-null values. Besides, optimizing queries (internal) in MySQL can be more challenging.</p>
<p><strong><em>E.g.</em></strong> <em>I have a</em> <strong><em>users</em></strong> <em>table</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703433743314/367b0950-a9b9-4966-9dd7-71581ae2140a.jpeg" alt class="image--center mx-auto" /></p>
<p>You can check the key length in <strong>Explain</strong> result:</p>
<p><code>explain select * from users where departure_id = 1;</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703433812183/61c8b022-6d2b-41bf-bb4a-52656ffb4d86.jpeg" alt class="image--center mx-auto" /></p>
<p>You can see that <strong>departure_id</strong> is <strong>interger</strong> 4 bytes, right? However, the real key length is 5 bytes due to 1 byte for its length.</p>
<p>So you should set <strong>NOT NULL</strong> for your columns whenever you can. Even when you do need to store a “<strong><em>no value</em></strong>” in a table, you might not need to use NULL. Perhaps you can use zero, a special value, or an empty string instead.</p>
<p>However, don’t be too afraid of using NULL when you need to represent an unknown value. In some cases, it’s better to use NULL than a magical constant.</p>
<hr />
<h2 id="heading-2-hash-index">2. Hash Index</h2>
<p>The index type is based on the Hashing technique to build a Hash Table and store indexed data. However, it is only supported by MySQL (Memory), Oracle and PostgreSQL.</p>
<p>If you are using MySQL InnoDB and you create a HASH index, InnoDB silently changes <strong>HASH</strong> to <strong>Btree</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703511770533/06af16cd-92e8-4acc-8120-778d6a93f461.png" alt class="image--center mx-auto" /></p>
<p>Here are some points of a hash index:</p>
<ul>
<li><p>Good performance with "="</p>
</li>
<li><p>Don't support range queries (&gt;, &lt;, &gt;=, &lt;=) and sorting, group by</p>
</li>
<li><p>Hash Collision: should not be used for columns with many duplicated values</p>
</li>
<li><p>More space for hashing values (than B-tree)</p>
</li>
</ul>
<hr />
<p>We have just walked through the most common data structures for indexing and the supported query types accordingly. In the next post, I will share common indexing strategies allowing you to start practicing on your own. See youuuuu!</p>
<p>(continued)</p>
<h1 id="heading-iv-references">IV. References</h1>
<ul>
<li><p><a target="_blank" href="https://www.amazon.com/High-Performance-MySQL-Strategies-Operating/dp/1492080519">High Performance MySQL, 4th Edition</a></p>
</li>
<li><p><a target="_blank" href="https://www.amazon.com/Performance-Explained-Everything-Developers-about/dp/3950307826">SQL Performance Explained Everything Developers Need to Know about SQL Performance</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Spring Boot 3 And Java 17 Migration Guide]]></title><description><![CDATA[Spring Boot 3.0 is a new major release that offers new features and improvements. However, it requires Java 17 as a minimum version and comes with numerous compatibility issues if you intend to upgrade.
I. Pros and Cons
You need to analyze the pros a...]]></description><link>https://phamduyhieu.com/spring-boot-3-and-java-17-migration-guide</link><guid isPermaLink="true">https://phamduyhieu.com/spring-boot-3-and-java-17-migration-guide</guid><category><![CDATA[Springboot]]></category><category><![CDATA[Java]]></category><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Thu, 16 Nov 2023 17:24:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1699952638329/183b925a-3af0-44ea-bdf2-5632c19095ff.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Spring Boot 3.0 is a new major release that offers new features and improvements. However, it requires Java 17 as a minimum version and comes with numerous compatibility issues if you intend to upgrade.</p>
<h1 id="heading-i-pros-and-cons">I. Pros and Cons</h1>
<p>You need to analyze the pros and cons of our migration. In my experience, there are some points you should review:</p>
<h2 id="heading-1-pros">1. Pros</h2>
<h3 id="heading-java-17-baseline">Java 17 Baseline</h3>
<p>You’ll need to upgrade to JDK 17 before you can develop Spring Boot 3.0 applications. This means you can take advantage of the latest features and performance improvements that Java 17 offers.</p>
<h3 id="heading-graalvm-native-image-support">GraalVM Native Image Support</h3>
<p>GraalVM Native Images provide a new way to deploy and run Java applications. It provides various advantages, like an instant startup and reduced memory consumption (pain points of Spring Boot apps).</p>
<h3 id="heading-improved-observability-with-micrometer-and-micrometer-tracing">Improved observability with Micrometer and Micrometer Tracing</h3>
<p>You can check more details <a target="_blank" href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Release-Notes#micrometer-updates">here</a>.</p>
<h2 id="heading-2-cons">2. Cons</h2>
<h3 id="heading-timeresouces-constraints">Time/Resouces constraints</h3>
<p>Migrating to a new major release takes time and resources, especially for testing. This migration affects all your flows so needs to be tested carefully. While you can update your code within a few days, please plan for testing to span more than a week (the duration depends on the size of your project).</p>
<h3 id="heading-risk-of-new-bugs">Risk of new bugs</h3>
<p>As mentioned earlier, the migration affects all your flows. Therefore, if your test coverage doesn't cover all your code, please be careful. Test your end-to-end flows and scrutinize the logs for any new exceptions or discrepancies compared to the previous state.</p>
<h1 id="heading-ii-before-we-start">II. Before we start</h1>
<p>If you’re currently running with an earlier version of Spring Boot, I recommend that you <a target="_blank" href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.7-Release-Notes">upgrade to Spring Boot 2.7</a> before migrating to Spring Boot 3.0. It minimizes compatibility issues as much as possible.</p>
<h2 id="heading-review-dependencies">Review Dependencies</h2>
<p>You can review your dependencies and <a target="_blank" href="https://docs.spring.io/spring-boot/docs/3.0.x/reference/html/dependency-versions.html#appendix.dependency-versions">dependency management for 3.x</a> to assess how your project is affected.</p>
<p>For dependencies that are not managed by Spring Boot, you can identify the compatible version before upgrading.</p>
<h2 id="heading-review-deprecations">Review Deprecations</h2>
<p>Classes, methods and properties that were deprecated in Spring Boot 2.x have been removed in this release. Prior to upgrading, please ensure that you are not calling any deprecated methods.</p>
<h1 id="heading-iii-migrate-to-spring-boot-3-and-java-17">III. Migrate to Spring Boot 3 and Java 17</h1>
<h2 id="heading-1-spring-boot-template-project">1. Spring Boot Template Project</h2>
<p>I will use my project as an example for you guys to share how I migrated from Spring Boot 2.7 (Java 11) to Spring Boot 3 and Java 17.</p>
<p>Github: <a target="_blank" href="https://github.com/hieubz/spring-boot-template-project">https://github.com/hieubz/spring-boot-template-project</a></p>
<p>This project includes the implementation of common backend features, designed to assist both myself and other Spring Boot developers in coding more efficiently. For further details, you can read more <a target="_blank" href="https://phamduyhieu.com/spring-boot-based-project-introduction">here</a>.</p>
<h2 id="heading-2-migration-steps">2 . Migration Steps</h2>
<h3 id="heading-configuration-properties-migration">Configuration Properties Migration</h3>
<p>Let's add the migrator by adding the following to your Maven <code>pom.xml</code>:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-properties-migrator<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>runtime<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<p>This will analyze your application’s environment and print diagnostics at startup console logs. Then you can based on that update your properties accordingly.</p>
<h3 id="heading-update-dependencies">Update Dependencies</h3>
<ul>
<li>We start with the parent pom <strong>spring-boot-starter-parent</strong> and Java version</li>
</ul>
<pre><code class="lang-xml">    <span class="hljs-tag">&lt;<span class="hljs-name">parent</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.1.5<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">relativePath</span>/&gt;</span> <span class="hljs-comment">&lt;!-- lookup parent from repository --&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">parent</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">properties</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">java.version</span>&gt;</span>17<span class="hljs-tag">&lt;/<span class="hljs-name">java.version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">properties</span>&gt;</span>
</code></pre>
<p><strong>Tips</strong>: We shouldn't specify the version of Spring Data JPA, Spring Web, Spring Data Redis,... because their compatible versions are already declared in the parent POM.</p>
<pre><code class="lang-xml">        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-data-jpa<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<ul>
<li>If you are working with MySQL, let's replace your <strong>mysql-connector-java</strong> by:</li>
</ul>
<pre><code class="lang-xml">        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.mysql<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mysql-connector-j<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>8.1.0<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<ul>
<li>If you are using <strong>logback</strong> for logging, let's update it to v1.4.11</li>
</ul>
<pre><code class="lang-xml">        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>ch.qos.logback<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>logback-classic<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.4.11<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<ul>
<li>If you are using <strong>Openfeign</strong> for integrations, let's update it to v4.x</li>
</ul>
<pre><code class="lang-xml">        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.cloud<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-cloud-starter-openfeign<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>4.0.4<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<ul>
<li>If you are using Spring JDBC, let's update it to v6.x</li>
</ul>
<pre><code class="lang-xml">        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-jdbc<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>6.0.12<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<ul>
<li>If you are using <strong>Jackson</strong> for data binding, let's update it to v2.15.x</li>
</ul>
<pre><code class="lang-xml">        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.fasterxml.jackson.core<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>jackson-databind<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.15.3<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

        <span class="hljs-comment">&lt;!--  support Java 8 Date/time Serialize/Deserialize  --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.fasterxml.jackson.datatype<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>jackson-datatype-jsr310<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.15.3<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<ul>
<li>If you are using <strong>Redisson</strong> as a Redis client, let's update it to v3.24.x</li>
</ul>
<pre><code class="lang-xml">        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.redisson<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>redisson-spring-boot-starter<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.24.3<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.redisson<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>redisson-spring-data-31<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.24.3<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<ul>
<li>You should use the default <strong>spring-boot-starter-test</strong> for unit testing. However, If you are customizing <strong>mockito-core</strong>, let's update it to v5.3.x</li>
</ul>
<pre><code class="lang-xml">        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.mockito<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mockito-core<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.3.1<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>test<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<ul>
<li>If you are using <strong>jjwt</strong> for authentication, let's update it to 0.12.x</li>
</ul>
<pre><code class="lang-xml">        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>io.jsonwebtoken<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>jjwt<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.12.3<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<ul>
<li>If you are using Springdoc for API documentation, let's replace your <strong>springdoc-openapi-ui</strong> by:</li>
</ul>
<pre><code class="lang-xml">        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springdoc<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>springdoc-openapi-starter-webmvc-ui<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.2.0<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<ul>
<li>If you are using <strong>spring-kafka</strong> as your Kafka client, let's update it to v3.0.x</li>
</ul>
<pre><code class="lang-xml">        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.kafka<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-kafka<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.0.10<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<h3 id="heading-rebuild-and-change-the-code">Rebuild and change the code</h3>
<ul>
<li><p>After updating your dependencies, let's rebuild your code first and check for any issues</p>
<pre><code class="lang-xml">  mvn clean package
</code></pre>
</li>
<li><p>Spring Boot 3.0 has migrated from Java EE to Jakarta EE APIs for all dependencies. So you should face the <strong>javax</strong> issue in your first build:</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700150843844/21820494-3487-4068-ac83-215f6d508f8d.png" alt class="image--center mx-auto" /></p>
<p>  Then you just need to replace all <strong>javax</strong> in your imports by <strong>jakarta</strong> (should use <strong>Ctrl</strong>+<strong>Shift</strong>+<strong>R</strong> to replace on IntelliJ)</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700151000527/df642e61-bf9d-438a-8a8f-8e0c4adaa076.png" alt class="image--center mx-auto" /></p>
<p>  If the Spring migrator is working, you can see a WARNING log in the startup console:</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700151465602/af66340d-eb50-418d-8f87-3727da5eb748.png" alt class="image--center mx-auto" /></p>
<p>  Simply update as suggested.</p>
</li>
<li><p>In Hibernate 6, you can use <strong>MySQLDialect</strong> for all MySQL versions (MySQL5Dialect, MySQL8Dialect have been deprecated)</p>
</li>
</ul>
<pre><code class="lang-haskell"><span class="hljs-title">spring</span>.jpa.properties.hibernate.dialect=org.hibernate.dialect.<span class="hljs-type">MySQLDialect</span>
</code></pre>
<ul>
<li>JPA <strong>SpringPhysicalNamingStrategy</strong> is replaced by <strong>CamelCaseToUnderscoresNamingStrategy</strong></li>
</ul>
<pre><code class="lang-haskell"><span class="hljs-title">org</span>.springframework.boot.orm.jpa.hibernate.<span class="hljs-type">SpringPhysicalNamingStrategy</span>

==&gt; org.hibernate.boot.model.naming.<span class="hljs-type">CamelCaseToUnderscoresNamingStrategy</span>
</code></pre>
<ul>
<li>Spring Security is not working if you are using <strong>WebSecurityConfigurerAdapter</strong> (deprecated). Besides, in v3.x, you have to use lambda to configure filterChain.</li>
</ul>
<p>So you have to remove the extension of <strong>WebSecurityConfigurerAdapter</strong> class.</p>
<pre><code class="lang-java"><span class="hljs-comment">// Now</span>
<span class="hljs-meta">@Configuration</span>
<span class="hljs-meta">@EnableWebSecurity</span>
<span class="hljs-meta">@EnableGlobalMethodSecurity(prePostEnabled = true)</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebSecurityConfig</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">WebSecurityConfigurerAdapter</span> </span>{}

<span class="hljs-comment">// Then without extension</span>
<span class="hljs-meta">@Configuration</span>
<span class="hljs-meta">@EnableWebSecurity</span>
<span class="hljs-meta">@EnableMethodSecurity</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebSecurityConfig</span> </span>{}
</code></pre>
<p>Then do several updates for <strong>AuthenticationManager</strong> bean creation:</p>
<pre><code class="lang-java"><span class="hljs-comment">// Now with the class extends WebSecurityConfigurerAdapter</span>
  <span class="hljs-meta">@Bean</span>
  <span class="hljs-meta">@Override</span>
  <span class="hljs-function"><span class="hljs-keyword">public</span> AuthenticationManager <span class="hljs-title">authenticationManagerBean</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception </span>{
    <span class="hljs-comment">// Get AuthenticationManager bean</span>
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">super</span>.authenticationManagerBean();
  }

<span class="hljs-comment">// Then without extension</span>
  <span class="hljs-meta">@Bean</span>
  <span class="hljs-function"><span class="hljs-keyword">public</span> AuthenticationManager <span class="hljs-title">authenticationManager</span><span class="hljs-params">(AuthenticationConfiguration authConfig)</span> <span class="hljs-keyword">throws</span> Exception </span>{
    <span class="hljs-keyword">return</span> authConfig.getAuthenticationManager();
  }
</code></pre>
<p>And <strong>SecurityFilterChain:</strong></p>
<pre><code class="lang-java"><span class="hljs-comment">/** We have to use Lambda for SecurityFilterChain configuration **/</span>

<span class="hljs-comment">// Now with the class extends WebSecurityConfigurerAdapter</span>
  <span class="hljs-meta">@Override</span>
  <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">configure</span><span class="hljs-params">(HttpSecurity http)</span> <span class="hljs-keyword">throws</span> Exception </span>{
      http.cors().and().csrf().disable();
      http.authorizeRequests().antMatchers(AUTH_WHITELIST).permitAll().anyRequest().authenticated();
      http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
      http.exceptionHandling().authenticationEntryPoint(authEntryPointJwt);
      http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
  }

// Then with lambda
  <span class="hljs-meta">@Bean</span>
  <span class="hljs-function"><span class="hljs-keyword">protected</span> SecurityFilterChain <span class="hljs-title">configure</span><span class="hljs-params">(HttpSecurity http)</span> <span class="hljs-keyword">throws</span> Exception </span>{
      http.cors(AbstractHttpConfigurer::disable).csrf(AbstractHttpConfigurer::disable);
      http.authorizeHttpRequests(auth -&gt; auth.requestMatchers(AUTH_WHITELIST).permitAll().anyRequest().authenticated());
      http.sessionManagement(s -&gt; s.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
      http.exceptionHandling(ex -&gt; ex.authenticationEntryPoint(authEntryPointJwt));
      http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
      <span class="hljs-keyword">return</span> http.build();
  }
</code></pre>
<ul>
<li><p><strong>Powermock</strong> is not working with Spring Boot 3 and JDK 17. Its latest update is in Feb 2022. So you need to move to <strong>Mockito</strong> if you are using <strong>Powermock</strong>.</p>
</li>
<li><p>The <strong>jjwt</strong> library updates its API, so we update our code:</p>
</li>
</ul>
<pre><code class="lang-java"><span class="hljs-comment">// Now</span>
  <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">generateJwtToken</span><span class="hljs-params">(Long userId)</span> </span>{
    <span class="hljs-keyword">return</span> Jwts.builder()
        .setSubject(userId.toString())
        .setIssuedAt(<span class="hljs-keyword">new</span> Date())
        .setExpiration(<span class="hljs-keyword">new</span> Date(<span class="hljs-keyword">new</span> Date().getTime() + jwtExpirationMs))
        .signWith(SignatureAlgorithm.HS256, jwtSecret.getBytes(StandardCharsets.UTF_8))
        .compact();
  }


<span class="hljs-comment">// Then</span>
  <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">generateJwtToken</span><span class="hljs-params">(Long userId)</span> </span>{
    <span class="hljs-keyword">return</span> Jwts.builder()
        .subject(userId.toString())
        .issuedAt(<span class="hljs-keyword">new</span> Date())
        .expiration(<span class="hljs-keyword">new</span> Date(<span class="hljs-keyword">new</span> Date().getTime() + jwtExpirationMs))
        .signWith(Keys.hmacShaKeyFor(jwtSecret.getBytes(StandardCharsets.UTF_8)), Jwts.SIG.HS256)
        .compact();
  }
</code></pre>
<p>And the JWT parser:</p>
<pre><code class="lang-java"><span class="hljs-comment">// Now</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> Claims <span class="hljs-title">getJwtTokenClaim</span><span class="hljs-params">(String jwt)</span> </span>{
   <span class="hljs-keyword">return</span> Jwts.parser()
        .setSigningKey(jwtSecret.getBytes(StandardCharsets.UTF_8))
        .parseClaimsJws(jwt)
        .getBody();
}

<span class="hljs-comment">// Then</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> Claims <span class="hljs-title">getJwtTokenClaim</span><span class="hljs-params">(String jwt)</span> </span>{
    <span class="hljs-keyword">return</span> Jwts.parser()
        .verifyWith(Keys.hmacShaKeyFor(jwtSecret.getBytes(StandardCharsets.UTF_8)))
        .build()
        .parseSignedClaims(jwt)
        .getPayload();
}
</code></pre>
<ul>
<li>Finally, rebuild and check for any issues. In my project, there are no issues left, so I stop updating the code here.</li>
</ul>
<h3 id="heading-testing">Testing</h3>
<p>Since this is a major upgrade, carefully test all APIs for discrepancies or exceptions. Review them one by one and monitor logs.</p>
<h1 id="heading-iv-conclusion">IV. Conclusion</h1>
<p>We just completed the migration to Spring Boot 3 and JDK 17. There are many issues during this process, so stay calm and get things done :))). I hope this is helpful for anyone planning the migration.</p>
<p>Hieu Pham.</p>
]]></content:encoded></item><item><title><![CDATA[Câu Chuyện Về Con Cá Chình]]></title><description><![CDATA[Thời cổ đại, ngư dân Nhật Bản ra biển bắt cá chình, vì thuyền nhỏ, khi trở về đến bờ cá chình đã chết hết.
Nhưng có một ngư dân, mỗi lần anh chở cá về chúng đều còn sống. Vì thế cá của anh bán được giá cao gấp đôi người khác. Mấy năm sau, người ngư d...]]></description><link>https://phamduyhieu.com/cau-chuyen-ve-con-ca-chinh</link><guid isPermaLink="true">https://phamduyhieu.com/cau-chuyen-ve-con-ca-chinh</guid><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Sun, 06 Aug 2023 02:56:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691290455468/ea6b86b4-b347-43f2-9e08-ec7d6ae77a5a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Thời cổ đại, ngư dân Nhật Bản ra biển bắt cá chình, vì thuyền nhỏ, khi trở về đến bờ cá chình đã chết hết.</p>
<p>Nhưng có một ngư dân, mỗi lần anh chở cá về chúng đều còn sống. Vì thế cá của anh bán được giá cao gấp đôi người khác. Mấy năm sau, người ngư dân này đã trở thành một phú ông giàu có vang danh gần xa. Đến khi bệnh nặng không thể ra biển được nữa, người ngư dân mới đem bí mật của mình nói lại với con trai về bí quyết giúp cá chình không chết:</p>
<p>Trong khoang thuyền chứa đầy cá chình, ông đã bỏ một con cá nheo vào đó. Trong tự nhiên, cá chình luôn đánh nhau với nheo.</p>
<p>Để chống lại những đợt công kích của cá nheo, cá chình buộc phải cố gắng nghênh chiến. Trong tình trạng đấu tranh như vậy, bản năng sống của cá chình sẽ được huy động tối đa, cho nên nó vẫn còn sống khi vào đến bờ.</p>
<p>Người ngư dân còn nói với con trai, nguyên nhân khiến cá chình chết là vì chúng biết chúng đã bị bắt, trước mắt chúng chỉ có cái chết, hy vọng sống đã bị dập tắt, cho nên ở trong khoang không được bao lâu thì chúng đều chết hết.</p>
<p>Cuối cùng bác ngư dân khuyên các con, phải dũng cảm đấu tranh, chỉ có đấu tranh, cuộc sống mới tràn đầy niềm tin và hy vọng.</p>
<p>Ở Nhật Bản, khi trẻ con vừa mới hiểu chuyện, câu chuyện đầu tiên mà cha mẹ kể cho chúng chính là câu chuyện về cá chình.</p>
<p>Tất cả những đứa trẻ Nhật Bản từ nhỏ đã được truyền niềm tin: Chỉ có dũng cảm chiến đấu, mới có được thành công và hy vọng!</p>
<p>(Sưu tầm)</p>
]]></content:encoded></item><item><title><![CDATA[Best Practices in Java]]></title><description><![CDATA[I'd like to share some best practices to help you effectively use the Java programming language and its fundamental libraries.
This article has 4 parts:

General programming: how to use variables, control structures, libraries, data types,... effecti...]]></description><link>https://phamduyhieu.com/best-practices-in-java</link><guid isPermaLink="true">https://phamduyhieu.com/best-practices-in-java</guid><category><![CDATA[Java]]></category><category><![CDATA[best practices]]></category><category><![CDATA[Core Java]]></category><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Sun, 19 Mar 2023 08:04:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1679213071290/cb801e04-47cf-48d7-a1e4-d0daff732193.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I'd like to share some best practices to help you effectively use the Java programming language and its fundamental libraries.</p>
<p>This article has 4 parts:</p>
<ul>
<li><p><strong>General programming</strong>: how to use variables, control structures, libraries, data types,... effectively.</p>
</li>
<li><p><strong>Lambdas and Streams</strong>: how to make the best use of functional interfaces, lambdas, and method references.</p>
</li>
<li><p><strong>Exceptions</strong>: guidelines for using exceptions effectively.</p>
</li>
<li><p><strong>Concurrency</strong>: write clear and correct concurrent programs.</p>
</li>
</ul>
<p>Ok, let's go!!!</p>
<h1 id="heading-i-general-programming">I. General Programming</h1>
<h3 id="heading-a-prefer-for-each-loops-to-traditional-for-loops">a. Prefer <em>for-each</em> loops to traditional <em>for loops</em></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679114068864/dd0a62f8-48a8-40bb-8382-49eca3e581dc.png" alt class="image--center mx-auto" /></p>
<p><strong>for-each loops</strong> get rid of the clutter and the opportunity for error by hiding the iterator or index variable. There is no performance penalty for using for-each</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679114095797/c2cca0c9-700b-4eea-bf87-a74594dfa5ab.png" alt class="image--center mx-auto" /></p>
<p>However, there are some common situations where you can’t use for-each:</p>
<ul>
<li><p>need the array index in order to do something</p>
</li>
<li><p>need to traverse multiple collections in parallel, then you need explicit control over the iterator or index variable</p>
</li>
</ul>
<h3 id="heading-b-prefer-primitive-types-to-boxed-primitives">b. Prefer primitive types to boxed primitives</h3>
<ul>
<li><p>Primitives are more time and space efficient than boxed primitives</p>
</li>
<li><p>Applying the == operator to boxed primitives is almost always <strong>wrong</strong> =&gt; be careful when comparing boxed primitives.</p>
</li>
<li><p>When you mix <strong>primitives</strong> and <strong>boxed primitives</strong> in an operation, the boxed primitive is <strong>auto-unboxed.</strong> If a null object reference is auto-unboxed, you get a NullPointerException</p>
</li>
<li><p>Repeatedly boxed and unboxed causing performance degradation.</p>
</li>
</ul>
<h3 id="heading-c-avoid-strings-where-other-types-are-more-appropriate">c. Avoid Strings where other types are more appropriate</h3>
<ul>
<li><p>If it’s <strong>numeric</strong>, it should be translated into the appropriate numeric type, such as <strong>int, long</strong>, <strong>float</strong>, or <strong>BigInteger</strong></p>
</li>
<li><p>If it’s the answer to a <strong>yes-or-no</strong> question, it should be translated into an appropriate <strong>enum</strong> type or a <strong>boolean</strong></p>
</li>
</ul>
<h3 id="heading-d-beware-the-performance-of-string-concatenation">d. Beware the performance of string concatenation</h3>
<p>Strings are <strong><em>immutable,</em></strong> so when two strings are concatenated, the contents of both are copied and Java creates a new String</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679116493445/f59ebfa1-84e9-48db-ac7f-1023fa7596d4.png" alt class="image--center mx-auto" /></p>
<p>To achieve acceptable performance, use a <strong>StringBuilder</strong> in place of a <strong>String</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679116536442/aed170ac-e234-470c-ba81-10ec8da49500.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-e-refer-to-objects-by-their-interfaces">e. Refer to objects by their interfaces</h3>
<p>If appropriate interface types exist, then <strong>parameters</strong>, <strong>return</strong> values, <strong>variables</strong>, and <strong>fields</strong> should all be declared using interface types</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679124883963/5af20ed8-d617-4f32-b2df-ba27227d34eb.png" alt class="image--center mx-auto" /></p>
<p>Your program will be much more flexible to switch implementations. However, it is entirely appropriate to refer to an object by a class rather than an interface if no appropriate interface exists. If there is no appropriate interface, just use the least specific class in the class hierarchy that provides the required functionality**.**</p>
<h1 id="heading-ii-lambdas-and-streams">II. Lambdas and Streams</h1>
<h3 id="heading-a-prefer-lambdas-to-anonymous-classes">a. Prefer lambdas to anonymous classes</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679125176389/9f1b3247-f20e-4b75-b131-0248e9bb148a.png" alt class="image--center mx-auto" /></p>
<p>In Java 8, the language formalized the notion that interfaces with a single abstract method are special and deserve special treatment. These interfaces are now known as <strong><em>functional interfaces</em></strong>, and the language allows you to <strong><em>create instances of these interfaces using lambda expressions</em></strong>, or lambdas for short.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679125314668/668790a6-6cc1-4d5f-8055-4f2deed4ffe4.png" alt class="image--center mx-auto" /></p>
<p>However, lambdas lack names and documentation. If a computation isn’t self-explanatory or exceeds a few lines, don’t put it in a lambda. <strong>One line</strong> is ideal for lambda, and <strong>three lines</strong> are a reasonable maximum.</p>
<h3 id="heading-b-prefer-method-references-to-lambdas">b. Prefer method references to lambdas</h3>
<p>Java provides a way to generate function objects even more succinct than lambdas: <strong><em>method references</em></strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679126388443/2467d3cd-0529-456f-a087-5846792f7590.png" alt class="image--center mx-auto" /></p>
<p>should become:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679126404826/505abe3b-38a9-4371-b57b-287d5f8fcefb.png" alt class="image--center mx-auto" /></p>
<p>However, where method references are shorter and clearer, use them; where they aren’t, stick with lambdas.</p>
<h3 id="heading-c-favor-the-use-of-standard-functional-interfaces">c. Favor the use of standard functional interfaces</h3>
<p>If one of the standard functional interfaces does the job, you should generally use it in preference to a purpose-built functional interface.</p>
<p>Of course you need to write your own if none of the standard ones does what you need, for example if you require a predicate that takes three parameters.</p>
<h3 id="heading-d-use-streams-judiciously">d. Use streams judiciously</h3>
<ul>
<li><p>Overusing streams makes programs hard to read and maintain.</p>
</li>
<li><p>In the absence of explicit types, careful naming of lambda parameters is essential to the readability of stream pipelines.</p>
</li>
<li><p>Using helper methods is important for readability in stream pipelines.</p>
</li>
</ul>
<h3 id="heading-f-prefer-collection-to-stream-as-a-return-type">f. Prefer Collection to Stream as a return type</h3>
<p>When writing a method that returns a sequence of elements, remember that some of your users may want to process them as a <strong>stream</strong> while others may want to <strong>iterate</strong> over them</p>
<p>\=&gt; Collection or an appropriate subtype is generally the best return type</p>
<h3 id="heading-g-use-caution-when-making-streams-parallel">g. Use caution when making streams parallel</h3>
<p>Java 8 introduced streams, which can be parallelized with a single call to the <strong>parallel</strong> method.</p>
<ul>
<li><p>Parallelizing a pipeline is unlikely to increase its performance if the source is from <strong>Stream.iterate</strong>, or the intermediate operation <strong>limit</strong> is used</p>
</li>
<li><p>Performance gains from parallelism are best on streams over <strong>ArrayList</strong>, <strong>HashMap</strong>, <strong>HashSet</strong>, and <strong>ConcurrentHashMap</strong> instances; <strong>arrays</strong>; <strong>int</strong> <strong>ranges</strong>; and <strong>long ranges.</strong> What these data structures have in common is that they can all be accurately and cheaply split into subranges of any desired sizes, which makes it easy to divide work among parallel threads</p>
</li>
<li><p>Do not even attempt to parallelize a stream pipeline unless you have good reason to believe that it will preserve the correctness of the computation and increase its speed</p>
</li>
</ul>
<h1 id="heading-iii-exceptions">III. Exceptions</h1>
<h3 id="heading-a-use-checked-exceptions-for-recoverable-conditions-and-runtime-exceptions-for-programming-errors">a. Use checked exceptions for recoverable conditions and runtime exceptions for programming errors</h3>
<ul>
<li><p>Use checked exceptions for conditions from which the caller can reasonably be expected to recover.</p>
<p>  <em>Ex: For example, suppose a checked exception is thrown when an attempt to make a purchase with a gift card fails due to insufficient funds. The exception should provide an accessor method to query the amount of the shortfall. This will enable the caller to relay the amount to the shopper.</em></p>
</li>
<li><p>If a program throws an unchecked exception or an error, it is generally the case that recovery is impossible and continued execution would do more harm than good.</p>
<p>  <em>Ex:</em> <strong><em>ArrayIndexOutOfBoundsException, NullPointerException</em></strong></p>
</li>
<li><p>If it isn’t clear whether recovery is possible, you’re probably better off using an unchecked exception</p>
</li>
</ul>
<h3 id="heading-b-avoid-unnecessary-use-of-checked-exceptions">b. Avoid unnecessary use of checked exceptions</h3>
<ul>
<li><p>Overuse of checked exceptions places a burden on the user of the API</p>
</li>
<li><p>If callers won’t be able to recover from failures, throw unchecked exceptions. If recovery may be possible and you want to force callers to handle exceptional conditions, first consider returning an <strong>optional</strong>.</p>
</li>
</ul>
<p>However, if <strong>optional</strong> provides insufficient information in the case of failure, you should throw a checked exception.</p>
<h3 id="heading-c-favor-the-use-of-standard-exceptions">c. Favor the use of standard exceptions</h3>
<p>The Java libraries provide a set of exceptions that cover most of the exception-throwing needs of most APIs.</p>
<p>This table summarizes the most commonly reused exceptions:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679156766293/1c6ee740-dee8-4e2c-8f81-23f616f0f842.png" alt class="image--center mx-auto" /></p>
<p>Do not reuse <strong>Exception</strong>, <strong>RuntimeException</strong>, <strong>Throwable</strong>, or <strong>Error</strong> directly.</p>
<h3 id="heading-d-throw-exceptions-appropriate-to-the-abstraction">d. Throw exceptions appropriate to the abstraction</h3>
<p>Higher layers should catch <em>lower-level</em> exceptions and, in their place, throw exceptions that can be explained in terms of the <em>higher-level</em> abstraction <strong><em>(exception translation)</em></strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679156897223/286af9fd-7dfe-4a61-9071-ff5c9920fd61.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-e-include-failure-capture-information-in-detail-messages">e. Include failure-capture information in detail messages</h3>
<ul>
<li>To capture a failure, the detail message of an exception should contain the values of all parameters and fields that contributed to the exception.</li>
</ul>
<p><em>Ex: The detail message of an</em> <strong><em>IndexOutOfBoundsException</em></strong> <em>should contain the</em> <strong><em>lower bound</em></strong>*, the* <strong><em>upper bound</em></strong>*, and the* <strong><em>index</em></strong> <strong><em>value that failed</em></strong> <em>to lie between the bounds</em></p>
<ul>
<li>Do not include <strong>passwords</strong>, <strong>encryption keys</strong>,... in detail messages</li>
</ul>
<h3 id="heading-f-strive-for-failure-atomicity">f. Strive for failure atomicity</h3>
<p>A failed method invocation should leave the object in the state that it was in prior to the invocation. There are several ways to achieve this effect:</p>
<ul>
<li><p>Design <strong>immutable</strong> objects</p>
</li>
<li><p>For methods that operate on <strong>mutable</strong> objects ==&gt; <strong>check parameters for validity</strong> <strong>before performing</strong> the operation (exceptions will be thrown before object modification commences)</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679157729351/f5273650-7517-416d-8135-f5a69e0701ef.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<h3 id="heading-g-dont-ignore-exceptions">g. Don't ignore exceptions</h3>
<p>When the designers of an API declare a method to throw an exception, they are trying to tell you something. Don’t ignore it!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679192847562/c62d9d56-cefe-4fe3-99b7-435eedc785ec.png" alt class="image--center mx-auto" /></p>
<p>If you choose to ignore an exception, the catch block should contain a <strong>comment</strong> explaining why it is appropriate to do so, and the <strong>variable should be named ignored</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679192925292/88f842fd-c996-4708-921b-4f6d67fe15d2.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-iv-concurrency">IV. Concurrency</h1>
<h3 id="heading-a-synchronize-access-to-shared-mutable-data">a. Synchronize access to shared mutable data</h3>
<p>The synchronized keyword ensures that only a single thread can execute a method or block at one time.</p>
<ul>
<li><p><strong>when multiple threads share mutable data, each thread that reads or writes the data must perform synchronization</strong></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679194964025/47f4e8ae-87d1-401c-8c22-46572cad0a49.png" alt class="image--center mx-auto" /></p>
<p>  <em>without synchronization, there is no guarantee that one thread’s changes will be visible to another thread</em></p>
</li>
<li><p><strong><em>volatile</em></strong> modifier performs <em>no mutual exclusion</em>, but guarantees that any thread that reads the field will see the <strong><em>most recently</em></strong> written value</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679194986373/5d6c403f-2a60-4a39-b5a0-ecbe8aa05bd4.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<p>However, you have to be careful when using <strong>volatile.</strong> For example, in the following method, the problem is that the increment operator (<strong>++</strong>) is not atomic. It performs <strong><em>two operations</em></strong> (volatile still works if performs one operation) on the <strong><em>nextSerialNumber</em></strong> field: first it reads the value, and then it writes back a new value:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679194341384/d6b83604-ff52-44fe-983d-4aec32304bdc.png" alt class="image--center mx-auto" /></p>
<p>If a second thread reads the field between the time a thread reads the old value and writes back a new one, the second thread will see the same value as the first and return the same serial number ==&gt; <strong>computes the wrong results</strong>.</p>
<p>One way to fix it is to use <strong>AtomicLong</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679194623659/dff71028-51d6-4d1c-b654-7f7a2c4af5ae.png" alt class="image--center mx-auto" /></p>
<p>The best way to avoid the problems discussed is not to share mutable data.</p>
<h3 id="heading-b-avoid-excessive-synchronization">b. Avoid excessive synchronization</h3>
<ul>
<li><p>Excessive synchronization can cause reduced performance, deadlock,...</p>
</li>
<li><p>Inside a synchronized region, do not invoke a method that is designed to be overridden, or one provided by a client in the form of a function object</p>
<p>  \=&gt; has no knowledge of what the method does and has no control over it.</p>
</li>
</ul>
<p>There are some ways to <strong>move the alien method invocations out of the synchronized block</strong>:</p>
<ul>
<li><p>taking a <em>“snapshot”</em> of shared mutable data =&gt; safely traversed without a lock</p>
</li>
<li><p>use <strong><em>concurrent collections</em></strong>*: CopyOnWriteArrayList*, <em>ConcurrentHashMap</em>,...</p>
</li>
</ul>
<p><strong>As a rule, you should do as little work as possible inside synchronized regions!</strong> If you must perform some time-consuming activity, find a way to move it out of the synchronized region.</p>
<p>If you are writing a mutable class, you have two options: you can omit all synchronization and <strong>allow the client to synchronize externally</strong> if concurrent use is desired, or you can <strong>synchronize internally</strong>, making the class thread-safe</p>
<h3 id="heading-c-prefer-executors-tasks-and-streams-to-threads">c. Prefer executors, tasks, and streams to threads</h3>
<p>Instead of creating and managing threads manually, you can create a <em>thread pool</em> with a fixed or variable number of threads. I prefer <strong>ThreadPoolExecutor</strong> or <strong>ThreadPoolTaskExecutor</strong> (in SpringBoot) for a heavily loaded production server.</p>
<h3 id="heading-d-prefer-concurrency-utilities-to-wait-and-notify">d. Prefer concurrency utilities to <em>wait</em> and <em>notify</em></h3>
<p>Instead of using <em>wait</em> and <em>notify</em>, you should use the higher-level concurrency utilities in <strong><em>java.util.concurrent</em></strong> package: <em>Executor</em>, <em>concurrent collections</em> and <em>synchronizers.</em></p>
<ul>
<li><p>use <strong>ConcurrentHashMap</strong> in preference to <strong>Collections.synchronizedMap</strong></p>
</li>
<li><p>For interval timing, use <strong>System.nanoTime</strong> rather than <strong>System.currentTimeMillis</strong></p>
<p>  (more accurate and more precise and is unaffected by adjustments to the system’s real-time clock)</p>
</li>
</ul>
<p>If you have to maintain legacy code that uses <em>wait</em> and <em>notify,</em> <strong>always use the <em>wait</em> loop idiom (inside a synchronized region) to invoke the <em>wait</em> method; never invoke it outside of a loop:</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679198057835/ca7cbf7e-a138-4d68-a2b0-41844f3a78f8.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-e-use-lazy-initialization-judiciously">e. Use lazy initialization judiciously</h3>
<p>The best advice for lazy initialization is <em>“don’t do it unless you need to”.</em> It decreases the cost of initializing a class or creating an instance, at the expense of increasing the cost of accessing the lazily initialized field.</p>
<p><strong>Under most circumstances, normal initialization is preferable to lazy initialization.</strong></p>
<p>If you must initialize a field lazily in order to achieve your performance goals or break a harmful initialization circularity:</p>
<ul>
<li><p>For instance fields, use <em>double-check idiom (singleton pattern)</em></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679200304576/e5e1971a-6acf-4f3f-ae2a-47366bcf2c15.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>For static fields, use <em>lazy initialization holder class idiom</em></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679200279727/e0f3dcad-986a-4e8d-8e93-21d9c087ebc3.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<h3 id="heading-f-dont-depend-on-the-thread-scheduler">f. Don't depend on the thread scheduler</h3>
<p>When many threads are runnable, the thread scheduler determines which ones get to run and for how long. Any reasonable operating system will try to make this determination fairly, but the policy can vary. Therefore, <strong>well-written programs shouldn’t depend on the details of this policy.</strong></p>
<p>The best way to write a robust, responsive, portable program is to ensure that the average number of runnable threads is not significantly greater than the number of processors. This leaves the thread scheduler with little choice: it simply runs the runnable threads till they’re no longer runnable. <strong>Note that the number of runnable threads isn’t the same as the total number of threads, which can be much higher. Threads that are <em>waiting are not runnable.</em></strong></p>
<p>In terms of the Executor Framework, this means <strong>sizing thread pools appropriately</strong> and keeping tasks short, but not <em>too</em> short, or dispatching overhead will harm performance.</p>
<hr />
<p>Phewww!!! I've just shared with you guys some important tips and tricks to work with Java efficiently. If you find it helpful, please share it with everyone to join hands in building a stronger tech community in Vietnam.</p>
<h1 id="heading-references">References</h1>
<ol>
<li><a target="_blank" href="https://www.amazon.com/Effective-Java-Joshua-Bloch/dp/0134685997"><strong>Effective Java</strong> 3rd Edition</a></li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Spring Boot Template Project Introduction]]></title><description><![CDATA[Whenever I need to implement a new feature, I typically start by researching available solutions on Google. Then I will experiment with one or more solutions to select the best one.
However, after several months, I might forget how to implement that ...]]></description><link>https://phamduyhieu.com/spring-boot-based-project-introduction</link><guid isPermaLink="true">https://phamduyhieu.com/spring-boot-based-project-introduction</guid><category><![CDATA[Springboot]]></category><category><![CDATA[Java]]></category><category><![CDATA[Spring]]></category><category><![CDATA[Redis]]></category><category><![CDATA[MySQL]]></category><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Sun, 12 Feb 2023 11:20:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1676201204995/9a2c1a69-25bb-473a-8ce8-2f4b2ac64fb1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Whenever I need to implement a new feature, I typically start by researching available solutions on Google. Then I will experiment with one or more solutions to select the best one.</p>
<p>However, after several months, I might <em>forget how to implement that feature</em>. Consequently, I end up having to <em>revisit internet resources, conduct research once again, and reattempt the implementation</em>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676107958936/3a05afc4-27cf-4fb5-a9bf-4f1f93580b11.png" alt class="image--center mx-auto" /></p>
<p>The above situation is very common, not just for me but also among my friends and colleagues. We waste a lot of time recalling and researching solutions - things could be synthesized in a template project for the next implementation.</p>
<p>So I have developed this project which includes <strong>implementations</strong> designed to assist both myself and other Spring Boot developers in seamlessly diving into coding. Each commit within the project represents the implementation of a specific technique.</p>
<p><strong><em>Link</em></strong>: <a target="_blank" href="https://github.com/hieubz/spring-boot-template-project"><em>https://github.com/hieubz/spring-boot-template-project</em></a></p>
<p><strong>Tech stack</strong>: Java 11, Spring Boot 2.7.x (upgraded to Java 17, Spring Boot 3.1.x)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677378359282/281d2ad4-85ee-4e72-bef9-4bf5ce869b62.png" alt class="image--center mx-auto" /></p>
<p>Every time I need to implement a feature in this list, I can search by feature keywords (<em>such as</em> <strong><em>Redis, retry, email,...</em></strong>) to find the corresponding commit, then apply the code of that commit for my feature. No need to search and remember boilerplate code anymore!</p>
<p><img src="https://github.com/hieubz/spring-boot-based-project/blob/main/src/main/resources/META-INF/feature_searching.png?raw=true" alt="feature_searching.png" /></p>
<p>We will have basic features here:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677378593141/c6ccd4f5-1f3b-46a7-8cfa-06acd22241ae.png" alt class="image--center mx-auto" /></p>
<p>or advanced things like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677378689217/3c093a83-e5be-4de6-9691-439fb5dd4aaf.png" alt class="image--center mx-auto" /></p>
<p>There are also modules related to Unit Test, Monitoring:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677378846201/980625d8-4561-4189-8c46-b08f1807b626.png" alt class="image--center mx-auto" /></p>
<p>I hope this project helps Spring Boot developers increase their productivity, allowing them to allocate more time to other important activities.</p>
<p>I plan to upgrade to <strong>Spring Boot 3</strong> and <strong>Java 17</strong> in the near future.</p>
<p>See yaaa!</p>
]]></content:encoded></item><item><title><![CDATA[Review sách Dev UP]]></title><description><![CDATA[Đây là một cuốn sách khá hay, toàn diện về nhiều khía cạnh trong đời sống lập trình viên. Tác giả là anh Nguyễn Hiển - một lập trình viên, nhà quản lý, lãnh đạo, tư vấn lâu năm. Nội dung được trình bày khá giản dị nhưng gần gũi, là đúc kết kinh nghiệ...]]></description><link>https://phamduyhieu.com/review-sach-dev-up</link><guid isPermaLink="true">https://phamduyhieu.com/review-sach-dev-up</guid><category><![CDATA[books]]></category><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Sun, 12 Feb 2023 11:17:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1668221453185/ydcBzKUZr.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Đây là một cuốn sách khá hay, toàn diện về nhiều khía cạnh trong đời sống lập trình viên. Tác giả là anh <a target="_blank" href="https://www.gurunh.com/">Nguyễn Hiển</a> - một lập trình viên, nhà quản lý, lãnh đạo, tư vấn lâu năm. Nội dung được trình bày khá giản dị nhưng gần gũi, là đúc kết kinh nghiệm nhiều năm của tác giả.</p>
<p>Cuốn sách được chia làm 5 phần: Những thế lưỡng nan, thử nghiệm, đánh giá, học tập, thực thi. Năm phần cũng chính là 5 bước trong mô hình vòng lặp <strong>DevUP</strong> mà tác giả đề xuất. Nói nôm na nó là việc bạn lựa chọn một việc gì đó, thử nghiệm và thực thi rồi rút ra bài học, sau đó cứ tiếp tục vòng lặp đó hàng ngày để ngày một tiến bộ.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668222709021/yS6ZDEZLf.png" alt="image.png" /></p>
<p><strong>Experiment - Valuation - Unlearn - Performance</strong> Vòng lặp 4 bước này sẽ giúp bạn liên tục phải vận động, học hỏi cái mới, rèn luyện kỹ năng, mở rộng các mối quan hệ với cộng đồng trong và ngoài ngành IT. Mỗi lần đi hết một cung tròn, chính là một lần LTV nâng cấp được trình độ, kỹ năng của mình. Nó có thể tốn 1 tháng, cũng có thể chỉ 1 tuần.</p>
<p>Bạn cũng sẽ biết cách đánh giá <strong>ROI - Return Of Investment</strong> mỗi khi đưa ra quyết định.</p>
<p><strong>VD</strong>: bạn đã có nền tảng Java 8 rồi thì giữa việc học thêm <strong>Java 11</strong> và học mới <strong>Golang</strong>, cái nào có <strong>ROI</strong> cao hơn? Cái đó tùy thuộc vào hoàn cảnh của bạn. Nếu công ty bạn chuộng Java và sắp tới có xu hướng sử dụng Java 11, thì đương nhiên việc học Java 11 có ROI cao hơn. Nhưng nếu bạn có mong muốn chuyển sang môi trường mới và <strong>Go</strong> là ngôn ngữ được chuộng ở các công ty đó, thì đầu tư vào <strong>Go</strong> ở thời điểm hiện tại là một lựa chọn đúng đắn. Còn nếu bạn thấy Return từ 2 việc trên là như nhau, bạn nên học Java 11 vì đơn giản Investment cho việc học Java 11 ít hơn, do đó ROI tốt hơn.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668223868040/rPFifSfOh.png" alt="image.png" /></p>
<p>Và một điều nữa là một chuyên môn giỏi phải đi kèm với khả năng nhìn toàn cảnh thì mới mang lại kết quả. Nếu không, có thể một phần mềm hoàn hảo được sinh ra nhưng không có người dùng.</p>
<p>Trên đây là một vài nhận xét về cuốn sách. Giờ là tới chi tiết từng phần mà mình tóm tắt lại theo ý hiểu của mình, sau còn đọc lại.</p>
<h1 id="heading-i-hieu-nhung-the-luong-nan">I. Hiểu những thế lưỡng nan</h1>
<p>Cuộc sống luôn đi kèm với những hoàn cảnh éo le, không rõ trắng đen, đòi hỏi bạn phải ra quyết định. Đúng hay sai à? còn tùy vào góc nhìn.</p>
<p>Bản thân mình cũng từng đứng trước nhiều ngã ba đường: đi làm Dev hay BA, đi hát mỗi tối kiếm tiền, vui nhưng bấp bênh hay theo ngành IT đã chọn.</p>
<p>Đấy là đối với định hướng nghề nghiệp. Còn chỉ riêng trong ngành IT cũng có hàng chục thế lưỡng nan được tác giả đưa ra đánh giá.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668252696739/yucoMKz6z.jpg" alt="p1.jpg" /></p>
<p>Chung quy lại, đứng trước những lựa chọn, tác giả khuyên các LTV nên cân nhắc được-mất trong dài hạn thay vì nhìn vào những thứ trước mắt như lương bổng hay vì <strong>name</strong> của một công ty. Làm việc ở nước ngoài về lâu dài chưa hẳn đã phải là tốt, hay ở lại trong nước cũng không hẳn là tụt hậu. Tác giả đã chỉ ra ưu/nhược điểm của từng lựa chọn, cho chúng ta cái nhìn từng trải của một người lâu năm trong nghề.</p>
<p>Đi hay ở, tập đoàn lớn hay startup, đi sâu hay đi rộng, lương tăng bao nhiêu là đủ,... tùy ở việc bạn muốn gì, muốn đạt được gì trong 5-10 năm tới. Mục tiêu dài hạn sẽ ảnh hưởng tới những quyết định của bạn trong hiện tại.</p>
<pre><code class="lang-plaintext">An "easy" short-term decision may introduce long-term problems

- Noam Wasserman -
</code></pre>
<h1 id="heading-ii-thu-nghiem">II. Thử Nghiệm</h1>
<p>Khi đã ở trong thế lưỡng nan, LTV chỉ còn cách lựa chọn theo những gì linh tính mách bảo (cái này là tôi thêm vào :D). Vì nếu cứ phân vân thì cũng vấn đề cứ nằm đó. Chi bằng ta cứ chọn và thử nghiệm.</p>
<p>Hãy thử nghiệm một <em>thiết kế</em>, <em>công cụ</em>, hay <em>công nghệ</em> trong những <em>pet project</em> của riêng mình. Khi tầm ảnh hưởng của bạn trong tổ chức tăng lên, hãy mạnh dạn đề xuất những kết quả từ những thử nghiệm cá nhân.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668252736136/PyjdnDw4s.jpg" alt="p2.jpg" /></p>
<p>Theo kinh nghiệm của tôi, bạn sẽ không thể trải nghiệm đủ những <em>công nghệ</em>, <em>dự án</em>, <em>domain</em> mà bạn muốn nếu chỉ làm những gì được giao. Hãy mạnh dạn xin chuyển team nếu thực sự muốn trải nghiệm ở vị trí khác. Và chăm chỉ thử nghiệm trong những <em>pet project</em> của bạn.</p>
<h1 id="heading-iii-danh-gia">III. Đánh giá</h1>
<p>Sau khi đã thử nghiệm thì cũng phải đánh giá kết quả chứ nhỉ: đúng hay sai, mình đang đứng ở đâu, học được điều gì? Và sau những thử nghiệm và đánh giá đó, con đường của bạn ngày càng rõ ràng, hoặc chí ít bạn cũng đã có thêm dữ kiện cho những quyết định sắp tới.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668252748399/AvE_OfPcB.jpg" alt="p3.jpg" /></p>
<p>Đánh giá xem mình đang Junior hay Senior, lựa chọn nào có ROI tốt hơn, góc nhìn của mình đã toàn cảnh chưa, phản hồi từ đồng nghiệp hay cấp trên như thế nào?</p>
<h1 id="heading-iv-hoc-tap">IV. Học tập</h1>
<p>Sau khi đã biết mình đang ở đâu, còn thiếu gì, thì là lúc bạn cần bổ sung kiến thức, kỹ năng còn thiếu hoặc chưa hoàn chỉnh. Học tập cũng có nghĩa là sắp đặt, cấu trúc lại hệ thống kiến thức đã có nhằm tiếp thu những kiến thức mới. Nôm na là <strong><em>unlearn</em></strong>, xem lại những gì mình đã học và từ bỏ nếu chúng không còn đúng đắn.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668252768703/kkym_WXcN.jpg" alt="p4.jpg" /></p>
<p>Tác giả đã đưa ra ý kiến về những điều tưởng chừng như là chân lý, thường như cơm bữa đối với LTV. Từ chuyện tỏ ra <em>lập dị</em>, <em>hay trễ hẹn</em>, tâm lý <em>kiểu gì cũng có bug</em>, tư tưởng đòi hỏi <em>yêu cầu hay quy trình phải rõ ràng</em>,... cho tới tư tưởng <em>LTV chỉ làm tới 40 tuổi</em>. Những lối suy nghĩ này tưởng như là bình thường nhưng lại trở nên bất thường hoặc sai trong thời điểm hiện tại.</p>
<p>Ngay bản thân mình cũng đã từng nghĩ như vậy khi còn đi học. Cho tới khi đi làm, gặp nhiều người anh/chị rất giỏi trong nghề, mình mới thấy những điều nhiều LTV hay chẹp miệng cho qua hay coi là hiển nhiên đó thực chất đang khiến họ trở nên xuề xòa, dễ dãi, thiếu chuyên nghiệp, và xa hơn là bị tụt lại phía sau.</p>
<p>Đừng cố bám vào những điều xưa cũ. Hãy học cách thử thách mọi thứ, từ <em>phong cách code</em>, <em>công nghệ</em>, <em>quy trình</em>, thậm chí, đến cách thức xây dựng hệ thống phần mềm.</p>
<h1 id="heading-v-thuc-thi">V. Thực thi</h1>
<p><strong><em>Có làm thì mới có ăn, không làm mà đòi có ăn thì ...</em></strong></p>
<p>Đấy, học chán r thì phải thực hành, hành động hàng ngày một cách đúng đắn. Đó chính là lúc LTV chuyển hóa những thử nghiệm thành một tư duy, kỹ năng bền vững của bản thân, thậm chí như một thói quen hay phản xạ vô điều kiện.</p>
<p>Và giá trị của một LTV sau cùng sẽ được đo đếm bằng giá trị kết quả mà anh ta mang lại trong công việc, cho tổ chức, cho cộng đồng.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668252787336/lz2VF4wGd.jpg" alt="IMG20221112180516.jpg" /></p>
<p>Do vậy, ngoài việc thực thi công việc, LTV còn phải cải thiện những kỹ năng cơ bản nhưng cực kỳ quan trọng khi làm việc trong một tổ chức như <em>problem solving</em>, <em>quản lý công việc</em>, <em>giao tiếp/cộng tác với đồng nghiệp</em>, hay chỉ đơn giản ở việc biết <em>say no</em>.</p>
<p>Cuối cùng, không ai phát triển được chuyên môn nếu tách mình ra khỏi cộng đồng chuyên môn. Tham gia và đóng góp vào cộng đồng chuyên môn nên là ưu tiên quan trọng của LTV. Hãy theo dõi và học hỏi những LTV giàu kinh nghiệm. Hãy chủ động chia sẻ kiến thức, kinh nghiệm của mình với cộng đồng, qua đó giúp ích cho những người khác và bạn cũng sẽ nhận được những phản biện của những LTV khác để hoàn thiện mình.</p>
<hr />
<p>Đó là <em>đôi dòng</em> những gì mình nhận xét và tóm tắt lại từ cuốn <strong>Dev UP</strong>. Nhiều kiến thức lắm, không nhớ hết được, nên chắc thỉnh thoảng phải đọc lại. Ae nào chưa đọc thì lên <a target="_blank" href="https://tiki.vn/sach-devup-p76531748.html">Tiki</a> mà đặt về nhé. Bổ ích lắm :D</p>
<p>Thôi nay thế thôi nhé, tôi đi chạy bộ đã =)))</p>
<p><em>-- Hanoi 12/11/2022 18h23 --</em></p>
]]></content:encoded></item><item><title><![CDATA[High Performance in MySQL - Part 2]]></title><description><![CDATA[Today I will continue to share my note about 3 topics: Replication, Table partitioning, and Scaling with MySQL.
You could read Part 1 here: High Performance in MySQL - Part 1
Notes: if you have read High Performance in MySQL book, you could realize t...]]></description><link>https://phamduyhieu.com/high-performance-in-mysql-part-2</link><guid isPermaLink="true">https://phamduyhieu.com/high-performance-in-mysql-part-2</guid><category><![CDATA[MySQL]]></category><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Sun, 12 Feb 2023 11:04:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1668316977224/tIB687BA0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today I will continue to share my note about 3 topics: <strong>Replication, Table partitioning,</strong> and <strong>Scaling</strong> with MySQL.</p>
<p>You could read Part 1 here: <a target="_blank" href="https://phamduyhieu.com/high-performance-in-mysql-part-1">High Performance in MySQL - Part 1</a></p>
<p>Notes: if you have read <strong>High Performance in MySQL</strong> book, you could realize that my series is only a note I rewrite from this book. My main goal is that I won't forget what I've learned, and can look it up online whenever I need it.</p>
<h1 id="heading-i-replication">I. Replication</h1>
<p>Replication lets you configure one or more servers as replicas of a master server, keeping their data synchronized with the source copy.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676193294341/ebba3a21-31a0-4edb-8d2f-4716fe4816c9.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-how-replication-works">How Replication works</h3>
<p>At a high level, replication is a simple three-part process:</p>
<ol>
<li><p>The source records changes to its data in its binary log as “<strong>binary log events</strong>.”</p>
</li>
<li><p>The replica copies the source’s binary log events to its local relay <strong>log</strong>.</p>
</li>
<li><p>The replica replays the events in the <strong>relay log</strong>, applying the changes to its own data.</p>
</li>
</ol>
<h3 id="heading-benefits">Benefits</h3>
<ul>
<li><p><strong>Data distribution</strong>: useful for maintaining a copy of your data in a geographically distant location, such as a different data center or cloud region</p>
</li>
<li><p><strong>Scaling read traffic:</strong> distribute read queries across several servers, which works very well for read-intensive applications (need to setup LB)</p>
</li>
<li><p><strong>Backups:</strong> a valuable technique for helping with backups. However, a replica is neither a backup nor a substitute for backups.</p>
</li>
<li><p><strong>Analytics and Reporting:</strong> Using a dedicated replica for reporting/analytics (online analytical processing, or OLAP) queries</p>
</li>
<li><p><strong>High availability and failover:</strong> avoid making MySQL a single point of failure in your application</p>
</li>
<li><p><strong>Testing MySQL upgrades:</strong> common practice to set up a replica with an upgraded MySQL version and use it to ensure that your queries work as expected before upgrading every instance.</p>
</li>
</ul>
<h2 id="heading-replication-problems-and-solutions">Replication Problems and Solutions</h2>
<ul>
<li><p><strong>Binary Logs Corrupted on the Source</strong>: rebuild your replicas</p>
</li>
<li><p><strong>Non-unique Server IDs</strong>: accidentally configure two replicas with the same server ID =&gt; be careful when setting up your replicas</p>
</li>
<li><p><strong>Undefined Server IDs</strong>: will not let you start the replica</p>
</li>
<li><p><strong>Missing Temporary Tables</strong>: use row-based replication <strong>|</strong> name your temporary tables consistently (prefix with <strong><em>temporary_</em></strong>, for example) and use replication rules to skip replicating them entirely</p>
</li>
<li><p><strong>Not Replicating All Updates</strong>: misuse <strong>SET</strong> <strong>SQL_LOG_BIN =</strong> <strong>0</strong> or don’t understand the replication filtering rules, your replica might not execute some updates that have taken place on the source</p>
</li>
<li><p><strong>Replication Lag</strong>:</p>
<ul>
<li><p><strong>Multithreaded</strong> replication</p>
</li>
<li><p>Use <strong>sharding</strong>: scale reads with replicas, scale writes with sharding</p>
</li>
<li><p>Turn <strong>off</strong> <strong>sync bin log</strong> on replicas (when sharding is not a viable option because of effort or design issues)</p>
</li>
</ul>
</li>
</ul>
<p><strong><mark>Keep it simple. Don’t do anything fancy, such as using replication rings or replication filters, unless you really need to.</mark></strong></p>
<h1 id="heading-ii-table-partitioning">II. Table Partitioning</h1>
<p>Table Partitioning is the way a MySQL database splits its actual data down into separate tables, but still gets treated as a single table by the SQL layer</p>
<h3 id="heading-partitioning-rules">Partitioning Rules</h3>
<ul>
<li><strong><mark>must add the partition key into the primary key</mark></strong></li>
</ul>
<p>Ex: the primary key must include <strong><em>“created”</em></strong> <em>column</em></p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> userslogs (
    username <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    logdata <span class="hljs-built_in">BLOB</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    created DATETIME <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    PRIMARY <span class="hljs-keyword">KEY</span>(username, created)
)
<span class="hljs-keyword">PARTITION</span> <span class="hljs-keyword">BY</span> <span class="hljs-keyword">RANGE</span>( <span class="hljs-keyword">YEAR</span>(created) )(
    <span class="hljs-keyword">PARTITION</span> from_2013_or_less <span class="hljs-keyword">VALUES</span> <span class="hljs-keyword">LESS</span> <span class="hljs-keyword">THAN</span> (<span class="hljs-number">2014</span>),
    <span class="hljs-keyword">PARTITION</span> from_2014 <span class="hljs-keyword">VALUES</span> <span class="hljs-keyword">LESS</span> <span class="hljs-keyword">THAN</span> (<span class="hljs-number">2015</span>),
    <span class="hljs-keyword">PARTITION</span> from_2015 <span class="hljs-keyword">VALUES</span> <span class="hljs-keyword">LESS</span> <span class="hljs-keyword">THAN</span> (<span class="hljs-number">2016</span>),
    <span class="hljs-keyword">PARTITION</span> from_2016_and_up <span class="hljs-keyword">VALUES</span> <span class="hljs-keyword">LESS</span> <span class="hljs-keyword">THAN</span> MAXVALUE
</code></pre>
<ul>
<li><p>the table itself becomes a virtual concept. The partitions hold the data and any indexes are built on the data in the partitions.</p>
</li>
<li><p>MySQL supports horizontal partitioning but <strong>not vertical</strong></p>
</li>
<li><p><strong>Partition types:</strong></p>
<ul>
<li><p><strong>Range:</strong> it is great because you have groups of known IDs in each table, and it helps range queries.</p>
</li>
<li><p><strong>Hash:</strong> “<em>load balances</em>” the table, and allows you to write to partitions more concurrently. This <strong>makes range queries on the partition key a bad idea.</strong></p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-benefits-1">Benefits</h3>
<ul>
<li><p><strong>Deletion</strong>: quickly delete data that is no longer needed</p>
</li>
<li><p><strong>Storage</strong>: possible to store more data in one table than can be held on a single disk or file system partition</p>
</li>
<li><p><strong>Performance</strong>: Query data faster when only accessing a smaller volume of data (could apply partition pruning)</p>
</li>
</ul>
<h1 id="heading-iii-scaling-mysql">III. Scaling MySQL</h1>
<p><strong>Scaling is the system’s ability to support growing traffic</strong></p>
<h3 id="heading-read-bound-workloads">Read-Bound Workloads</h3>
<p>When adding more application nodes to scale the clients serving requests leads to some database issues:</p>
<ul>
<li><p><strong>High CPU</strong>: means the server is spending all of its time processing queries. The higher CPU utilization gets, the more latency you will see in queries.</p>
</li>
<li><p><strong>Heavy disk read IOPS or throughput</strong>: indicating that you are going to disk very often or for large numbers of rows read from disk</p>
</li>
</ul>
<p>\==&gt; adding indexes, optimizing queries, and caching data you can cache</p>
<h3 id="heading-write-bound-workloads">Write-Bound Workloads</h3>
<p>There are some examples of write-bound workloads:</p>
<ul>
<li><p>Peak e-commerce season and sales are growing, along with the number of orders to track.</p>
</li>
<li><p>Signups are growing exponentially <em>(Ex: ChatGPT reaches 100 million users 2 months after launch)</em></p>
</li>
</ul>
<p>All of these are business use cases that lead to exponentially more database writes that you now have to scale.</p>
<p>\==&gt; scale up (add more RAM, CPU and disk) or scale out (functional sharding)</p>
<h2 id="heading-1scaling-read">1.Scaling Read</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676196698510/4a355f33-1110-434c-874b-270a92937aae.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Use <strong>Replica Read Pools</strong></p>
</li>
<li><p>A very common way to manage these read pools is to use a <strong>load balancer</strong> (HAProxy, Nginx) to run a <strong>virtual IP</strong> that acts as an intermediary for all traffic meant to go to the read replicas</p>
</li>
</ul>
<h2 id="heading-2scaling-write-with-sharding">2.Scaling Write with Sharding</h2>
<ul>
<li><p><strong>Sharding</strong> means splitting your data into different, smaller database clusters so that you can execute more writes on more source hosts at the same time.</p>
</li>
<li><p>Do not split based on the structure of the engineering team. That will always change at some point. Do split tables based on <strong>business function</strong></p>
</li>
<li><p>Most applications <strong><em>shard only the data that needs sharding</em></strong>—typically, the parts of the data set that will grow very large. And not just the data that is growing rapidly but also the data that logically belongs with it and will regularly be queried at the same time (<strong>partitioning</strong>)</p>
</li>
<li><p>Do not shy away from tackling spots where separate business concerns have been intermingled in the data and you need to advocate for not just data separation but also application refactoring and introducing <strong>API access across those boundaries</strong>.</p>
</li>
</ul>
<h3 id="heading-choosing-a-partitioning-scheme">Choosing a Partitioning Scheme</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676199391019/ea609109-04b5-4f00-814b-59960f7979b4.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>A good partitioning key is usually the primary key of a <strong><em>very important entity</em></strong> in the database. These keys determine the unit of sharding. For example, if you partition your data by a <strong>user ID</strong> or a <strong>client ID</strong>, the unit of sharding is the <strong>user</strong> or <strong>client</strong>.</p>
</li>
<li><p>Diagram your data model with an <strong>entity-relationship diagram</strong> or an equivalent tool that shows all the entities and their relationships. Try to lay out the diagram so that the related entities are close together.</p>
</li>
<li><p>Consider your application’s queries as well. Even if two entities are related in some way, if you seldom or never join on the relationship, you can break the relationship to implement the sharding.</p>
</li>
<li><p>Choosing a partitioning key that lets you <strong>avoid cross-shard queries</strong> as much as possible but also makes shards small enough that you won’t have problems with disproportionately large chunks of data</p>
</li>
</ul>
<h3 id="heading-querying-across-shards">Querying across Shards</h3>
<ul>
<li><p>Most sharded applications have at least some queries that need to aggregate or join data from multiple shards (for reports)</p>
</li>
<li><p>Strive to make your queries as simple as possible and contained within one shard.</p>
</li>
<li><p>For those cases where some cross-shard aggregation is needed, we recommend you <strong>make that part of the application logic</strong>.</p>
</li>
<li><p>Cross-shard queries can also benefit from <strong>summary tables</strong>. You can build them by traversing all the shards and <strong>storing the results redundantly</strong> on each shard when they’re complete. If duplicating the data on each shard is too wasteful, you can consolidate the summary tables onto another data store so they’re stored only once.</p>
</li>
</ul>
<h1 id="heading-iv-summary">IV. Summary</h1>
<p>Optimizing and scaling MySQL is a journey. Before you dive into scalability bottlenecks, make sure you’ve optimized your queries, checked your indexes, and have a solid configuration for MySQL.</p>
<p>Once optimized, focus on determining whether you are <strong>read-bound</strong> or <strong>write-bound</strong>, and then consider what strategies work best to solve any immediate issues.</p>
<p>For <strong>read-bound</strong> workloads, our recommendation is to move to <strong>read pools</strong> unless replication lag is an impossible problem to overcome. If <strong>lag</strong> is an issue or if your problem is <strong>write-bound</strong>, you need to consider <strong>sharding</strong> as your next step.</p>
<p>That's all about MySQL I know so far. I hope it could help you to consolidate your knowledge and give you some ideas to optimize your MySQL.</p>
]]></content:encoded></item><item><title><![CDATA[High Performance in MySQL  - Part 1]]></title><description><![CDATA[MySQL is an open-source relational database management system and is one of the most common databases. Everyone uses MySQL and me too. But whether we are using it correctly and optimally.
Today I will share my experience and what I learned in 3 main ...]]></description><link>https://phamduyhieu.com/high-performance-in-mysql-part-1</link><guid isPermaLink="true">https://phamduyhieu.com/high-performance-in-mysql-part-1</guid><category><![CDATA[MySQL]]></category><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Thu, 03 Nov 2022 07:37:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1667460721696/rMqietHyz.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>MySQL is an open-source relational database management system and is one of the most common databases. Everyone uses MySQL and me too. But whether we are using it correctly and optimally.</p>
<p>Today I will share my experience and what I learned in 3 main topics: <strong>Schema Design</strong>, <strong>Indexing </strong> and <strong>Query Optimization</strong>.</p>
<p>But before we dig dive into them, we should understand MySQL's logical architecture. In other words, we should understand how MySQL processes our queries.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667458496431/9csU6l2JT.png" alt="image.png" /></p>
<p>When we send a query to MySQL:</p>
<ul>
<li>MySQL will check and open connection (reject if too many connections)</li>
<li><strong>Parser</strong> will parse the query to check the syntax</li>
<li><strong>Optimizer</strong> will optimize the query (based on <strong>Performance Schema</strong>)</li>
<li>Run the optimized query</li>
</ul>
<p>And you see, MySQL will optimize our queries depending on metrics in the Performance Schema before running them. So which data types we use, how we design our tables, how we do the indexing and how we write the queries, will determine the performance of our database. It's hard to read and remember all knowledge so I write it as a quick note with multiple points. Anw, let's start!</p>
<h1 id="heading-i-schema-design">I. Schema Design</h1>
<h2 id="heading-1-data-types">1. Data Types</h2>
<p>Using optimal data types not only reduces the storage space but also improves the query performance (because query data will be loaded onto RAM =&gt; if RAM is full, data will be flushed to disk =&gt; poor performance)</p>
<ul>
<li>Smaller is usually better</li>
<li>Simple is good (e.g, use <strong>decimal</strong> rather than <strong>string</strong> for lat/long values)</li>
<li>Avoid <strong>null</strong> if possible: harder for MySQL to optimize queries</li>
</ul>
<p>Let's check the data types MySQL has and discuss when we should use them:</p>
<ul>
<li><p><strong>Varchar</strong>: variable length</p>
<ul>
<li><p>use 1 or 2 extra bytes to store length, 1 byte if the value requires no more than 255 bytes, and 2 bytes if it’s more</p>
<p>Ex: varchar(10) will use up to 11 bytes, varchar(500) will use up to 502 bytes</p>
</li>
<li>Should use varchar(255) to maximize the use of a column because it needs only 1 extra byte for length.</li>
</ul>
</li>
<li><strong>Char</strong>: fixed length of characters =&gt; good choice for storing hashed user password</li>
<li><strong>Text</strong>: string data types designed to store large amounts of data, cannot index full length. It will be stored off the table when the value is greater than 8kb and needs to be read from the disk when querying.</li>
<li><strong>Blob</strong>: store binary data (images, videos,...) =&gt; in practice, we should save images and videos in other storage space and store image paths in MySQL (avoid full RAM)</li>
<li><strong>Integer</strong>: tinyint 1 byte, small int 2 bytes, int 4 bytes, bigint 8 bytes
=&gt; the width for integer types such as int(11) which is meaningless for most applications because it does not restrict the range of values</li>
<li><strong>Real number</strong>: Float 4 bytes, Double 8 bytes. Double has greater precision than Float</li>
<li><strong>Datetime</strong>: 1000 - 9999, 8 bytes</li>
<li><strong>Timestamp</strong>: 4 bytes, range 1970-2038, timestamp values will be converted from the current time zone to UTC for storage, and converted back from UTC to the current time zone for retrieval</li>
<li><strong>Decimal</strong>: store numbers with fractional part (e.g, financial data)</li>
<li><strong>Enum</strong>: cannot update value orders in enum, will be stored as int (should use <strong>tinyint</strong> instead so that you do not need to alter)</li>
</ul>
<p>Notes: with varchar, text type, we should create a prefixed index if needed.</p>
<h2 id="heading-2-schema-design-mistakes">2. Schema Design Mistakes</h2>
<ul>
<li>Too many columns: heavy bin log could lead to replication lag, poor performance when pulling data onto memory for read/join queries,...</li>
<li>Too many joins: should join on 3 tables at most (harder for query optimization)</li>
<li>Should not use <strong>null</strong></li>
</ul>
<h1 id="heading-ii-indexing">II. Indexing</h1>
<p>The index is a data structure that storage engines use to find rows quickly. Index performance can drop very quickly when our dataset grows.</p>
<h2 id="heading-1-types-of-indexes">1. Types of Indexes</h2>
<h3 id="heading-a-b-tree-indexes">a. B-tree indexes</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667383713889/ycwTDJqi5.png" alt="image.png" /></p>
<ul>
<li>A data structure that store data in its node in sorted order</li>
<li>Leaf pages contain a link to the next for fast range traversals through nodes (has order)</li>
<li>Leaf pages have pointers to the indexed data</li>
<li>Storage engine does not have to scan the whole table to find the desired data</li>
</ul>
<h4 id="heading-advantages">Advantages</h4>
<ul>
<li>B-trees store indexed columns in order =&gt; useful for range searching</li>
<li>Work well for lookups by the full key value, a key range, a key prefix</li>
<li>Store replated values close together</li>
<li>Index stores a copy of values =&gt; some queries can be satisfied from the index alone (covering index)</li>
</ul>
<p>=&gt; Index reduces the amount of data the server has to examine</p>
<p> =&gt; Index helps the server avoid sorting and temporary tables</p>
<h4 id="heading-limitation">Limitation</h4>
<ul>
<li>Can’t skip columns in the index</li>
<li><p>Can’t optimize accesses with any columns to the right of the first range condition</p>
<pre><code>VD: where last_name = “Smith” and first_name like ‘J%’ and dob = …. 

Because the LIKE is a range condition so MySQL cannot apply index <span class="hljs-keyword">for</span> **dob** column searching.
</code></pre></li>
</ul>
<h4 id="heading-btree-works-with-the-following-kinds-of-queries">Btree works with the following kinds of queries:</h4>
<ul>
<li>Match on the full key value specifies values for all columns in the index</li>
<li>Match a <strong>leftmost</strong> prefix: uses only the first column in the index</li>
<li>Match a column prefix: uses only the first column in the index.</li>
<li>Match one part exactly and match a range on another part</li>
<li>Index-only queries: access only the index, not the row storage</li>
</ul>
<h3 id="heading-b-hash-indexes">b. Hash indexes</h3>
<p>Hash indexes use hash tables to store data and have somewhat different characteristics from those just discussed:</p>
<ul>
<li><p>They are used only for equality comparisons that use the = or != operators (but are very fast). They are not used for comparison operators such as &lt; that find a range of values. Systems that rely on this type of single-value lookup are known as “key-value stores”; to use MySQL for such applications, use hash indexes wherever possible.</p>
</li>
<li><p>The optimizer cannot use a hash index to speed up ORDER BY operations. (This type of index cannot be used to search for the next entry in order.)</p>
</li>
<li><p>MySQL cannot determine approximately how many rows there are between two values (this is used by the range optimizer to decide which index to use).</p>
</li>
<li><p>Only whole keys can be used to search for a row. (With a B-tree index, any leftmost prefix of the key can be used to find rows.)</p>
</li>
</ul>
<h3 id="heading-c-adaptive-hash-indexes">c. Adaptive Hash indexes</h3>
<p>The <strong>InnoDB</strong> storage engine has a special feature called adaptive hash indexes. When <strong>InnoDB</strong> notices that some index values are being accessed very frequently, it builds a hash index for them in memory on top of B-tree indexes. This gives its B-tree indexes some properties of hash indexes, such as very fast hashed lookups. This process is completely automatic, and you can’t control or configure it, although you can disable the adaptive hash index altogether.</p>
<h2 id="heading-2-indexing-strategies">2. Indexing Strategies</h2>
<h3 id="heading-a-prefix">a. Prefix</h3>
<ul>
<li>Selectivity: ratio of the number of distinctly indexed values to the total number of rows in the table =&gt; higher is better</li>
<li>With varchar /Text column: must define prefix indexes =&gt; long enough to give good selectivity and short enough to save space</li>
<li>Cannot use prefix indexes for ORDER BY or GROUP BY queries, nor can it use them as covering indexes </li>
</ul>
<h3 id="heading-b-multicolumn-indexes">b. MultiColumn indexes</h3>
<ul>
<li>You need a single index with all relevant columns (AND), not multiple indexes that have to be combined</li>
<li>OR condition: sometimes use lots of CPU and memory resources to merge</li>
<li>Choose the most selective columns first in the index (examine the distribution of values in the table, count distinct / count *)</li>
</ul>
<h3 id="heading-c-clustered-indexes">c. Clustered Indexes</h3>
<ul>
<li>Store the Btree index and the rows together in the same structure</li>
<li>When a table has a clustered index, its rows are actually stored in the index’s leaf pages</li>
</ul>
<h3 id="heading-d-secondary-indexes">d. Secondary Indexes</h3>
<ul>
<li>Secondary index accesses require two index lookups instead of one </li>
<li>A leaf node doesn’t store a pointer to the referenced row’s physical location; rather, it stores the row’s primary key values</li>
<li>To find a row from a secondary index, the storage engine first finds the leaf node in the secondary index and then uses the primary key values stored there to navigate the primary key and find the row (traverse two Btrees)</li>
</ul>
<h3 id="heading-e-covering-indexes">e. Covering Indexes</h3>
<ul>
<li>An index that contains all data needed for a query is called a covering index</li>
<li>Databases do not need to access the filesystem</li>
</ul>
<h1 id="heading-iii-query-optimization">III. Query Optimization</h1>
<h2 id="heading-1-optimize-data-access">1. Optimize Data Access</h2>
<h3 id="heading-a-are-you-asking-the-database-for-data-you-dont-need">a. Are You Asking the Database for Data You Don’t Need?</h3>
<p>You should find out whether your application is retrieving more data than you need</p>
<ul>
<li>Fetching more rows than needed =&gt; need <strong>limit</strong></li>
<li>Fetching all columns from a multi-table join =&gt; define what columns you need</li>
<li>Fetching all columns=&gt; cannot use covering indexes, add more IO, memory <ul>
<li>Avoid using <strong>select * from</strong></li>
<li>But in some cases, we should query full objects, cache them, and use them many times could increase performance</li>
</ul>
</li>
<li>Fetching the same data repeatedly =&gt; <strong>caching</strong></li>
</ul>
<h3 id="heading-b-is-mysql-examining-too-much-data">b. Is MySQL Examining Too Much Data?</h3>
<p>In MySQL, the simplest query cost metrics are:</p>
<ul>
<li>Response time: Service time + Queue time</li>
<li>Number of rows examined</li>
<li>Number of rows returned</li>
</ul>
<p>Ideally, the number of rows examined would be the same as the number returned (100%). To reduce the number of examined rows:</p>
<ul>
<li>Use covering indexes: no need to retrieve rows from tables</li>
<li>Change the schema, using summary tables (prepare summary/report tables in advance)</li>
<li>Rewrite a complicated query so the MySQL optimizer is able to execute it optimally</li>
</ul>
<h2 id="heading-2-ways-to-restructure-queries">2. Ways to Restructure Queries</h2>
<h3 id="heading-a-complex-queries-versus-many-queries">a. Complex Queries Versus Many Queries</h3>
<p>The traditional approach to database design emphasizes doing as much work as possible with as few queries as possible. This approach was historically better because of the cost of network communication and the overhead of the query parsing and optimization stages.</p>
<p>However, this advice doesn’t apply as much to MySQL because it was designed to
handle connecting and disconnecting very efficiently and to respond to small, simple queries very quickly. Modern networks are also significantly faster than they used to
be, reducing network latency. So <strong>running multiple queries isn’t necessarily such a bad thing</strong>.</p>
<p>It’s still a good idea to use as few queries as possible, but sometimes you can make a query more efficient by decomposing it and executing a few simple queries instead of one complex one.</p>
<h3 id="heading-b-chopping-up-a-query">b. Chopping up a query</h3>
<ul>
<li><p>Need to delete old data =&gt; chop up a DELETE statement and run sequentially</p>
<pre><code> E.g: DELETE FROM messages WHERE created &lt; DATE_SUB(NOW(),INTERVAL <span class="hljs-number">3</span> MONTH);

    =&gt; we will limit the number <span class="hljs-keyword">of</span> affected rows:

 DELETE FROM messages WHERE created &lt; DATE_SUB(NOW(),INTERVAL <span class="hljs-number">3</span>    MONTH) LIMIT <span class="hljs-number">10000</span>
</code></pre></li>
</ul>
<p>=&gt; minimize the impact on the server (smaller transactions), reduce replication lag</p>
<p>=&gt; it might be a good idea to add some sleep time between DELETE statements to reduce the load on servers.</p>
<h3 id="heading-c-join-decomposition">c. Join Decomposition</h3>
<ul>
<li>MySQL can run well over 100000 simple queries per second</li>
<li>Moderns networks are also significantly faster than they used to be</li>
</ul>
<p>=&gt; sometimes you can make a query more efficient by decomposing it and executing a few simple queries instead of one complex one.</p>
<h4 id="heading-advantages">Advantages</h4>
<ul>
<li>Caching can be more efficient</li>
<li>Reduce lock contention</li>
<li>Doing joins in the application makes it easier to scale the database by placing tables on different servers (because we do not need to join)</li>
<li>The queries themselves can be more efficient (such as using an <strong>IN()</strong> instead of a <strong>join</strong> lets MySQL retrieve rows more optimally)</li>
<li>You can reduce redundant row accesses. Doing a join in the application means you retrieve each row only once, whereas a join in the query is essentially a denormalization that might repeatedly access the same data</li>
</ul>
<h4 id="heading-disadvantages">Disadvantages</h4>
<ul>
<li>Need to perform the join in the application</li>
<li>Require a certain level of your team</li>
</ul>
<h1 id="heading-iv-conclusion">IV. Conclusion</h1>
<p>Phewww, we've just discussed about 3 main and most important topics in MySQL. I can not show all my experience and knowledge about MySQL in one post, so this post is like a note for me or anyone else to review and recall tips and strategies to improve MySQL performance. </p>
<p>In the next post, we will discuss <strong>Replication</strong> and <strong>Scaling</strong> techniques in MySQL. I will share how I scaled my database and improved read/write performance.</p>
<p>See you next time!</p>
<h1 id="heading-references">References</h1>
<ol>
<li><a target="_blank" href="https://www.oreilly.com/library/view/high-performance-mysql/9781492080503/">High Performance MySQL: Optimization, Backups, and Replication</a></li>
<li><a target="_blank" href="https://dev.mysql.com/doc/refman/8.0">MySQL 8.0 Documentation</a> </li>
</ol>
]]></content:encoded></item><item><title><![CDATA[LFU cache and Java implementation]]></title><description><![CDATA[I found this one on VOZ forum when a member shared about Shopee coding interview. And this is one of the most interesting problems on Leetcode in my opinion. I need to combine both fancy data structures HashMap and LinkedList in my solution. Today, t...]]></description><link>https://phamduyhieu.com/lfu-cache-and-java-implementation</link><guid isPermaLink="true">https://phamduyhieu.com/lfu-cache-and-java-implementation</guid><category><![CDATA[LFU cache]]></category><category><![CDATA[Java]]></category><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Sat, 01 Oct 2022 09:37:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1664616788534/qwD2j7N2E.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I found this one on <a href="https://voz.vn/">VOZ forum</a> when a member shared about Shopee coding interview. And this is one of the most interesting problems on Leetcode in my opinion. I need to combine both fancy data structures <strong>HashMap</strong> and <strong>LinkedList</strong> in my solution. Today, to enjoy my weekend, I will explain how I implement the <strong>LFU cache</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664611595217/hOX3rtzjU.png" alt="image.png" /></p>
<h1 id="heading-i-preparation">I. Preparation</h1>
<p>A cache always has 2 main functions: <strong>get</strong> and <strong>put</strong>. And the requirements here are <strong>get</strong> and <strong>put</strong> method must run in O(1) average time complexity. </p>
<p>=&gt; we will store data in a <strong>Hashmap</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664611899901/DBKC9w0eM.png" alt="image.png" /></p>
<p>we invalidate and remove the <strong>least frequently used</strong> key. When there are 2 or more keys with the same frequency, we will remove the <strong>least recently used</strong> key. </p>
<p>=&gt; we will store the frequency of keys in a Hashmap &lt;<strong>Frequency</strong>, <strong>LinkedList of Key</strong>&gt; and will maintain the <strong>least recently used</strong> by the LinkedList of keys in the value.</p>
<p>=&gt; we also need to maintain what is the <strong>min frequency</strong> of <strong>cache</strong>, so when you update the freqMap, you also need to update the min frequency.</p>
<p>And this is my note before I implement:</p>
<ul>
<li><p>class <strong>LFUCache</strong>: </p>
<ul>
<li>capacity</li>
<li>min freq</li>
<li>freqMap: map of (freq, double linked list of nodes)</li>
<li>cache: map of (key, node)</li>
</ul>
</li>
<li><p><strong>get</strong>:</p>
<ul>
<li>if not exist: return -1</li>
<li>if exist:<ul>
<li>check if the node has freq = min_freq and list size == 0 =&gt; min_freq++ (because after that we will increase cur freq by 1)</li>
<li>increase node frequency by 1</li>
<li>remove the node from the current LinkedList in freqMap and insert it to the head of the list at <strong>freq + 1</strong> key</li>
<li>return value</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li><strong>put</strong>:<ul>
<li>if exist: update the value of the key in the <strong>cache</strong>, increase the freq of the node by 1, and update freqMap with the new freq.</li>
<li>else:<ul>
<li>full capacity: get linked list from <strong>freqMap</strong> by min freq of <strong>cache</strong>, remove the last node in <strong>freqMap</strong> and <strong>cache</strong>.</li>
<li>create a new node with freq = 1, reset min freq to 1</li>
<li>insert to <strong>freqMap</strong>: get the cur list or create a new list if not exist, add the new one, and put the list again.</li>
<li>insert into <strong>cache</strong>.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h1 id="heading-ii-implementation">II. Implementation</h1>
<p>Phewwww, here is my implementation:</p>
<pre><code><span class="hljs-keyword">import</span> java.util.HashMap;
<span class="hljs-keyword">import</span> java.util.Map;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LFUCache</span> </span>{

  private int capacity;
  private int minFreq;
  private <span class="hljs-built_in">Map</span>&lt;Integer, DoubleLinkedList&gt; freqMap = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();
  private <span class="hljs-built_in">Map</span>&lt;Integer, Node&gt; cache = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();

  public LFUCache(int capacity) {
    <span class="hljs-built_in">this</span>.capacity = capacity;
  }

  public int get(int key) {
    <span class="hljs-keyword">if</span> (!cache.containsKey(key)) <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;
    Node node = cache.get(key);
    updateFreqList(node);
    <span class="hljs-keyword">return</span> node.val;
  }

  public <span class="hljs-keyword">void</span> put(int key, int value) {
    <span class="hljs-keyword">if</span> (capacity == <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span>;
    <span class="hljs-comment">// update value and frequency when exist</span>
    <span class="hljs-keyword">if</span> (cache.containsKey(key)) {
      Node node = cache.get(key);
      node.val = value;
      updateFreqList(node);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-comment">// remove when cache is full</span>
      <span class="hljs-keyword">if</span> (cache.size() == capacity) {
        DoubleLinkedList minFreqList = freqMap.get(minFreq);
        Node minNode = minFreqList.removeLast();
        cache.remove(minNode.key);
      }

      Node newNode = <span class="hljs-keyword">new</span> Node(key, value);
      minFreq = <span class="hljs-number">1</span>;
      DoubleLinkedList curList = freqMap.getOrDefault(<span class="hljs-number">1</span>, <span class="hljs-keyword">new</span> DoubleLinkedList());
      curList.add(newNode);
      freqMap.put(<span class="hljs-number">1</span>, curList);
      cache.put(key, newNode);
    }
  }

  private <span class="hljs-keyword">void</span> updateFreqList(Node node) {
    <span class="hljs-comment">// remove node from cur list</span>
    DoubleLinkedList curList = freqMap.get(node.frequency);
    curList.remove(node);

    <span class="hljs-keyword">if</span> (node.frequency == minFreq &amp;&amp; curList.size == <span class="hljs-number">0</span>) minFreq++;

    node.frequency++;
    <span class="hljs-comment">// insert into new list with new freq</span>
    DoubleLinkedList newList = freqMap.getOrDefault(node.frequency, <span class="hljs-keyword">new</span> DoubleLinkedList());
    newList.add(node);
    freqMap.put(node.frequency, newList);
  }

  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Node</span> </span>{
    int key;
    int val;
    Node next;
    Node prev;
    int frequency;

    public Node(int k, int v) {
      key = k;
      val = v;
      frequency = <span class="hljs-number">1</span>;
    }
  }

  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DoubleLinkedList</span> </span>{
    Node head;
    Node tail;
    int size;

    public DoubleLinkedList() {
      <span class="hljs-built_in">this</span>.size = <span class="hljs-number">0</span>;
      head = <span class="hljs-keyword">new</span> Node(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>);
      tail = <span class="hljs-keyword">new</span> Node(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>);
      head.next = tail;
      tail.prev = head;
    }

    public <span class="hljs-keyword">void</span> add(Node node) {
      node.next = head.next;
      head.next.prev = node;
      node.prev = head;
      head.next = node;
      size++;
    }

    public <span class="hljs-keyword">void</span> remove(Node node) {
      node.prev.next = node.next;
      node.next.prev = node.prev;
      size--;
    }

    public Node removeLast() {
      <span class="hljs-keyword">if</span> (size &gt; <span class="hljs-number">0</span>) {
        Node tailNode = tail.prev;
        remove(tailNode);
        <span class="hljs-keyword">return</span> tailNode;
      }
      <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
    }
  }
}
</code></pre><h1 id="heading-iii-result">III. Result</h1>
<p>Phewwwww, it's done. I implemented my own doubly linked list, and compare it with when I use <strong>LinkedList of Java Core</strong>.  Surprisingly, my own linked list had better runtime (149ms) while Java core's <strong>LinkedList</strong> triple (509ms). That may be because the <strong>core LinkedList</strong> needs to do many other actions (when we add and remove) rather than focusing on only this problem =)))</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664614665890/7QdSuwqmG.png" alt="image.png" /></p>
<p>Okay, that's all for today's post.</p>
<h1 id="heading-iv-enjoy-your-weekend">IV. Enjoy your weekend</h1>
<p>By the way, let's see =))). Autumn has already come. Go out and enjoy now =)))</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664616864646/5p7bilyqf.jpg" alt="thu_3-09_56_22_226 (2).jpg" /></p>
<p>Enjoy your weekend!</p>
]]></content:encoded></item><item><title><![CDATA[Web Security Notes]]></title><description><![CDATA[There are some security concepts in web development that a developer needs to understand. I wrote this note because nobody can remember all those things they read. Taking notes is a good way to store them instead of trying to remember them - impossib...]]></description><link>https://phamduyhieu.com/web-security-notes</link><guid isPermaLink="true">https://phamduyhieu.com/web-security-notes</guid><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Tue, 13 Sep 2022 01:07:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1663031210761/Fm-TzQMVF.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There are some security concepts in web development that a developer needs to understand. I wrote this note because nobody can remember all those things they read. Taking notes is a good way to store them instead of trying to remember them - impossible =)))</p>
<h2 id="heading-i-cors">I. CORS</h2>
<ul>
<li><strong>What</strong>: Technique that allows a server to indicate any other domains which can make requests to that server in the browser</li>
<li><p><strong>Why</strong> we need: the same origin policy of browser which restricts JavaScript code from making requests from one domain to another domain</p>
<blockquote>
<p><strong>Ex</strong>: you open a Facebook tab and a hacker website tab on your browser. The tab Facebook uses JS to request to the server, if there is no same origin policy, JS of hacker website could also make requests to the Facebook server. That’s why the browser needs to have a policy to detect JS of a resource could access other resources or not</p>
</blockquote>
</li>
<li><p><strong>How to work</strong>:</p>
<ul>
<li>a client send a request to a server with Origin header which contains the domain of the current website</li>
<li>The server will validate the Origin, and if valid, return a response with the header <strong>Access-Control-Allow-Origin</strong> (often have the same value as the <strong>Origin</strong> header)</li>
<li>If there is no Access-Control-Allow-Origin header in a response or an invalid value there, the browser will return an error</li>
</ul>
</li>
<li><p><strong>Config</strong> CORS in Spring Boot:</p>
<ul>
<li>Use @CrossOrigin annotation to enable cross-origin calls from a list of other domains</li>
<li>Define maxAge to cache the preflight response</li>
<li>Config at method level, class level, or globally</li>
<li>To config globally, you need to config a configuration bean that implement webMvcConfiguer to add CorsMappings</li>
</ul>
</li>
</ul>
<h2 id="heading-ii-attack-basics">II. Attack Basics</h2>
<h3 id="heading-1-sql-injection">1. SQL Injection</h3>
<ul>
<li><strong>What</strong>: Attack that uses malicious SQL statement to access information that is not intended to display.</li>
<li><p><strong>Results</strong>: </p>
<ul>
<li>Extract sensitive data</li>
<li>Delete data or drop tables</li>
</ul>
</li>
<li><p><strong>How to prevent</strong>:</p>
<ul>
<li>do not use string concat to build a query</li>
<li>use parameterized queries with spring JPA or JDBC to prevent that.</li>
<li>Principle of least privilege: reduce the permissions of the application/users at runtime<br /> so it can at most edit data, but not change table structures</li>
<li>Password hashing: use one-way hash algorithms such as Bcrypt, can use with salt</li>
</ul>
</li>
</ul>
<h3 id="heading-2-xss-cross-site-scripting">2. XSS - Cross-Site Scripting</h3>
<p>Attackers can inject malicious JavaScript into your website.</p>
<h4 id="heading-a-persistent-xss">a. Persistent XSS</h4>
<ul>
<li><strong>How</strong>: user can add content such as new comments, and those comments which contain malicious JavaScript will be stored in database. So any other users who see that comment will be attacked, and their browser will run this javascript</li>
<li><p><strong>Results</strong>: </p>
<ul>
<li>Spreading malicious js on social media sites, auto download something to your computer,...</li>
<li>Steal your session</li>
<li>Steal your sensitive data</li>
</ul>
</li>
<li><p><strong>How to prevent</strong>:</p>
<ul>
<li>Escape dynamic content: replace significant characters with HTML entity encoding =&gt; <strong>the script will never be treated as executable code by the browser</strong></li>
<li>Whitelist values: users have to select from a list rather than provide any input</li>
<li>Implement <strong>Content-Security Policy</strong> that defines script source and tells the browser to never execute inline JavaScript</li>
<li>HTTP-only cookies: mark cookies as <strong>HTTP-only</strong> so cookies will be received, stored, and sent by the browser only, but cannot be modified or read by JavaScript</li>
</ul>
</li>
<li><p><strong>Set HTTP-only on Spring</strong>:</p>
<ul>
<li>Create a ResponseCookie object</li>
<li>Set HTTP only = true, set maxAge</li>
<li>Add cookie to the response</li>
</ul>
</li>
</ul>
<h4 id="heading-b-reflected-xss">b. Reflected XSS</h4>
<ul>
<li><p><strong>How</strong>: </p>
<ul>
<li>Hacker injects <strong>malicious JavaScript</strong> into the query string and sends it to users</li>
<li>Users click to that URL, the server will respond the parameter back to the user (such as on the search results page)</li>
<li>Then the browser will render the script (send requests to the hacker website with the param is the cookie of users). </li>
<li>Hacker server has session or cookie, then can call to that website as that user.</li>
</ul>
</li>
<li><p><strong>Types of pages will be attacked</strong>:</p>
<ul>
<li><strong>Search results</strong>: search criteria get displayed back to the users</li>
<li><strong>Error pages</strong>: have an error message which contains invalid input, does the input get escaped properly when it is displayed back to the user?</li>
<li><strong>Form submissions</strong>: if a page post data, does any part of the data being submitted by the form get displayed back to the user?</li>
</ul>
</li>
</ul>
<h3 id="heading-3-csrf">3. CSRF</h3>
<ul>
<li><p><strong>What</strong>: If hackers can forge HTTP requests to your site, they may be able to trick your users into triggering unintended actions</p>
</li>
<li><p><strong>How to attack</strong>:</p>
<ul>
<li>User login to their website A</li>
<li>Hacker create a malicious website and trick users to click on their link</li>
<li>In the hacker’s website, there is a form or img to forge a request to website A with user’s cookie</li>
<li>Website A has no way to distinguish between a forged request and an actual request    </li>
<li>That request could do some intended action via the user’s account such as posting a new post, spreading worms on social media, or transferring funds from the visitor’s account to others,...</li>
</ul>
</li>
<li><p><strong>How to prevent</strong>:</p>
<ul>
<li>Use <strong>REST</strong> standard: GET requests are used only to view resources =&gt; limit the harm that can be done by malicious URLs - an attacker will have to work much harder to generate a harmful POST request</li>
<li><p>Client-side generated <strong>CSRF-tokens</strong>: client code generates and sends the same unique secret value in both Cookie and a custom HTTP header. </p>
<p><strong>=&gt;</strong> considering a website is only allowed to read/write a Cookie for its own domain, so only a real website can send the same value in both headers</p>
<p><strong>=&gt;</strong> The server will compare the token attached to the request with the value stored in the cookie.</p>
</li>
<li>Check the HTTP <strong>Referer</strong> and <strong>Origin</strong> header: check the expected domain which triggered the request and reject any requests with abnormal domains</li>
</ul>
</li>
</ul>
<h3 id="heading-4-ddos">4. DDOS</h3>
<ul>
<li><strong>What</strong>: Denial of Service, when attackers attempt to make your website unavailable to others</li>
<li><strong>How</strong>: flooding with requests to exhaust all the available resources (server resources, network bandwidth)
=&gt; real users are unable to get access</li>
<li><strong>Types</strong>:<ul>
<li><strong>SYN flood</strong>: exploits 3-way handshake of TCP when client does not send ACK message to server so may connections do not close so that the server cannot open new connections with real users</li>
<li><strong>HTTP Flood</strong>: hackers will exploit legitimate GET or POST requests
<strong>=&gt;</strong> exhaust the server’s connection pool</li>
<li>Others: ...</li>
</ul>
</li>
<li><strong>How to prevent</strong>:<ul>
<li>Block IP address =&gt; hackers will use distributed DOS</li>
<li>Apply rate limit for IP address, users</li>
<li>Autoscaling</li>
<li>Caching commonly accessed resources to reduce database access</li>
<li>Serve your images, videos and other resources from CDN so that you are offloading accessed resources to a third-party service designed to withstand large amounts of traffic</li>
</ul>
</li>
</ul>
<h2 id="heading-iii-other-concepts">III. Other Concepts</h2>
<h3 id="heading-hash-vs-encrypt-vs-encode">Hash vs Encrypt vs Encode</h3>
<ul>
<li><strong>Hashing</strong> is the act of transforming data from arbitrary size to a fixed size value.
  =&gt; use for checking the integrity of data or verifying the password (Bcrypt hashing)</li>
<li><strong>Encode</strong> is a way to transform data into another form to preserve usability.
  Ex: we transform text, audio, image into bits 1 and 0 so computers can understand, store and process them.</li>
<li><strong>Encryption</strong> is the act of transforming data into another form to preserve the confidentiality<blockquote>
<p>Ex: RSA encryption uses a public key to encrypt and a private key to decrypt data</p>
</blockquote>
</li>
</ul>
<h3 id="heading-is-there-any-way-to-crack-hash">Is there any way to crack Hash?</h3>
<p>Yes of course. We can try to guess the original string by calculating the hash of every possible input and then comparing the results.</p>
<h3 id="heading-encryption-algorithms">Encryption Algorithms</h3>
<ul>
<li><strong>Symmetric encryption</strong>: uses the same key for both encrypting and decrypting data (such as AES,...)</li>
<li><strong>Asymmetric encryption</strong>: uses a public key to encrypt and a private key to decrypt data (such as RSA,...)</li>
</ul>
<p>To be continued...</p>
]]></content:encoded></item><item><title><![CDATA[Học gì và học để làm gì?]]></title><description><![CDATA[Mỗi người có 1 mục tiêu cuộc đời, tạm gọi là mission. Có người muốn thành chuyên gia trong lĩnh vực của họ, có người muốn phát triển lên làm quản lý. Cũng có người muốn đi kinh doanh, phát triển doanh nghiệp của riêng mình. Có người lại chỉ cần chill...]]></description><link>https://phamduyhieu.com/hoc-gi-va-hoc-de-lam-gi</link><guid isPermaLink="true">https://phamduyhieu.com/hoc-gi-va-hoc-de-lam-gi</guid><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Tue, 02 Aug 2022 16:19:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1659457054436/iVrQ3O4Xq.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Mỗi người có 1 mục tiêu cuộc đời, tạm gọi là mission. Có người muốn thành chuyên gia trong lĩnh vực của họ, có người muốn phát triển lên làm quản lý. Cũng có người muốn đi kinh doanh, phát triển doanh nghiệp của riêng mình. Có người lại chỉ cần chill chill sáng cắp ô đi tối cắp ô về, chẳng màng phấn đấu.</p>
<p>Tùy vào mission thế nào, tự khắc bạn sẽ biết mình cần làm gì. Và bao giờ cũng thế, khi mục tiêu của bạn đã rõ, in ra dán đc lên trán, thì cũng là lúc bạn nhận thức được việc gì quan trọng hay không quan trọng, học cái này hay cái kia, và học để dùng cho việc gì.</p>
<p>Đặt mục tiêu càng sớm, bạn càng rút ngắn được thời gian hoàn thành mục tiêu, không sa đà vào những thứ không quan trọng. Đương nhiên là phải có kỷ luật nữa.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659457009787/hDZqnwW8h.jpeg" alt="long_road.jpeg" /></p>
<p>Tôi xác định mục tiêu khá muộn so với bạn bè đồng trang lứa. Tôi cũng không hối hận vì đổi lại là tuổi trẻ nhiều sắc màu cung bậc. Đó là quãng thời gian sống với âm nhạc, những chuyến đi dài rong ruổi, gặp những con người thú vị và lắng nghe những câu chuyện hay. Đến một ngày, tôi dừng lại và tự hỏi mình sẽ làm gì tiếp đây. Và cho đến khi đã ra trường khoảng hơn 1 năm, tôi mới có câu trả lời.</p>
<p>Và từ đó đến nay, tôi luôn nỗ lực cho những việc quan trọng, liên quan trực tiếp đến mục tiêu. Đặc biệt là tôi luôn cân nhắc việc có nên học 1 thứ gì đó không, hay tôi có thực sự cần nó trong công việc hay cuộc sống không. Bởi vì học mà không dùng thì quá lãng phí thời gian. <strong>Cũng giống như hàng đống kiến thực bạn được nhồi nhét trên trường, tới giờ bạn còn nhớ hay áp dụng được những gì???</strong> </p>
<p>Tới giờ đi làm rồi, có ai quan tâm vòng Benzen ra răng? hay các hàm tích phân tầng tầng lớp lớp dùng cho việc chi? (Trừ những bạn nghiên cứu đúng chuyên ngành thì mình k nói).</p>
<p>Cho nên khi một ai đó khen một thứ gì đó hay và bảo tôi học đi, tôi luôn nghĩ ngay tới việc sẽ áp dụng nó vào đâu, mức độ ưu tiên, trước khi quyết định dành thời gian cho nó.</p>
<p>Ngành IT kiến thức là vô biên, nếu không biết chọn lọc thì thực sự bạn dễ bị <em>"cái gì cũng biết mà đếch biết cái gì"</em>. Như cá nhân tôi đã xác định trong 3 năm tới chỉ tập trung làm Backend, thì tôi phải dành tới 95% nguồn lực cho nó. Hôm trước, trong buổi phỏng vấn vị trí Backend Dev, tôi được hỏi nếu khách hàng yêu cầu thì em có sẵn sàng chuyển qua code Front-end không? Ngay lập tức tôi chia sẻ luôn định hướng của bản thân và bày tỏ không sẵn sàng làm như thế. Vì tôi biết nếu chạy theo những gì khách hàng yêu cầu thì tôi sẽ bị xoay như chong chóng, lâu dần chẳng biết mình mạnh cái gì. </p>
<p>Xã hội ngày càng phân công rõ ràng. Các công ty đang có xu hướng tuyển người chuyên về một lĩnh vực nhất định chứ không đỏi hỏi một người biết mọi thứ nhưng chẳng thứ gì sâu sắc. Tốt nhất bạn nên chia sẻ định hướng rõ ràng với nhà tuyển dụng để tìm được một môi trường phù hợp.</p>
<p>Quay lại chuyện học gì và học để làm gì, chỉ có bạn mới trả lời được, sau khi đã biết mission của mình. Tuy nhiên hãy nhớ: <strong>phần lớn kiến thức mà bạn đã học trên trường chẳng áp dụng được cho cuộc sống hiện tại của bạn</strong>. Do vậy lựa mà học thứ cần thiết thôi :))) Còn ti tỉ thứ quan trọng đang chờ bạn khám phá, với điều kiện bạn phải nhận ra chúng trước. Khi đã nhận ra rồi thì cắm đầu mà chạy tới đích chứ còn ngó nghiêng làm gì nữa :)))</p>
<p>02-08-2022 23:05</p>
<p>Duy Hieu</p>
]]></content:encoded></item><item><title><![CDATA[Enhance Your Experience With Xfast – Super Fast Super Cheap]]></title><description><![CDATA[To bring our customers better experiences every day, Giao Hang Tiet Kiem officially launched the XFAST service with extremely outstanding features.

Where: Applicable for orders with pickup and delivery addresses within the urban area in Hanoi and Ho...]]></description><link>https://phamduyhieu.com/enhance-your-experience-with-xfast-ghtk</link><guid isPermaLink="true">https://phamduyhieu.com/enhance-your-experience-with-xfast-ghtk</guid><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Wed, 01 Jun 2022 17:31:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1654104264338/AEoFvHGWF.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>To bring our customers better experiences every day, <a target="_blank" href="https://giaohangtietkiem.vn"><strong>Giao Hang Tiet Kiem</strong></a> officially launched the <a target="_blank" href="https://giaohangtietkiem.vn/xfast-hang-giao-sieu-toc-gia-re-vo-dich-13110"><strong>XFAST service</strong></a> with extremely outstanding features.</p>
<ul>
<li><p><strong>Where</strong>: Applicable for orders with pickup and delivery addresses within the urban area in Hanoi and Ho Chi Minh City.</p>
</li>
<li><p><strong>Who</strong>: shops and personal customers with fruits, food, clothes, cosmetics, books, components,...</p>
</li>
<li><p><strong>Time</strong>: 7h-21h30</p>
</li>
</ul>
<p><strong>XFAST</strong> commits that the maximum delivery time of orders will be specifically applied to each kilometer as follows:</p>
<ul>
<li><p>0 - 3km delivered in 30 minutes</p>
</li>
<li><p>3 - 6km delivered in 60 minutes</p>
</li>
<li><p>6 - 9km delivered in 90 minutes</p>
</li>
<li><p>More than 9km delivery only from 2-3 hours</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654104596232/DXVOYclfY.jpg" alt="Xfast-sieu-toc-web-100-1.jpg" /></p>
<p><strong>Cost</strong>:</p>
<ul>
<li>0.9 USD for a package with distance &lt;= 2km</li>
<li>plus 0.15USD/km if distance &gt; 2km</li>
<li>order from 18h-6h: additional cost 0.2USD</li>
</ul>
<p>For the best support, Shop can contact the following channels to answer questions from GHTK:</p>
<p>– Email: cskh@ghtk.vn</p>
<p>– Fanpage: Giaohangtietkiem.vn</p>
]]></content:encoded></item><item><title><![CDATA[Tips for Using Exceptions in Java]]></title><description><![CDATA[There is a certain amount of controversy about the proper use of exceptions. Some programmers believe that all checked exceptions are a nuisance, others can’t seem to throw enough of them. We think that exceptions (even checked exceptions) have their...]]></description><link>https://phamduyhieu.com/tips-for-using-exceptions-in-java</link><guid isPermaLink="true">https://phamduyhieu.com/tips-for-using-exceptions-in-java</guid><dc:creator><![CDATA[Hiếu Phạm Duy]]></dc:creator><pubDate>Sun, 20 Mar 2022 08:39:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1647765581206/7antbR6S3.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There is a certain amount of controversy about the proper use of exceptions. Some programmers believe that all checked exceptions are a nuisance, others can’t seem to throw enough of them. We think that exceptions (even checked exceptions) have their place, and offer you these <strong>tips</strong> for their proper use.</p>
<h2 id="heading-i-exception-handling-is-not-supposed-to-replace-a-simple-test">I. Exception handling is not supposed to replace a simple test.</h2>
<p>As an example of this, we wrote some code that tries 10,000,000 times to pop an empty stack. It first does this by finding out whether the stack is empty.</p>
<pre><code><span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>stack.isEmpty()) s.<span class="hljs-built_in">pop</span>();
</code></pre><p>Next, we force it to pop the stack no matter what and then catch the <strong>EmptyStackException</strong>.</p>
<pre><code><span class="hljs-keyword">try</span> {
   stack.<span class="hljs-built_in">pop</span>();
}  <span class="hljs-keyword">catch</span> (EmptyStackException e) {
}
</code></pre><p>On my test laptop, the version that calls <strong>isEmpty</strong> ran in 20 milliseconds. The version that catches the <strong>EmptyStackException</strong> ran in 3640 milliseconds.</p>
<p>As you can see, it took far longer to catch an <strong>exception</strong> than to perform a <strong>simple</strong> <strong>test</strong>. The moral is: <strong>Use exceptions for exceptional circumstances only.</strong></p>
<h2 id="heading-ii-do-not-micromanage-exceptions">II. Do not micromanage exceptions.</h2>
<p>Many programmers wrap every statement in a separate <strong>try</strong> block.</p>
<pre><code><span class="hljs-keyword">for</span> (i <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i <span class="hljs-operator">&lt;</span> <span class="hljs-number">100</span>; i<span class="hljs-operator">+</span><span class="hljs-operator">+</span>) {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-built_in">this</span>.method1()
      } <span class="hljs-keyword">catch</span> (EmptyStackException e) {
        <span class="hljs-comment">// problem 1</span>
      }
      <span class="hljs-keyword">try</span> {
        <span class="hljs-built_in">this</span>.method2()
      } <span class="hljs-keyword">catch</span> (IOException e) {
        <span class="hljs-comment">// problem 2</span>
      }
}
</code></pre><p>This approach blows up your code dramatically.  Just wrap the entire task in a <strong>try</strong> block. If any one operation fails, you can then abandon the task.</p>
<pre><code><span class="hljs-keyword">for</span> (i <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i <span class="hljs-operator">&lt;</span> <span class="hljs-number">100</span>; i<span class="hljs-operator">+</span><span class="hljs-operator">+</span>) {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-built_in">this</span>.method1()
        <span class="hljs-built_in">this</span>.method2()
      } <span class="hljs-keyword">catch</span> (EmptyStackException e) {
        <span class="hljs-comment">// problem 1</span>
      } <span class="hljs-keyword">catch</span> (IOException e) {
        <span class="hljs-comment">// problem 2</span>
      }
}
</code></pre><p>This code looks much cleaner. It fulfills one of the promises of exception handling: to <strong>separate normal processing from error handling</strong>.</p>
<h2 id="heading-iii-make-good-use-of-the-exception-hierarchy">III. Make good use of the exception hierarchy.</h2>
<p>Don’t just throw a <strong>RuntimeException</strong>. Find an appropriate subclass or create your own.
Don’t just catch <strong>Throwable</strong>. It makes your code hard to read and maintain.</p>
<p>Do not hesitate to turn an exception into another exception that is <strong>more appropriate</strong>. For example, when you parse an <strong>integer</strong> in a file, catch the <strong>NumberFormatException</strong> and turn it into a subclass of <strong>IOException</strong> or <strong>FileInputFormatException</strong> that you declared.</p>
<h2 id="heading-iv-throw-early-catch-late">IV. Throw early, catch late</h2>
<p>Some programmers worry about throwing exceptions when they detect errors. Maybe it would be better to return a <strong>dummy value</strong> rather than throw an <strong>exception</strong> when a method is called with invalid parameters? </p>
<p>For example, should <strong>Stack.pop</strong> return <strong>null</strong>, or throw an exception when a stack is empty? We think it is better to throw an <strong>EmptyStackException</strong> at the point of failure than to have a <strong>NullPointerException</strong> occur at later time.</p>
<p>Many programmers feel compelled to catch all exceptions that are thrown. Often, it is actually better to <strong>propagate the exception instead of catching it</strong>:</p>
<p>Higher-level methods are often better equipped to inform the user of errors or to abandon unsuccessful commands.</p>
<p>(Source: Core Java Volumn I - Fundamentals)</p>
]]></content:encoded></item></channel></rss>