<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Validation - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Validation - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 26 Jul 2026 11:16:26 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/validation/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ The Data Quality Handbook: Data Errors, the Developer's Role, and Validation Layers Explained. ]]>
                </title>
                <description>
                    <![CDATA[ In August 2012, Knight Capital, a major trading firm in the United States, deployed faulty trading software to its production system. The system used this incorrect configuration data and it triggered ]]>
                </description>
                <link>https://www.freecodecamp.org/news/data-quality-handbook-data-errors-the-developer-s-role-validation-layers/</link>
                <guid isPermaLink="false">69dea3b491716f3cfb75fd9d</guid>
                
                    <category>
                        <![CDATA[ data ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Data Science ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Validation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Great John ]]>
                </dc:creator>
                <pubDate>Tue, 14 Apr 2026 20:29:40 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/4f0c9085-cb4f-4255-b7a0-e146eafc32c9.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In August 2012, Knight Capital, a major trading firm in the United States, deployed faulty trading software to its production system. The system used this incorrect configuration data and it triggered millions of unintended stock trades.</p>
<p>The company lost about $440 million in just 45 minutes. Knight Capital nearly collapsed and had to be rescued by investors. It was later acquired by another firm.</p>
<p>When Target expanded into Canada, the company relied on a new supply chain system that contained incorrect product and inventory data. Product information in the database was incomplete and inaccurate. Prices, sizes, and product descriptions were entered incorrectly.</p>
<p>Inventory systems reported items in stock that were actually unavailable. Customers found empty shelves in stores despite the system showing stock. The company lost over $2 billion in the Canadian market. Target eventually shut down all Canadian stores in 2015.</p>
<p>One employee made the statement “Even though we had a great supply chain system on paper, we didn’t have accurate data. Bad data leads to bad decisions’’</p>
<p>Another famous example of data-related engineering failures involves the Mars Climate Orbiter spacecraft. One engineering team used metric units (newtons). Another team used imperial units (pounds-force). The system failed to convert the data correctly. The spacecraft entered Mars' atmosphere at the wrong altitude. The mission failed and the spacecraft was destroyed. The loss was about $125 million.</p>
<p>In this article, we'll delve deep into what data quality truly means, the types of data errors that silently break systems, the developer’s responsibility in preventing them, and the validation layers that work together to keep bad data out of production.</p>
<h3 id="heading-what-well-cover">What We'll Cover:</h3>
<ul>
<li><p><a href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a href="#heading-the-importance-of-data-quality">The Importance of Data Quality</a></p>
<ul>
<li><p><a href="#heading-how-does-bad-data-happen-in-the-first-place">How Does Bad Data Happen in the First Place?</a></p>
</li>
<li><p><a href="#heading-the-cost-of-bad-data">The Cost of Bad Data</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-types-of-data-errors">Types of Data Errors</a></p>
<ul>
<li><p><a href="#heading-required-field-errors">Required Field Errors</a></p>
</li>
<li><p><a href="#heading-format-validation-errors">Format Validation Errors</a></p>
</li>
<li><p><a href="#heading-range-and-limit-errors">Range and Limit Errors</a></p>
</li>
<li><p><a href="#heading-logical-consistency-errors">Logical Consistency Errors</a></p>
</li>
<li><p><a href="#heading-duplicate-and-data-integrity-errors">Duplicate and Data Integrity Errors</a></p>
</li>
<li><p><a href="#heading-relational-errors-reference-integrity">Relational Errors (Reference Integrity)</a></p>
</li>
<li><p><a href="#heading-structural-errors-dropdowns-radio-buttons-enums">Structural Errors (Dropdowns, Radio Buttons, Enums)</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-what-makes-good-data">What Makes Good Data?</a></p>
<ul>
<li><p><a href="#heading-completeness">Completeness:</a></p>
</li>
<li><p><a href="#heading-uniqueness">Uniqueness:</a></p>
</li>
<li><p><a href="#heading-validity">Validity:</a></p>
</li>
<li><p><a href="#heading-timeliness">Timeliness:</a></p>
</li>
<li><p><a href="#heading-accuracy">Accuracy:</a></p>
</li>
<li><p><a href="#heading-consistency">Consistency:</a></p>
</li>
<li><p><a href="#heading-fitness-for-purpose">Fitness for Purpose:</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-data-validation-layers">Data Validation Layers</a></p>
<ul>
<li><p><a href="#heading-frontend-layer-protect-the-user-not-the-system">Frontend Layer — “Protect the User, Not the System”</a></p>
</li>
<li><p><a href="#heading-backend-validation-the-real-gatekeeper">Backend Validation — “The Real Gatekeeper”</a></p>
</li>
<li><p><a href="#heading-database-layer-protect-the-data-at-rest">Database Layer — “Protect the Data at Rest”</a></p>
</li>
<li><p><a href="#heading-service-layer-business-logic-validate-real-world-rules">Service Layer / Business Logic — “Validate Real-World Rules”</a></p>
</li>
<li><p><a href="#heading-jobs-queues-data-ingestion-validate-external-data">Jobs / Queues / Data Ingestion — “Validate External Data”</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-testing-strategies-to-protect-data-quality">Testing Strategies to Protect Data Quality</a></p>
<ul>
<li><p><a href="#heading-unit-testing-the-schema-amp-constraint-check">Unit Testing: The Schema &amp; Constraint Check</a></p>
</li>
<li><p><a href="#heading-integration-testing-the-flow-amp-lineage-check">Integration Testing: The Flow &amp; Lineage Check</a></p>
</li>
<li><p><a href="#heading-functional-testing-the-business-rule-check">Functional Testing: The Business Rule Check</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h3 id="heading-prerequisites">Prerequisites</h3>
<ul>
<li><p>A basic understanding of what data is</p>
</li>
<li><p>A basic understanding of data structures</p>
</li>
<li><p>An understanding of what an API is</p>
</li>
<li><p>An understanding of what a database is and what it does</p>
</li>
</ul>
<h2 id="heading-the-importance-of-data-quality">The Importance of Data Quality</h2>
<p>As you can see from just these few examples, the quality of the data you're working with really matters.</p>
<p>Gartner reports that organisations attribute <a href="https://www.forbes.com/councils/forbestechcouncil/2021/10/14/flying-blind-how-bad-data-undermines-business/"><strong>around $15 million in annual losses</strong></a> to poor‑quality data. The same research also shows that <a href="https://www.forbes.com/councils/forbestechcouncil/2021/10/14/flying-blind-how-bad-data-undermines-business/"><strong>nearly 60% of companies have no clear idea what bad data actually costs them</strong></a>, largely because they don’t track or measure data‑quality issues at all.</p>
<p>A 2016 study by IBM is even more eye-popping. IBM found that <a href="https://community.sap.com/t5/technology-blog-posts-by-sap/bad-data-costs-the-u-s-3-trillion-per-year/ba-p/13575387">poor data quality strips $3.1 trillion from the U.S. economy annually</a> due to lower productivity, system outages, and higher maintenance costs.</p>
<p>Bad data is, and will continue to be, the kryptonite of any organisation. This is even more concerning as more organisations now depend on data for strategy execution than ever before.</p>
<p>When data is wrong, incomplete, duplicated, or inconsistent, the consequences ripple outward: Incorrect dashboards mislead teams, which leads to making incorrect decisions. Implementing these decisions can lead to faulty strategy and policy implementation.</p>
<p>Eventually, the organisation pays the price, financially, operationally, and reputationally. And while money can be recovered, reputation rarely bounces back so easily.</p>
<h3 id="heading-how-does-bad-data-happen-in-the-first-place">How Does Bad Data Happen in the First Place?</h3>
<p>Form fields are usually the first place where data enters an application, so they’re often where bad data begins. This is why the developer’s role is so critical.</p>
<p>Many of the most damaging data errors don’t originate from malicious users or complex edge cases – they come from simple oversights that the system should never have allowed in the first place.</p>
<p>But it's equally important to recognise that data quality issues often originate <em>before</em> the data ever reaches an application. Upstream processes — how data is collected, measured, recorded, or pre‑validated — can introduce inaccuracies long before the system receives it.</p>
<p>For example, a nurse might weigh a patient using an uncalibrated mechanical scale, record the incorrect value on a paper form, and later have that value transcribed into the hospital system. By the time the data enters the application, the error is already embedded.</p>
<p>This means that maintaining data quality requires attention both to upstream data collection practices and to the system-level validation that developers control.</p>
<p>When the UI, backend, or API layer permits invalid, incomplete, inconsistent, or logically impossible data to enter the pipeline, the organisation inherits a long‑term liability. Even small choices — such as allowing empty fields, ignoring duplicates, or failing to enforce validation rules — can introduce errors that may only surface months later in reports or dashboards, leading to confusion and inaccurate insights.</p>
<h3 id="heading-the-cost-of-bad-data">The Cost of Bad Data</h3>
<p>Data quality can also be impacted at any stage of the data pipeline: before ingestion, in production, or even during analysis.</p>
<p>If bad data is caught in the UI, it's almost free, if we're thinking in terms of cost. If it's caught at the API layer, that's still pretty cheap. If it's caught in the database, the cost is moderate. And if it's caught in a report or ML model months later, that's expensive, and sometimes irreversible.</p>
<p>A key principle in modern data management is: the cheapest and safest place to catch bad data is at the source, and that is before ingestion. <a href="https://www.matillion.com/blog/the-1-10-100-rule-of-data-quality-a-critical-review-for-data-professionals">The well-known 1-10-100 Rule</a>, introduced by George Labovitz and Yu Sang Chang in 1992, clearly illustrates this idea.</p>
<p>According to the rule, it costs about \(1 to validate data at the point of entry, \)10 to correct it after it has entered the system, and $100 per record if the error goes unnoticed and causes problems further down the line.</p>
<p>As the saying goes, an ounce of prevention is worth a pound of cure – and this is especially true when it comes to maintaining high-quality data.</p>
<p>To help buttress my point, I’ve categorised the different types of errors and oversights that developers should never allow that can and should be prevented before they ever reach the database, analytics layer, or reporting systems.</p>
<h2 id="heading-types-of-data-errors">Types of Data Errors</h2>
<h3 id="heading-required-field-errors">Required Field Errors</h3>
<p>If you build a form that allows a user to submit a registration form with important fields left empty (like first name, last name, email address, phone number, date of birth, or address), you're directly letting incomplete data enter the system.</p>
<p>I remember a scenario from my time as a data analyst where I was analysing a dataset containing different types of alarms triggered across several buildings. These alarms fell into categories such as aquarium alarms, intruder alarms, fire alarms, and maintenance alarms.</p>
<p>The purpose of the analysis was simple: identify which buildings had the highest frequency of alarms so that maintenance, resources, or investigations could be allocated appropriately.</p>
<p>Whenever an alarm went off, the security team recorded it using a software system. By the end of each month, we could view the cumulative alarms and generate insights.</p>
<p>But I encountered a major data quality issue. The security officers often selected the alarm category but failed to submit the building where the alarm occurred — and the system allowed this incomplete record to be saved into the database.</p>
<p>Every alarm had to occur in a specific building. Yet during analysis, I would see entries like “20 fire alarms” with no building information attached. Since I couldn’t determine where these alarms happened, the data became unusable. I had no choice but to delete those records because they provided no actionable value.</p>
<p>This is a classic example of poor data validation. If the developer had implemented proper constraints, the system would never allow an alarm to be submitted without a building name.</p>
<p>Required fields should be enforced at the UI and backend levels to prevent missing data from entering the system in the first place. These gaps lead to missing or unusable data in the database, often forcing teams to delete or manually repair records later.</p>
<p>To prevent these errors, you can use required‑field validation, disable the submit button until all mandatory fields are completed, and visually highlight missing fields with inline error messages.</p>
<p>Here's a practical code example of some bad code (no required checks):</p>
<pre><code class="language-plaintext">&lt;form id="signup"&gt;
  &lt;input type="text" id="name" placeholder="Full name"&gt;
  &lt;input type="email" id="email" placeholder="Email"&gt;
  &lt;button type="submit"&gt;Sign up&lt;/button&gt;
&lt;/form&gt;

&lt;script&gt;
document.getElementById("signup").addEventListener("submit", e =&gt; {
  const name = document.getElementById("name").value;
  const email = document.getElementById("email").value;
  console.log("Submitted:", { name, email });
});
&lt;/script&gt;
</code></pre>
<p>From the above code snippet, the core problem is that the form doesn't enforce required input. Neither HTML‑level validation (using the <code>required</code> attribute) nor JavaScript‑based checks are implemented. This omission allows users to submit the form without providing necessary information, making the form unreliable for collecting valid and complete user data.</p>
<p>From a usability and data quality perspective, this is problematic. Forms are typically designed to collect meaningful and complete information, and fields such as “Full name” and “Email” are usually essential. Without marking these inputs as required or validating them programmatically, we risk receiving blank or invalid submissions, which can compromise the quality of stored data and any processes that depend on it.</p>
<p>Here's an example of a better version (UI prevents empty submission):</p>
<pre><code class="language-plaintext">&lt;form id="signup"&gt;
  &lt;input type="text" id="name" placeholder="Full name" required&gt;
  &lt;input type="email" id="email" placeholder="Email" required&gt;
  &lt;button type="submit"&gt;Sign up&lt;/button&gt;
&lt;/form&gt;

&lt;script&gt;
document.getElementById("signup").addEventListener("submit", e =&gt; {
  if (!e.target.checkValidity()) {
    e.preventDefault();
    alert("Please fill in all required fields.");
  }
});
&lt;/script&gt;
</code></pre>
<p>In this revised version of the code, the addition of the <code>required</code> attribute to both the name and email input elements ensures that the browser won't allow the form to be submitted unless these fields are filled. This is an important step toward maintaining data completeness and improving the overall reliability of the form.</p>
<p>Also, by checking <code>e.target.checkValidity()</code>, we now ensure that the form is evaluated before submission proceeds.</p>
<p>Another positive aspect is the conditional use of <code>e.preventDefault()</code>. When the form is invalid, the default submission behavior is stopped, preventing incomplete or incorrect data from being sent.</p>
<h3 id="heading-format-validation-errors">Format Validation Errors</h3>
<p>If you have a form that allows a user to enter an email without an @ symbol, an email without a domain, a phone number containing letters, or a postcode/ZIP code in the wrong format, that allows invalid data to enter the system.</p>
<p>The same applies when you allow a user to submit an impossible date (32/15/2025) or a credit card number with the wrong length.</p>
<p>These issues will cause the data analyst to spend more time cleaning the data, if it's even cleanable. And such incorrect inputs create unreliable data that breaks downstream processes and increases cleanup costs.</p>
<p>To prevent these types of errors, you can use regex validation, input masks, and field‑type restrictions (for example, numeric‑only fields for phone numbers) to enforce correct formats before submission.</p>
<p>Here's a bad example of allowing format validation errors:</p>
<pre><code class="language-plaintext">&lt;input id="phone" placeholder="Phone number"&gt;
&lt;button onclick="save()"&gt;Save&lt;/button&gt;

&lt;script&gt;
function save() {
  const phone = document.getElementById("phone").value;
  console.log("Saving phone:", phone);
}
&lt;/script&gt;
</code></pre>
<p>This code doesn't perform any checks on the format or structure of the phone number. The function simply retrieves whatever value exists –&nbsp;whether valid, invalid, or blank –&nbsp;and logs it to the console without any condition.</p>
<p>Here's the fixed version:</p>
<pre><code class="language-plaintext">&lt;input id="phone" placeholder="Phone number" required&gt;
&lt;button onclick="save()"&gt;Save&lt;/button&gt;

&lt;script&gt;
function save() {
  const phone = document.getElementById("phone").value;

  if (!/^\d+$/.test(phone)) {
    alert("Phone number must contain digits only.");
    return;
  }

  console.log("Saving phone:", phone);
}
&lt;/script&gt;
</code></pre>
<p>This version fixes the earlier mistake by introducing a clear validation rule. Before the system accepts the phone number, it checks whether the input contains only digits. The regular expression <code>^\d+$</code> ensures that the value is made up entirely of numbers, with no letters or symbols allowed. If the user enters anything invalid, the function stops and displays an error message instead of saving bad data.</p>
<p>This approach prevents the format error that occurred in the previous example. Instead of blindly trusting whatever the user types, the code now enforces a rule that matches the expected format of a phone number. This is what a responsible developer should do: verify the input before using it.</p>
<h3 id="heading-range-and-limit-errors">Range and Limit Errors</h3>
<p>Allowing users to enter values outside acceptable limits – such as negative ages, quantities below zero, discounts above 100%, or measurements far beyond realistic ranges – that enables the ingestion of data that violates business rules. These errors distort analytics, break calculations, and create operational inconsistencies.</p>
<p>To mitigate these errors, you can apply min/max constraints, sliders, steppers, and numeric boundaries to ensure values fall within valid ranges.</p>
<p>Here's a bad example of allowing range and limit errors:</p>
<pre><code class="language-plaintext">&lt;input id="age" type="number"&gt;
&lt;button onclick="submitAge()"&gt;Submit&lt;/button&gt;

&lt;script&gt;
function submitAge() {
  console.log("Age:", document.getElementById("age").value);
}
&lt;/script&gt;
</code></pre>
<p>As seen above, we've created an input field for age but doesn't specify any limits or constraints. The browser allows the user to type any number — including values that make no sense, such as negative ages, extremely large ages, or decimals. The JavaScript function simply reads the value and logs it without checking whether the age is realistic.</p>
<p>Here's a better version:</p>
<pre><code class="language-plaintext">&lt;input id="age" type="number" min="0" max="120" required&gt;
&lt;button onclick="submitAge()"&gt;Submit&lt;/button&gt;

&lt;script&gt;
function submitAge() {
  const ageInput = document.getElementById("age");
  if (!ageInput.checkValidity()) {
    alert("Age must be between 0 and 120.");
    return;
  }
  console.log("Age:", ageInput.value);
}
&lt;/script&gt;
</code></pre>
<p>Now in this version, the inclusion of the <code>min="0"</code> and <code>max="120"</code> attributes sets clear boundaries for acceptable input values. This ensures that only realistic age values within a defined range are allowed, preventing invalid entries such as negative numbers or excessively large ages.</p>
<p>The JavaScript function further enhances this validation by using the <code>checkValidity()</code> method. This method checks whether the input satisfies all defined constraints, including the required condition and the specified numeric range. If the input doesn't meet these conditions, the function prevents further execution and displays an alert message, informing the user that the entered age must fall within the allowed range.</p>
<h3 id="heading-logical-consistency-errors">Logical Consistency Errors</h3>
<p>If you allow a user to select an end date before the start date, choose a checkout date earlier than check‑in at a hotel, or enter a delivery date before the order date, this will result in logically impossible data. The same applies when you allow a user to enter a graduation year earlier than their admission to a program, or submit working hours that exceed 24 hours in a day.</p>
<p>You can mitigate this by implementing cross‑field validation, business‑rule checks, and conditional logic that ensures related fields remain consistent.</p>
<p>Here's a bad example of a logical consistency error:</p>
<pre><code class="language-plaintext">&lt;input type="date" id="start"&gt;
&lt;input type="date" id="end"&gt;
&lt;button onclick="save()"&gt;Save&lt;/button&gt;

&lt;script&gt;
function save() {
  console.log({
    start: document.getElementById("start").value,
    end: document.getElementById("end").value
  });
}
&lt;/script&gt;
</code></pre>
<p>In the code above, the core issue is the complete absence of validation. Although the inputs use <code>type="date"</code>, which provides a structured way for users to select dates, the code doesn't enforce that either field is required. This means the user can leave one or both date fields empty, and the <code>save()</code> function will still run and log the values. As a result, the system may end up processing incomplete or meaningless data.</p>
<p>Beyond missing required checks, the code also fails to validate the logical relationship between the two dates. In any scenario involving a start date and an end date, it's expected that the start date shouldn't occur after the end date. But this code performs no such comparison.</p>
<p>This means that the user can select a start date that's later than the end date, and the system will accept it without warning. This leads to inconsistent or impossible data being recorded.</p>
<p>Also, the function simply logs the values without providing any feedback to the user. There's no mechanism to alert the user when a field is empty or when the dates are logically incorrect. This reduces usability and makes it difficult for users to understand or correct their mistakes.</p>
<p>Here's the fixed version:</p>
<pre><code class="language-plaintext">&lt;input type="date" id="start" required&gt;
&lt;input type="date" id="end" required&gt;
&lt;button onclick="save()"&gt;Save&lt;/button&gt;

&lt;script&gt;
function save() {
  const startValue = document.getElementById("start").value;
  const endValue = document.getElementById("end").value;

  // Extra safety: check empties (in case required is bypassed)
  if (!startValue || !endValue) {
    alert("Both start and end dates are required.");
    return;
  }

  const start = new Date(startValue);
  const end = new Date(endValue);

  if (end &lt; start) {
    alert("End date cannot be before start date.");
    return;
  }

  console.log({ start, end });
}
&lt;/script&gt;
</code></pre>
<p>In this improved version, first, both date fields now include the <code>required</code> attribute, ensuring that the user can't leave either field empty without triggering validation.</p>
<p>Second, we've added a logical validation check to ensure that the relationship between the two dates is correct. After retrieving the values, the function converts them into <code>Date</code> objects and compares them to verify that the end date doesn't occur before the start date. If this condition is violated, the function stops execution and displays an alert informing the user of the error.</p>
<p>This prevents inconsistent or impossible date ranges from being accepted.</p>
<h3 id="heading-duplicate-and-data-integrity-errors">Duplicate and Data Integrity Errors</h3>
<p>When you let a user submit an email that's already registered, choose a username that's already taken, or enter a duplicate employee ID or student number, this results in identity conflicts and duplicate records. Problems also arise when you allow users to upload unsupported file types, oversized files, or corrupted images.</p>
<p>Security risks can emerge when users are able to enter HTML/script tags (XSS), SQL‑injection patterns, or disallowed special characters. These issues compromise data quality, system integrity, and security.</p>
<p>You can prevent these types of issues by using uniqueness checks, file‑type and size validation, and input sanitization to block duplicates, invalid uploads, and malicious inputs.</p>
<p>Here's an example of a duplicate error:</p>
<pre><code class="language-plaintext">&lt;input id="email" placeholder="Enter email" required&gt;
&lt;button onclick="save()"&gt;Save&lt;/button&gt;

&lt;script&gt;
const savedEmails = [];

function save() {
  const email = document.getElementById("email").value;
  savedEmails.push(email);
  console.log("Saved emails:", savedEmails);
}
&lt;/script&gt;
</code></pre>
<p>This code blindly pushes every email into the <code>savedEmails</code> array without checking whether the email already exists. Because there is no duplicate detection, the user can enter the same email multiple times.</p>
<p>Here is the fixed version:</p>
<pre><code class="language-plaintext">&lt;input id="email" placeholder="Enter email" required&gt;
&lt;button onclick="save()"&gt;Save&lt;/button&gt;

&lt;script&gt;
const savedEmails = [];

function save() {
  const email = document.getElementById("email").value.trim();

  // Check if the field is empty
  if (!email) {
    alert("Please enter an email before saving.");
    return;
  }

  // Check for duplicate
  if (savedEmails.includes(email)) {
    alert("This email has already been saved.");
    return;
  }

  savedEmails.push(email);
  console.log("Saved emails:", savedEmails);
}
&lt;/script&gt;

</code></pre>
<p>In this improved version of the code, we've implemented proper validation steps to prevent duplicate email entries. Before saving the email, the function checks whether the value already exists in the <code>savedEmails</code> array using the <code>includes()</code> method. If the email is found, the function stops execution and displays an alert informing the user that the email has already been saved. This ensures that each email is stored only once, maintaining the uniqueness and integrity of the data.</p>
<h3 id="heading-relational-errors-reference-integrity">Relational Errors (Reference Integrity)</h3>
<p>If you let a user select a city that doesn’t belong to the chosen country, a product ID that no longer exists, a retired SKU, or a shipping method unavailable in the selected region, this can result in broken references.</p>
<p>The same applies when users can select a manager from a different department or choose a fully booked time slot, not setting the right roles and permissions. These errors break relationships between tables and corrupt downstream joins and reports.</p>
<p>Here, you can use dependent dropdowns, real‑time lookups, and foreign‑key validation to help ensure that users can only select valid, existing, and compatible options.</p>
<p>Here's a bad example of a relational error:</p>
<pre><code class="language-plaintext">&lt;select id="country"&gt;
  &lt;option value="uk"&gt;United Kingdom&lt;/option&gt;
  &lt;option value="usa"&gt;United States&lt;/option&gt;
&lt;/select&gt;

&lt;select id="city"&gt;
  &lt;option value="london"&gt;London&lt;/option&gt;
  &lt;option value="manchester"&gt;Manchester&lt;/option&gt;
  &lt;option value="newyork"&gt;New York&lt;/option&gt;
  &lt;option value="losangeles"&gt;Los Angeles&lt;/option&gt;
&lt;/select&gt;

&lt;button onclick="save()"&gt;Save&lt;/button&gt;

&lt;script&gt;
function save() {
  const country = document.getElementById("country").value;
  const city = document.getElementById("city").value;

  console.log("Saving:", { country, city });
}
&lt;/script&gt;
</code></pre>
<p>From the above, the mistake in this code is that we've treated country and city as completely independent fields, even though one is supposed to depend on the other. By presenting all cities regardless of the selected country, the interface allows users to create combinations that make no sense — such as choosing “United Kingdom” with “New York” or “United States” with “Manchester.”</p>
<p>Also, because the <code>save()</code> function performs no validation and simply logs whatever the user selects, the system ends up accepting and storing relationships that should never exist. This breaks the logical link between the two fields and leads to invalid, inconsistent data that can corrupt downstream.</p>
<p>Here's the fixed, production-ready version:</p>
<pre><code class="language-plaintext">&lt;select id="country" onchange="loadCities()" required&gt;
  &lt;option value=""&gt;Select country&lt;/option&gt;
  &lt;option value="uk"&gt;United Kingdom&lt;/option&gt;
  &lt;option value="usa"&gt;United States&lt;/option&gt;
&lt;/select&gt;

&lt;select id="city" required disabled&gt;
  &lt;option value=""&gt;Select city&lt;/option&gt;
&lt;/select&gt;

&lt;button onclick="save()"&gt;Save&lt;/button&gt;

&lt;script&gt;
const citiesByCountry = {
  uk: ["London", "Manchester"],
  usa: ["New York", "Los Angeles"]
};

function loadCities() {
  const country = document.getElementById("country").value;
  const citySelect = document.getElementById("city");

  // Reset city dropdown
  citySelect.innerHTML = '&lt;option value=""&gt;Select city&lt;/option&gt;';

  // Disable if no country selected
  if (!country) {
    citySelect.disabled = true;
    return;
  }

  // Enable dropdown
  citySelect.disabled = false;

  // Load cities safely
  (citiesByCountry[country] || []).forEach(city =&gt; {
    const option = document.createElement("option");
    option.value = city.toLowerCase().replace(/\s+/g, ""); // remove ALL spaces
    option.textContent = city;
    citySelect.appendChild(option);
  });
}

function save() {
  const country = document.getElementById("country").value;
  const city = document.getElementById("city").value;

  // Required validation
  if (!country || !city) {
    alert("Please select both a country and a city.");
    return;
  }

  // Build list of valid cities for this country
  const validCities = (citiesByCountry[country] || [])
    .map(c =&gt; c.toLowerCase().replace(/\s+/g, ""));

  // Relational validation
  if (!validCities.includes(city)) {
    alert("Selected city does not belong to the chosen country.");
    return;
  }

  console.log("Saving:", { country, city });
}
&lt;/script&gt;
</code></pre>
<p>This improved code turns the country–city form into a controlled, relationship‑aware flow instead of two loose dropdowns.</p>
<p>When the user selects a country, the <code>loadCities()</code> function runs. It first clears the city dropdown and, if no country is selected, keeps the city field disabled so the user can't choose a city on its own.</p>
<p>Once a valid country is chosen, the city dropdown is enabled and populated only with the cities that belong to that specific country, using the <code>citiesByCountry</code> mapping. Also, the city values are normalised (lowercased and stripped of spaces) so they’re consistent and safe to compare.</p>
<p>When the user clicks “Save,” the <code>save()</code> function checks that both a country and a city have been selected. If either is missing, it shows an alert and stops. It then rebuilds the list of valid city values for the chosen country and verifies that the selected city is actually in that list.</p>
<h3 id="heading-structural-errors-dropdowns-radio-buttons-enums">Structural Errors (Dropdowns, Radio Buttons, Enums)</h3>
<p>If users can type a country as “U.S.A”, “USA”, “United States”, or “us”, enter gender as “male”, “Male”, “M”, or “man”, or type a department as “Engineering”, “Eng”, or “engineer”, this can result in inconsistent categorical data.</p>
<p>The same applies to currencies typed as “usd”, “USD”, “US Dollars”, product categories spelled differently, status values like “active”, “Active”, “ACT”, “enabled”, or boolean values like “yes”, “Yes”, “Y”, “1”.</p>
<p>These inconsistencies make analytics, grouping, and reporting unreliable, and the analyst will spend time cleaning and standardizing these files.</p>
<p>You should replace free‑text fields with dropdowns, radio buttons, and enums to enforce standardized categorical values.</p>
<p>Bad example of a structural error:</p>
<pre><code class="language-plaintext">&lt;form id="profile"&gt;
  &lt;label&gt;Country&lt;/label&gt;
  &lt;input type="text" id="country" placeholder="Enter country"&gt;
  &lt;button type="submit"&gt;Save&lt;/button&gt;
&lt;/form&gt;

&lt;script&gt;
document.getElementById("profile").addEventListener("submit", e =&gt; {
  e.preventDefault();
  const country = document.getElementById("country").value;
  console.log("Saving:", country);
});
&lt;/script&gt;
</code></pre>
<p>The problem with this code is that it pretends to save a country value without doing any real validation or enforcing any rules, which makes the form unreliable and prone to bad data.</p>
<p>The form uses a plain text input for “country,” meaning the user can type anything they want — misspellings, random characters, invalid countries, or even leave it blank. Because the input isn’t marked as required and the JavaScript doesn’t check whether the field contains a meaningful value, the form will happily “save” an empty string or nonsense text.</p>
<p>The <code>submit</code> handler prevents the default form submission but does nothing beyond logging whatever the user typed, so the system accepts invalid, incomplete, or malformed data without question. In short, the code collects input but doesn't validate it, doesn't enforce correctness, and doesn't protect the system from bad or unusable values.</p>
<p>Here's the fixed version:</p>
<pre><code class="language-plaintext">&lt;form id="profile"&gt;
  &lt;label&gt;Country&lt;/label&gt;
  &lt;select id="country" required&gt;
    &lt;option value=""&gt;Select country&lt;/option&gt;
    &lt;option value="uk"&gt;United Kingdom&lt;/option&gt;
    &lt;option value="usa"&gt;United States&lt;/option&gt;
    &lt;option value="canada"&gt;Canada&lt;/option&gt;
  &lt;/select&gt;

  &lt;button type="submit"&gt;Save&lt;/button&gt;
&lt;/form&gt;

&lt;script&gt;
document.getElementById("profile").addEventListener("submit", e =&gt; {
  e.preventDefault();

  const country = document.getElementById("country").value;

  // Required validation
  if (!country) {
    alert("Please select a country before saving.");
    return;
  }

  console.log("Saving:", country);
});
&lt;/script&gt;
</code></pre>
<p>The biggest improvement is that we're no longer relying on a free‑text field for the country. By switching to a dropdown, the form now limits the user to a controlled set of valid options. This prevents misspellings, random text, or invalid country names from ever entering the system.</p>
<p>These are the main types of data errors you might come across in your work. Now that we've discussed what causes them and some key fixes/preventative measures you can take, let's move on to data quality itself.</p>
<h2 id="heading-what-makes-good-data">What Makes Good Data?</h2>
<p>So what, in fact, is data quality? <a href="https://www.ibm.com/products/tutorials/6-pillars-of-data-quality-and-how-to-improve-your-data">IBM defines it</a> as the degree of accuracy, consistency, completeness, reliability, and relevance of the data collected, stored, and used within an organization or a specific context.</p>
<p>Let's look at each of these features of quality data a bit more closely to understand what they entail.</p>
<h3 id="heading-completeness">Completeness:</h3>
<p>Completeness measures how much of the required data is actually present. When large portions of fields are missing, the dataset stops representing reality and any analysis built on it becomes unreliable.</p>
<p>An example would be a sign‑up form that stores users, but half of them are missing an email address. If you run an analysis on “email engagement,” your results will be skewed because a big chunk of users can’t even receive emails. This means that this data is incomplete.</p>
<h3 id="heading-uniqueness">Uniqueness:</h3>
<p>Uniqueness checks whether each real‑world entity appears only once in the dataset. Duplicate records inflate counts, break joins, and distort metrics.</p>
<p>An example would be a customer table containing two rows for the same person with the same customer ID. When calculating “active customers,” the system counts them twice, inflating revenue projections.</p>
<h3 id="heading-validity">Validity:</h3>
<p>Validity evaluates whether data follows the expected format, type, or business rules. This includes correct data types, allowed ranges, and patterns defined by the system.</p>
<p>An example would be a field meant to store dates contains values like “32/99/2025” or “tomorrow.” These invalid entries break downstream ETL jobs that expect a proper date format.</p>
<h3 id="heading-timeliness">Timeliness:</h3>
<p>Timeliness reflects whether data is available when it’s needed. Even accurate data becomes useless if it arrives too late for the process that depends on it. For example, after a customer places an order, the system should generate an order ID instantly.</p>
<h3 id="heading-accuracy">Accuracy:</h3>
<p>Accuracy measures how closely data matches the real‑world truth. When multiple systems report the same metric, one must be designated as the authoritative source to avoid conflicting values.</p>
<h3 id="heading-consistency">Consistency:</h3>
<p>Consistency checks whether data aligns across different datasets or within related fields. If two systems describe the same concept, their values shouldn't contradict each other.</p>
<p>For example, a company’s HR system reports 50 employees in Engineering, but the payroll system lists only 42. Since both describe the same group, the mismatch signals a data quality issue.</p>
<h3 id="heading-fitness-for-purpose">Fitness for Purpose:</h3>
<p>Fitness for purpose assesses whether the data is suitable for the specific business task at hand. Even complete, accurate, and timely data may be unhelpful if it doesn’t answer the intended question.</p>
<p>A dataset of website clicks might be perfect for analysing user engagement, for example, but it’s useless for forecasting revenue because it contains no purchase or pricing information.</p>
<h2 id="heading-data-validation-layers">Data Validation Layers</h2>
<p>Now that we've highlighted the characteristics that ensure quality data, it's important to discuss the layers of data validation.</p>
<p>There are five layers you'll need to check to enforce data quality.</p>
<h3 id="heading-frontend-layer-protect-the-user-not-the-system">Frontend Layer — “Protect the User, Not the System”</h3>
<p>Frontend validation plays an important role in enhancing the user experience – but it doesn't provide real protection for a system.</p>
<p>Since frontend logic operates within the user’s environment, we can't trust it as a mechanism for enforcing data quality. Any code executed in the browser is ultimately under the user’s control, meaning it can be disabled, modified, intercepted, or bypassed entirely.</p>
<p>For instance, a user can simply open browser developer tools, remove validation rules, and submit invalid or malicious data without restriction.</p>
<p>Frontend validation is incapable of enforcing complex business rules. Constraints such as ensuring that a discounted price is lower than the original price, validating that a start date precedes an end date, preventing stock levels from becoming negative, or confirming that a product belongs to a valid category within the database require deeper system-level checks.</p>
<p>At the frontend level, what is being validated is: required fields, email format, password strength, address fields, and payment input format.</p>
<p>So frontend validation doesn't guarantee data quality or security, as it can be bypassed through API tools (like Postman), disabled JavaScript, malicious bots, and third-party integrations.</p>
<p>Because of this, it's best to treat the front-end as a usability layer, not a trust layer.</p>
<h3 id="heading-backend-validation-the-real-gatekeeper">Backend Validation — “The Real Gatekeeper”</h3>
<p>You can only guarantee true data quality and system integrity at the backend and database layers.</p>
<p>The backend is responsible for enforcing request validation, implementing business logic, and managing authentication and authorization.</p>
<p>If validation fails here, invalid data is rejected before it can propagate. Without this layer, data corruption begins at ingestion.</p>
<p>For example:</p>
<pre><code class="language-plaintext">$request-&gt;validate([
   'name' =&gt; 'required|string|max:255',
   'price' =&gt; 'required|numeric|min:0',
   'stock' =&gt; 'required|integer|min:0',
   'category_id' =&gt; 'required|exists:categories,id',
]);
</code></pre>
<p>The code snippet above demonstrates how you can use request validation in Laravel to ensure that incoming data meets specific requirements before it's processed or stored in the database. This is an essential practice in web development, as it helps maintain data integrity, prevents errors, and enhances application security.</p>
<p>In this example, we're using the <code>$request-&gt;validate()</code> method to define a set of validation rules for four input fields: <code>name</code>, <code>price</code>, <code>stock</code>, and <code>category_id</code>. Each field is assigned a series of constraints that the incoming data must satisfy.</p>
<p>The name field is marked as required, meaning it must be included in the request and can't be empty. It must also be a string, ensuring that only textual data is accepted, and it's limited to a maximum length of 255 characters using <code>max:255</code>. This prevents excessively long inputs that could potentially cause issues in the database or user interface.</p>
<p>Similarly, the price field is required and must be numeric, allowing only numbers such as integers or decimal values. The rule <code>min:0</code> ensures that the price can't be negative, which is logically consistent for most product pricing scenarios.</p>
<p>The stock field is also required and must be an integer, meaning it can only accept whole numbers. This is appropriate for counting physical items. Like the price field, it includes a <code>min:0</code> rule to prevent negative stock values, which would not make sense in an inventory system.</p>
<p>Finally, the category_id field is validated to ensure it is both present and valid. The <code>required</code> rule ensures that a category is selected, while the <code>exists:categories,id</code> rule checks that the provided value corresponds to an existing id in the categories database table. This prevents invalid or non-existent category references, thereby preserving relational integrity within the database.</p>
<p>This layer validates null values, data types and formats, allowed ranges, and referential integrity (exists).</p>
<h3 id="heading-database-layer-protect-the-data-at-rest">Database Layer — “Protect the Data at Rest”</h3>
<p>Validation at the application level is insufficient on its own. You'll also need to enforce database-level constraints like NOT NULL constraints, UNIQUE constraints (email, SKU, order number), foreign keys (orders.user_id → users.id), and check constraints (for example, price &gt;= 0).</p>
<p>This layer is critical because application bugs may bypass validation, background jobs and imports may skip controllers, and malicious actors may attempt direct access.</p>
<p>The database layer acts as the final line of defense, ensuring structural integrity regardless of application failures. Database constraints are the last hard stop: they enforce correctness even when code is bypassed.</p>
<h3 id="heading-service-layer-business-logic-validate-real-world-rules">Service Layer / Business Logic — “Validate Real-World Rules”</h3>
<p>This layer enforces domain-specific logic that can't be captured by simple validation rules. The service layer is where the application stops asking “Is this data shaped correctly?” and starts asking “Is this allowed to happen in the real world?”.</p>
<p>This layer enforces domain‑specific rules that can't be captured by simple request validation or database constraints. These rules reflect business truth, not structural correctness.</p>
<p><strong>Example:</strong></p>
<pre><code class="language-plaintext">if (\(product-&gt;stock &lt; \)quantity) {
   throw new OutOfStockException();
}
</code></pre>
<p>This prevents overselling and ensures the system reflects physical reality.</p>
<pre><code class="language-plaintext">if (\(cartTotal !== \)calculatedTotal) {
   throw new PriceMismatchException();
}
</code></pre>
<p>This protects revenue and prevents tampering.</p>
<p>In this layer, you enforce real‑world business rules by ensuring inventory correctness, recalculating totals, applying discount logic, and checking user‑specific limits.</p>
<h3 id="heading-jobs-queues-data-ingestion-validate-external-data">Jobs / Queues / Data Ingestion — “Validate External Data”</h3>
<p>When importing or processing external data (for example, supplier feeds), validation must occur before processing. You'll need to ensure schema conformity, that the required columns are present, that you have the correct data types, that the JSON structure is valid, and that you're detecting duplicate batches.</p>
<p>This is because external data sources are a major source of data quality issues. Without validation here, corrupted data can silently enter the system at scale.</p>
<p>Now that we've discussed the layers of a modern application stack, it should be clear that data quality isn't something you “check once” at the UI.</p>
<p>It must be enforced repeatedly, at multiple depths of the system. Each layer catches a different class of defects, and together they form a defensive wall that prevents bad data from ever reaching storage, analytics, or downstream consumers.</p>
<h2 id="heading-testing-strategies-to-protect-data-quality">Testing Strategies to Protect Data Quality</h2>
<p>To wrap up, here are the three foundational testing strategy every developer should apply to protect data quality.</p>
<h3 id="heading-unit-testing">Unit Testing</h3>
<p>Unit tests are the first line of defense in data quality. In this context, a “unit” refers to a single column, a single transformation, or a single validation rule.</p>
<p>The purpose is straightforward: verify that the smallest building blocks of your data logic behave exactly as intended. This matters because if these low‑level rules are not tested and validated, incorrect or inconsistent data will flow into the database and contaminate everything built on top of it.</p>
<p>By isolating each rule or transformation, you can guarantee that schema constraints, field‑level assumptions, and low‑level logic remain correct before data ever flows into larger pipelines or business processes.</p>
<p>Typical questions answered at this layer include:</p>
<ol>
<li><p>Does this column allow nulls?</p>
</li>
<li><p>Does this regex correctly strip whitespace from email strings?</p>
</li>
<li><p>Does this transformation produce the expected output for a single row?</p>
</li>
</ol>
<p>This is where you can verify that the data contract is sound. If a column must be non‑null, unique, or follow a specific pattern, the unit test enforces it. When these rules fail here, they fail cheaply – before they can corrupt a table or mislead a dashboard.</p>
<p>To make this concrete, here’s what a unit test looks like in a real codebase. Even though this example comes from Laravel, the testing principle is identical to data‑quality unit tests: one rule, one expectation, isolated from everything else.</p>
<h4 id="heading-example-testing-a-discount-calculation-rule">Example: Testing a Discount Calculation Rule</h4>
<p>Imagine your e‑commerce shop has this rule:</p>
<ul>
<li><p>If a product costs more than £100, apply a 10% discount.</p>
</li>
<li><p>Otherwise, apply no discount.</p>
</li>
</ul>
<p>Let's say this is your discount logic:</p>
<pre><code class="language-plaintext">&lt;?php

namespace App\Services;

class DiscountService
{
    public function calculate(float $price): float
    {
        if ($price &gt; 100) {
            return $price * 0.10; // 10% discount
        }

        return 0;
    }
}
</code></pre>
<p>The unit test for this logic will be:</p>
<pre><code class="language-plaintext">&lt;?php

namespace Tests\Unit;

use Tests\TestCase;
use App\Services\DiscountService;

class DiscountServiceTest extends TestCase
{
    /** @test */
    public function it_applies_10_percent_discount_when_price_is_above_100()
    {
        $service = new DiscountService();

        \(discount = \)service-&gt;calculate(200);

        \(this-&gt;assertEquals(20, \)discount);
    }

    /** @test */
    public function it_applies_no_discount_when_price_is_100_or_below()
    {
        $service = new DiscountService();

        \(discount = \)service-&gt;calculate(100);

        \(this-&gt;assertEquals(0, \)discount);
    }
}
</code></pre>
<p>The <code>DiscountService</code> contains a simple rule: if a price is greater than 100, a 10% discount is applied. Otherwise, no discount is applied. The unit test verifies this rule in isolation, without involving controllers, databases, or HTTP requests. By testing the service directly, the developer ensures that the core calculation behaves exactly as intended.</p>
<p>The first test checks the positive case — a price of 200 should produce a discount of 20. The second test checks the boundary condition — a price of 100 should produce no discount. Together, these tests confirm both sides of the rule and protect against regressions if the logic changes in the future.</p>
<p>Now, since this is Laravel example, Laravel tests help you verify both your logic (unit tests) and your full application behaviour (feature tests). You can run them using <code>php artisan test</code>, which executes tests in a separate testing environment, ensuring your real database and main codebase remain safe and unaffected.</p>
<h3 id="heading-integration-testing-the-flow-amp-lineage-check">Integration Testing: The Flow &amp; Lineage Check</h3>
<p>While unit tests validate the correctness of individual rules, integration tests validate the movement of data across components. Integration testing verifies that multiple layers work together as a single data flow.</p>
<p>In this example, the controller receives an order, calls the discount service, applies the transformation, and persists the result to the database. That interaction across layers is what elevates this from a unit test to an integration test. This is where you test the real‑world flow:</p>
<ol>
<li><p>Controller → Service → Repository → MySQL</p>
</li>
<li><p>Check if MySQL migrations run correctly</p>
</li>
<li><p>Check foreign keys enforce relationships</p>
</li>
<li><p>Check to ensure services interact with the database as expected</p>
</li>
<li><p>Check to ensure models and repositories behave consistently</p>
</li>
</ol>
<p>Integration tests reveal issues that only appear when components interact: incorrect joins, broken migrations, mismatched field names, or subtle type mismatches that unit tests cannot detect.</p>
<p>This is the layer where you catch the bugs that would otherwise silently corrupt data lineage.</p>
<p><strong>Here's an example:</strong></p>
<pre><code class="language-plaintext">&lt;?php

namespace Tests\Feature;

use Tests\TestCase;
use App\Models\Order;
use Illuminate\Foundation\Testing\RefreshDatabase;

class ApplyDiscountTest extends TestCase
{
    use RefreshDatabase;

    /** @test */
    public function check_it_persists_the_correct_discounted_total_to_the_database()
    {
        $order = Order::factory()-&gt;create(['subtotal' =&gt; 150]);

        \(response = \)this-&gt;postJson("/orders/{$order-&gt;id}/apply-discount");

        $response-&gt;assertStatus(200);

        $this-&gt;assertDatabaseHas('orders', [
            'id' =&gt; $order-&gt;id,
            'grand_total' =&gt; 135, // 150 - 10% discount
            'discount_total' =&gt; 15
        ]);
    }
}
</code></pre>
<p>This represents a full flow rather than a single rule:</p>
<ul>
<li><p>Controller → Service</p>
</li>
<li><p>Service → Calculation</p>
</li>
<li><p>Controller → Database write</p>
</li>
<li><p>Database → Final state</p>
</li>
</ul>
<p>This test begins by creating an order using an Eloquent factory. It immediately steps beyond the boundaries of a unit test, since it interacts with the database and relies on Laravel’s model layer to persist real data.</p>
<p>From there, the test sends an actual HTTP POST request to the <code>/orders/{id}/apply-discount</code> endpoint, which means it's not calling a method directly, but instead it's traveling through Laravel’s routing layer, invoking the controller responsible for handling the request, and triggering whatever business logic is responsible for calculating and applying the discount.</p>
<p>This movement through multiple layers (routing, controller, service logic, and model persistence) is precisely what defines integration testing: the goal is to verify that these components work together correctly as a system.</p>
<p>Once the request is processed, the test asserts that the response returns a successful status code, which confirms that the HTTP layer behaved as expected.</p>
<p>But the most important part comes afterward, when the test checks the database to ensure that the correct <code>grand_total</code> and <code>discount_total</code> were saved. This final assertion proves that the discount logic was executed, the model was updated, and the changes were successfully written to the database.</p>
<p>In other words, the test isn't merely checking whether a calculation is correct. It's also checking whether the entire pipeline –&nbsp;from receiving the request to updating the database –&nbsp;functions as a coherent whole.</p>
<h3 id="heading-functional-testing-the-business-rule-check">Functional Testing: The Business Rule Check</h3>
<p>Functional tests validate the entire user experience, from the moment a request enters the system to the moment a response is returned. This includes:</p>
<ul>
<li><p>HTTP requests</p>
</li>
<li><p>Controller logic</p>
</li>
<li><p>Validation rules</p>
</li>
<li><p>Service operations</p>
</li>
<li><p>Database writes</p>
</li>
<li><p>Redirects or rendered views</p>
</li>
</ul>
<p>This is where you test the business rules that govern real‑world behaviour:</p>
<p>“A student can't register for two exams at the same time.”</p>
<p>“A cart can't have negative quantities.”</p>
<p>“A user can't update their profile without a valid email.”</p>
<p>Functional tests ensure that the system behaves correctly from the perspective of the user and the business, not just the code.</p>
<h4 id="heading-heres-an-example-functional-test">Here's an example: Functional Test</h4>
<pre><code class="language-plaintext">&lt;?php

namespace Tests\Feature;

use Tests\TestCase;
use App\Models\Product;
use Illuminate\Foundation\Testing\RefreshDatabase;

class CartQuantityFunctionalTest extends TestCase
{
    use RefreshDatabase;

    /** @test */
    public function a_user_cannot_set_a_negative_cart_quantity()
    {
        // Arrange: create a product
        $product = Product::factory()-&gt;create(['price' =&gt; 40]);

        // Simulate existing cart
        $this-&gt;withSession([
            'cart' =&gt; [
                $product-&gt;id =&gt; ['quantity' =&gt; 2]
            ]
        ]);

        // Act: user tries to update quantity to a negative number
        \(response = \)this-&gt;post('/cart/update', [
            'product_id' =&gt; $product-&gt;id,
            'quantity' =&gt; -5
        ]);

        // Assert: system rejects invalid business behaviour
        $response-&gt;assertStatus(302); // redirect back with errors
        $response-&gt;assertSessionHasErrors(['quantity']);

        // Assert: cart remains unchanged (business rule preserved)
        \(this-&gt;assertEquals(2, session('cart')[\)product-&gt;id]['quantity']);
    }
}
</code></pre>
<p>The test begins by creating a realistic environment in which a user interacts with a shopping cart. This is essential for understanding the behaviour the system is meant to enforce.</p>
<p>First, it generates a real product in the database using a factory, giving the product a price so that it resembles an item a customer might genuinely add to their cart.</p>
<p>Once the product exists, the test manually seeds the session with a cart containing that product and a quantity of two. This simulates a user who has already added the item to their cart in a previous interaction, and it establishes the baseline state the system must preserve if the user attempts an invalid update.</p>
<p>With the environment prepared, the test then imitates a user action by sending a POST request to the <code>/cart/update</code> endpoint. Instead of calling a method directly, it uses Laravel’s HTTP layer to reproduce the exact behaviour of a browser submitting a form. The request includes the product ID and a deliberately invalid quantity of negative five.</p>
<p>This is the heart of the scenario: the user is attempting something that violates the business rules of the application, and the test is designed to confirm that the system responds appropriately.</p>
<p>Now, when the request is processed, the test expects the application to reject the input, redirect the user back, and attach validation errors to the session. The assertion that the response has a 302 status code and contains validation errors confirms that the validation layer is functioning correctly and that the controller is enforcing the rule that quantities can't be negative.</p>
<p>The final part of the test is where the business rule is truly verified. After the failed update attempt, the test inspects the session to ensure that the cart remains unchanged. This is crucial because rejecting invalid input is only half of the requirement: the system must also protect the integrity of the existing cart data.</p>
<p>Functional tests answer questions like:</p>
<ul>
<li><p>Does the system prevent invalid real‑world behaviour?</p>
</li>
<li><p>Does the user get the correct feedback?</p>
</li>
<li><p>Does the data remain consistent after the request?</p>
</li>
<li><p>Does the final output match the business expectation?</p>
</li>
</ul>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Data quality is never the result of a single check or a single team. It emerges from a disciplined, layered approach where each testing level catches a different category of defects.</p>
<p>Unit tests safeguard the smallest rules, integration tests validate the flow of data across components, and functional tests enforce the business logic that governs real‑world behaviour.</p>
<p>When these layers operate together, bad data has nowhere to hide. When they don’t, even a minor oversight can slip through the cracks and escalate into a costly downstream failure.</p>
<p>So as you can see, your role in data quality is fundamentally proactive, not reactive. By designing systems with validation, integrity, and monitoring in mind, you ensure that data flowing through the pipeline is accurate, timely, complete, unique, and fit for purpose – supporting reliable analytics, reporting, and intelligent systems.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What Makes Code Vulnerable – And How to Fix It ]]>
                </title>
                <description>
                    <![CDATA[ Writing code is relatively easy. But writing secure code is much harder. The truth is, most developers don’t realize their code is vulnerable until something breaks. Or, worse, until someone attacks it. So if you want secure code, you first have to k... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-makes-code-vulnerable-and-how-to-fix-it/</link>
                <guid isPermaLink="false">680679690b7357fefc92cf6b</guid>
                
                    <category>
                        <![CDATA[ #cybersecurity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vulnerability ]]>
                    </category>
                
                    <category>
                        <![CDATA[ coding ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Validation ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Mon, 21 Apr 2025 16:59:21 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1745251285687/7ce5aca0-1edc-49e4-879d-b5690cbb64ea.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Writing code is relatively easy. But writing secure code is much harder.</p>
<p>The truth is, most developers don’t realize their code is vulnerable until something breaks. Or, worse, until someone attacks it. So if you want secure code, you first have to know what bad code looks like.</p>
<p>In this tutorial, we’ll see 10 clear signs that your code might be vulnerable to attacks. And more importantly, how to fix it.</p>
<h3 id="heading-heres-what-well-cover">Here’s what we’ll cover:</h3>
<ul>
<li><p><a class="post-section-overview" href="#heading-1-hardcoded-credentials">1. Hardcoded Credentials</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-2-no-input-validation">2. No Input Validation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-3-poor-error-handling">3. Poor Error Handling</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-4-outdated-dependencies">4. Outdated Dependencies</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-5-no-authentication-or-weak-authentication">5. No Authentication or Weak Authentication</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-6-missing-authorization-checks">6. Missing Authorization Checks</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-7-exposed-sensitive-data-in-urls">7. Exposed Sensitive Data in URLs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-8-no-rate-limiting">8. No Rate Limiting</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-9-unsafe-file-uploads">9. Unsafe File Uploads</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-10-missing-https">10. Missing HTTPS</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-final-thoughts">Final Thoughts</a></p>
</li>
</ul>
<h2 id="heading-1-hardcoded-credentials"><strong>1. Hardcoded Credentials</strong></h2>
<p>This one is <em>everywhere</em>. Maybe you’ve seen it yourself – an API key sitting right there in the code. A database password written in plain text.</p>
<p>It looks like this:</p>
<pre><code class="lang-plaintext">DB_PASSWORD = "supersecret123"
API_KEY = "sk_test_abc123"
</code></pre>
<p>If this code leaks (and it will), attackers can do whatever they want. They can log into your systems, steal your data, or run up huge bills on cloud services – all without breaking a sweat.</p>
<p>And here’s the scary part: this kind of leak doesn’t just happen when your whole project gets hacked. It can happen when someone pushes code to GitHub and forgets to add <code>.env</code> to <code>.gitignore</code>. Boom – your secret keys are now public.</p>
<h3 id="heading-how-to-protect-against-it"><strong>How to Protect Against It</strong></h3>
<p>Never hardcode sensitive data like API keys, database passwords, or tokens. Instead, use environment variables.</p>
<p>These are hidden from the source code and can be safely managed per environment (dev, test, production). For example, a <code>.env</code> file imported into your codebase:</p>
<pre><code class="lang-plaintext">import os
db_password = os.getenv("DB_PASSWORD")
</code></pre>
<h2 id="heading-2-no-input-validation"><strong>2. No Input Validation</strong></h2>
<p>If you trust user input, you’re already in trouble. Attackers love sending weird stuff, like super long strings, funky characters, or unexpected formats.</p>
<p>Here’s what it looks like:</p>
<pre><code class="lang-plaintext">username = request.GET['username']
print("Hello " + username)
</code></pre>
<p>Now someone enters:</p>
<pre><code class="lang-plaintext">username=Robert'); DROP TABLE users; --
</code></pre>
<p><strong>Boom.</strong> You’ve just been SQL injected. Your database table? Gone.</p>
<p>Without validation, your app can break or even be hijacked. Bad input can lead to issues like SQL injection, cross-site scripting (XSS), and general bugs.</p>
<p>Basically, you’re giving attackers a blank check.</p>
<h3 id="heading-how-to-protect-against-it-1"><strong>How to Protect Against It</strong></h3>
<p>Make sure you validate all inputs. For example:</p>
<pre><code class="lang-plaintext">import re
email = request.GET.get('email')
if not re.match(r"[^@]+@[^@]+\.[^@]+", email):
    return "Invalid email format"
</code></pre>
<p>Use parameterized queries. Never build SQL strings from raw user input:</p>
<pre><code class="lang-plaintext">cursor.execute("SELECT * FROM users WHERE email = %s", (email,))
</code></pre>
<p>And use strict data types. Don’t just assume input is clean. Make it pass a test.Limit input length. No one needs a 5,000-character username.Escape special characters especially if you’re using input in HTML or SQL.</p>
<h2 id="heading-3-poor-error-handling"><strong>3. Poor Error Handling</strong></h2>
<p>This is what lazy error handling looks like:</p>
<pre><code class="lang-plaintext">except Exception as e:
    print(e)  # Exposes internal errors to the user
</code></pre>
<p>Or worse:</p>
<pre><code class="lang-plaintext">except:
    pass  # Silently swallows all errors
</code></pre>
<p>In the first example, the error is fully displayed to the user. The second example ignores all errors.</p>
<p>Silent errors are dangerous. And showing full error messages to users? That’s handing over a map to your system.</p>
<p>Imagine a database error pops up in production, and your app spits out something like:</p>
<pre><code class="lang-plaintext">psycopg2.OperationalError: could not connect to server: Connection refused
</code></pre>
<p>Great – now attackers know what database you’re using, and they might start poking around.</p>
<h3 id="heading-how-to-protect-against-it-2"><strong>How to Protect Against It</strong></h3>
<ul>
<li><p><strong>Log detailed errors</strong> – but do it securely. Use logging tools or services, and don’t store logs where users can see them.</p>
</li>
<li><p><strong>Show users simple messages</strong> like:<br>  <code>"Oops! Something went wrong. Please try again later."</code><br>  That’s all they need to know.</p>
</li>
<li><p><strong>Never expose stack traces in production.</strong> Turn off debug mode and use proper error pages.</p>
</li>
<li><p><strong>Handle specific exceptions</strong> where possible, so you know exactly what failed and why.</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="lang-plaintext">try:
    process_data()
except ValueError as e:
    logger.error(f"Data error: {e}")
    return "Invalid input. Please check your data."
except Exception as e:
    logger.exception("Unexpected error")
    return "Something went wrong. Try again later."
</code></pre>
<p>Use error monitoring tools like Sentry, Rollbar, or LogRocket. They catch errors, track them, and help you fix them – before users even notice.</p>
<h2 id="heading-4-outdated-dependencies"><strong>4. Outdated Dependencies</strong></h2>
<p>Using old packages is like leaving your front door wide open. Attackers know exactly where the weak spots are – and they actively scan for them.</p>
<p>If your <code>package.json</code> or <code>requirements.txt</code> file hasn’t changed in years, that’s a red flag.</p>
<h3 id="heading-how-to-protect-against-it-3"><strong>How to Protect Against It</strong></h3>
<ul>
<li><p><strong>Update regularly.</strong> New versions often patch security flaws.</p>
</li>
<li><p><strong>Audit your dependencies.</strong> Use tools like <code>npm audit</code> and <code>pip-audit</code> based on your codebase.</p>
</li>
<li><p><strong>Automate updates</strong> with tools like Dependabot, Renovate, or PyUp.</p>
</li>
</ul>
<pre><code class="lang-plaintext">pip-audit
# or
npm audit
</code></pre>
<p>Even small packages can have big impacts. Stay updated, stay safe.</p>
<h2 id="heading-5-no-authentication-or-weak-authentication"><strong>5. No Authentication or Weak Authentication</strong></h2>
<p>If your app lets anyone in without verifying who they are, that’s game over. Weak logins are just as dangerous.</p>
<p>Common mistakes include:</p>
<ul>
<li><p><strong>No password complexity rules</strong> – Weak passwords like “123456” or “password” can be cracked in seconds using brute-force or dictionary attacks.</p>
</li>
<li><p><strong>Storing passwords in plain text</strong> – If your database is ever breached, all user credentials are exposed instantly, leading to massive data leaks and account takeovers.</p>
</li>
<li><p><strong>No account lockout after repeated failed logins</strong> – Without a limit on login attempts, attackers can keep guessing passwords endlessly using automated tools.</p>
</li>
</ul>
<h3 id="heading-how-to-protect-against-it-4"><strong>How to Protect Against It</strong></h3>
<p>First, you can hash passwords using strong algorithms like <code>bcrypt</code>.</p>
<p>Here’s an example in Python:</p>
<pre><code class="lang-plaintext">import bcrypt
hashed = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
</code></pre>
<p>You can also enforce strong password policies (min length, symbols, and so on) and use multi-factor authentication (MFA) if available for extra protection.</p>
<p>A few extra lines of code can stop a full-blown breach.</p>
<h2 id="heading-6-missing-authorization-checks"><strong>6. Missing Authorization Checks</strong></h2>
<p>Authentication checks <em>who you are</em>. Authorization checks <em>what you can do</em>. Skipping the second one is like giving everyone admin access.</p>
<p>Example:</p>
<pre><code class="lang-plaintext">@app.route('/user/&lt;id&gt;')
def get_user(id):
    return User.query.get(id)
</code></pre>
<p>Here, there’s no check to see if the current user is allowed to view that data.</p>
<h3 id="heading-how-to-protect-against-it-5"><strong>How to Protect Against It</strong></h3>
<pre><code class="lang-plaintext">@app.route('/user/&lt;id&gt;')
@login_required
def get_user(id):
    if current_user.id != int(id):
        return "Unauthorized", 403
    return User.query.get(id)
</code></pre>
<p>In the above code, a login is required and the user is verified before giving them access to the data.</p>
<ul>
<li><p>Always verify ownership and roles before showing or modifying data.</p>
</li>
<li><p>Implement access control rules across your API and frontend.</p>
</li>
<li><p>Don’t trust IDs from the frontend – verify on the backend too.</p>
</li>
</ul>
<h2 id="heading-7-exposed-sensitive-data-in-urls"><strong>7. Exposed Sensitive Data in URLs</strong></h2>
<p>Ever seen a password reset link like this?</p>
<pre><code class="lang-plaintext">https://example.com/reset-password?token=abcd1234
</code></pre>
<p>Looks harmless – but it’s not. Tokens, session IDs, and API keys <strong>should never be in URLs</strong>. They get saved in:</p>
<ul>
<li><p>Browser history</p>
</li>
<li><p>Server logs</p>
</li>
<li><p>Analytics tools</p>
</li>
</ul>
<h3 id="heading-how-to-protect-against-it-6"><strong>How to Protect Against It</strong></h3>
<p>Make sure you only send sensitive data in POST requests or headers, like this:</p>
<pre><code class="lang-plaintext">POST /reset-password
Authorization: Bearer abcd1234
</code></pre>
<h2 id="heading-8-no-rate-limiting"><strong>8. No Rate Limiting</strong></h2>
<p>Rate limiting is a security technique that controls how many times a user (or system) can make a request to your server within a given time frame – for example, no more than 10 login attempts per minute.</p>
<p>Without rate limits,</p>
<ul>
<li><p>An attacker can make 1,000 login attempts in a minute</p>
</li>
<li><p>Your server may crash under fake requests</p>
</li>
</ul>
<h3 id="heading-how-to-protect-against-it-7"><strong>How to Protect Against It</strong></h3>
<p>Set a max request limit per IP or user. You can use tools like Cloudflare or inbuilt tools in programming languages to do this. For example, in Python, we can use flask_limiter.</p>
<pre><code class="lang-plaintext">from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

limiter = Limiter(app, key_func=get_remote_address)

@app.route("/login")
@limiter.limit("5 per minute")
def login():
    # login logic
</code></pre>
<p>In the above code, the login attempts are limited to 5 per minute. Stop abuse before it starts.</p>
<h2 id="heading-9-unsafe-file-uploads"><strong>9. Unsafe File Uploads</strong></h2>
<p>Letting users upload files? Cool. But if you’re not careful, they can:</p>
<ul>
<li><p>Upload malware</p>
</li>
<li><p>Overwrite key files</p>
</li>
<li><p>Execute scripts on your server</p>
</li>
</ul>
<p>Here’s an example of a common mistake:</p>
<pre><code class="lang-plaintext">file. Save(f"/uploads/{file.filename}")
</code></pre>
<p>Any type of file could be uploaded this way.</p>
<h3 id="heading-how-to-protect-against-it-8"><strong>How to Protect Against It</strong></h3>
<p>To start, you can rename files before saving:</p>
<pre><code class="lang-plaintext">pythonCopyEditimport uuid
filename = str(uuid.uuid4()) + ".jpg"
</code></pre>
<p>You can check content type (not just file extension):</p>
<pre><code class="lang-plaintext">pythonCopyEditif file.content_type not in ["image/jpeg", "image/png"]:
    return "Invalid file type"
</code></pre>
<p>You also can store files outside public directory, and finally limit file size in your server config and backend code</p>
<h2 id="heading-10-missing-https"><strong>10. Missing HTTPS</strong></h2>
<p>If your app still uses plain old HTTP, all data travels in the open – including:</p>
<ul>
<li><p>Passwords</p>
</li>
<li><p>Tokens</p>
</li>
<li><p>Personal info</p>
</li>
</ul>
<p>Attackers can sniff it all with tools like <a target="_blank" href="https://www.freecodecamp.org/news/learn-wireshark-computer-networking/">Wireshark</a>.</p>
<h3 id="heading-how-to-protect-against-it-9"><strong>How to Protect Against It</strong></h3>
<p>To start, you can use HTTPS everywhere and get a free SSL cert from <a target="_blank" href="https://letsencrypt.org/">Let’s Encrypt</a>.</p>
<p>You can also redirect insecure traffic – here’s how you’d do it in Flask, for example:</p>
<pre><code class="lang-plaintext">@app.before_request
def before_request():
    if not request.is_secure:
        return redirect(request.url.replace("http://", "https://"))
</code></pre>
<p>Encrypting traffic is not optional – it’s table stakes for modern apps.</p>
<h2 id="heading-final-thoughts"><strong>Final Thoughts</strong></h2>
<p>Writing secure code isn’t about being perfect. It’s about being careful. Slow down. Look at your code with fresh eyes. Think like an attacker. Plan for failure before it happens.</p>
<p>The best security isn’t patched in later – it’s baked in from the start.</p>
<p>For more cybersecurity tutorials, <a target="_blank" href="https://newsletter.stealthsecurity.sh/">join my newsletter</a>. New to cybersecurity? Check out my <a target="_blank" href="https://start.stealthsecurity.sh/">Security Starter Course</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Prevent Web API Attacks with Data Validation – Web API Security Guide ]]>
                </title>
                <description>
                    <![CDATA[ Adequate data protection and user confidentiality are key responsibilities for web developers. Hence, it is important to ensure the highest possible security while building API endpoints. The act of application security is a shared responsibility amo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/web-api-security-guide/</link>
                <guid isPermaLink="false">66bb58d7965d5c9ed5487ba4</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Validation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Security ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwatobi ]]>
                </dc:creator>
                <pubDate>Wed, 03 Apr 2024 09:13:45 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/apidat.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Adequate data protection and user confidentiality are key responsibilities for web developers. Hence, it is important to ensure the highest possible security while building API endpoints.</p>
<p>The act of application security is a shared responsibility amongst the client and server developers and negligence of one’s role can be disastrous. <a target="_blank" href="https://www.statista.com/statistics/1307426/number-of-data-breaches-worldwide/#:~:text=During%20the%20fourth%20quarter%20of,concerns%20of%20company%20leaders%20worldwide.">Statistics</a> show that data breaches in 2023 resulted in exposure of over 8 million data records worldwide.</p>
<p>In this article, I'll be highlighting key areas of API security, which involves data validation.  This concept is quite crucial in helping you protect your API from web attacks via malicious user data. This tutorial is well-suited for all backend developers regardless of years of experience.</p>
<p>To be able to follow this tutorial, here are some prerequisites:</p>
<ul>
<li>Knowledge of Node.js</li>
<li>Knowledge of npm and package installation</li>
</ul>
<p>With that in place, let’s get started.</p>
<h2 id="heading-how-does-data-validation-work">How Does Data Validation Work?</h2>
<p>First of all, what is data validation? Data validation simply entails ensuring the accuracy and reliability of the data received from external sources before onward data processing. </p>
<p>It is a key component of web API security as it is essential for preventing the occurrence of web injection attacks, SQL attacks and NoSQL attacks. To know more about these, you can check this <a target="_blank" href="https://owasp.org/www-community/Injection_Flaws#:~:text=Description,connected%20to%20the%20vulnerable%20application.">link</a>.</p>
<p>Note that data validation is needed but not limited to the following backend operations.:</p>
<ul>
<li>User login and sign up</li>
<li>Response query</li>
<li>Updating server databases</li>
</ul>
<p>All these can be used as avenues by mischievous black hat hackers to gain access to the server database and obtain sensitive user details or even wreak havoc by formatting the entire database.</p>
<h2 id="heading-popular-data-validation-tools">Popular Data Validation Tools</h2>
<p>So far, there are lot of tools that can help the programmer achieve efficient data validation in API development. </p>
<p>They help you avoid reinventing the wheel of using long regex code to validate data. They provide a whole lot of features, including error handling and validation customization functionalities.  </p>
<p>Some of these tools include:<br>•    <a target="_blank" href="https://joi.dev">Joi</a><br>•    <a target="_blank" href="https://zod.dev/">Zod</a><br>•    <a target="_blank" href="https://www.npmjs.com/package/yup">Yup</a><br>•    <a target="_blank" href="https://ajv.js.org/">AJv</a><br>•    <a target="_blank" href="https://valibot.dev/">Valibot</a><br>•    <a target="_blank" href="https://www.npmjs.com/package/validatorjs">Validator.js</a><br>•    <a target="_blank" href="https://docs.superstructjs.org/guides/02-validating-data">Superstruct</a></p>
<p>To further shed light on these tools, we'll compare some of the most popular data validation tools mentioned above.</p>
<h2 id="heading-pros-and-cons-of-data-validation-tools">Pros and Cons of Data Validation Tools</h2>
<p>To further enlighten you about these JavaScript validation tools, I will be highlighting some pros and cons of three of these popular JavaScript validation tools.</p>
<h3 id="heading-joi">Joi</h3>
<h6 id="heading-pros">Pros</h6>
<ul>
<li>It has a strong, large user community and development support</li>
<li>It has built-in capabilities to handle complex validations</li>
</ul>
<h6 id="heading-cons">Cons</h6>
<ul>
<li>It’s syntax is quite verbose</li>
</ul>
<h3 id="heading-zod">Zod</h3>
<h6 id="heading-pros-1">Pros</h6>
<ul>
<li>It is easily compatible with Typescript projects</li>
<li>It has efficient error-handling capabilities</li>
</ul>
<h6 id="heading-cons-1">Cons</h6>
<ul>
<li>Async validation isn’t supported.</li>
</ul>
<h3 id="heading-yup">Yup</h3>
<h6 id="heading-pros-2">Pros</h6>
<ul>
<li>It mainly uses declarative syntax to set its validation tool which confers its simplicity</li>
<li>It has a comparable fast performance.</li>
</ul>
<h6 id="heading-cons-2">Cons</h6>
<ul>
<li>It doesn’t provide customization features</li>
<li>It has limited ability to handle complex validations</li>
</ul>
<p>For the purpose of this tutorial, we'll use Joi as our data validation tool.</p>
<h2 id="heading-introduction-to-joi">Introduction to Joi</h2>
<p>Joi is a simple and efficient JavaScript-based data validation tool that is based on the schema-type configuration.</p>
<p>It has built-in capabilities for validating the occurrence of data in various forms, but not limited to Booleans, strings, functions and intervals. It can also handle complex validation operations.</p>
<p>Additionally, it provides minimal caching functionalities. More information about the tool can be found <a target="_blank" href="https://joi.dev/api/?v=17.12.2">here</a>.</p>
<h2 id="heading-how-to-set-up-joi">How to Set Up Joi</h2>
<p>In this section, we'll set up Joi in our local environment. To install Joi, navigate to the code folder via the command line and run this:</p>
<pre><code class="lang-bash">npm i joi
</code></pre>
<p>A message confirming successful installation should be displayed. With that completed, we can demonstrate the power of Joi in validating user registration in our demo API.</p>
<h2 id="heading-demo-project">Demo Project</h2>
<p>In this project, you'll use Joi to validate the input received from the client with the intent to sign up on the server. The default code for the user sign-up function for the Node.js application can be found <a target="_blank" href="https://github.com/oluwatobi2001/location-backend/blob/master/Controller/Authentication.js">here</a>.</p>
<p>Go on and import the installed Joi package into your code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> Joi = <span class="hljs-built_in">require</span>(<span class="hljs-string">"joi"</span>);
</code></pre>
<p>Before writing our signup controller, we'll initialize the Joi library within the code file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> SignUpSchema = Joi.object({});
</code></pre>
<p>In this project, we'll validate the email, password and username parameters received from the client.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> SignUpSchema = Joi.object({
    <span class="hljs-attr">email</span>: Joi.string().email({
        <span class="hljs-attr">minDomainSegments</span>: <span class="hljs-number">2</span>,
        <span class="hljs-attr">tlds</span>: {
            <span class="hljs-attr">allow</span>: [<span class="hljs-string">'com'</span>, <span class="hljs-string">'net'</span>]
        }
    }),
    <span class="hljs-attr">username</span>: Joi.string().alphanum().min(<span class="hljs-number">3</span>).max(<span class="hljs-number">15</span>).required(),
    <span class="hljs-attr">password</span>: Joi.string().min(<span class="hljs-number">8</span>).required()
});
</code></pre>
<p>The email parameter object ensures that the email address is a string, and the domain site is limited to .com and .net, disallowing other forms of domains.</p>
<p>For the username parameter, it ensures that it is a string containing both letters and numbers with a minimum character count of 3 and a maximum character count of 15. The required function ensures that these conditions must be met or the entire request won't be validated.</p>
<p>The password parameter ensures that the password supplied is in a string format with a minimum character count of 8, and it is also required.</p>
<p>To apply it to our endpoints, we include this within the controller function:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { error, value } = SignUpSchema.validate(req.body, { <span class="hljs-attr">abortEarly</span>: <span class="hljs-literal">false</span> });
<span class="hljs-keyword">if</span> (error) {
    res.status(<span class="hljs-number">400</span>).json(error.details);
    <span class="hljs-keyword">return</span>;
}
</code></pre>
<p>This function gets executed before inserting the user details into the database. The schema tries to validate the received input and then proceeds to the database if successfully validated.</p>
<p>The <code>abortEarly</code> feature is included to allow for all parameters to be assessed. All the errors will be displayed if there is any.</p>
<p>The above can also be replicated in the Login controller function. You can also check out the <a target="_blank" href="https://joi.dev/api/?v=17.12.2">documentation</a> for other examples of complex validation options using Joi.</p>
<p>The final code for the project is displayed below:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> jwt = <span class="hljs-built_in">require</span>(<span class="hljs-string">"jsonwebtoken"</span>);
<span class="hljs-keyword">const</span> userSchema = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../Schema/User"</span>);
<span class="hljs-keyword">const</span> Joi = <span class="hljs-built_in">require</span>(<span class="hljs-string">"joi"</span>);
<span class="hljs-keyword">const</span> bcrypt = <span class="hljs-built_in">require</span>(<span class="hljs-string">"bcrypt"</span>);
<span class="hljs-keyword">const</span> { createNewColumn, checkRecordsExists, insertRecord } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../utils/sqlSchemaFunction'</span>);

<span class="hljs-keyword">const</span> generateAccessToken = <span class="hljs-function">(<span class="hljs-params">use</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> jwt.sign({ <span class="hljs-attr">userID</span>: use }, process.env.JWT, { <span class="hljs-attr">expiresIn</span>: <span class="hljs-string">"1d"</span> });
}

<span class="hljs-keyword">const</span> SignUpSchema = Joi.object({
    <span class="hljs-attr">email</span>: Joi.string().email({ <span class="hljs-attr">minDomainSegments</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">tlds</span>: { <span class="hljs-attr">allow</span>: [<span class="hljs-string">'com'</span>, <span class="hljs-string">'net'</span>] } }),
    <span class="hljs-attr">username</span>: Joi.string().alphanum().min(<span class="hljs-number">3</span>).max(<span class="hljs-number">15</span>).required(),
    <span class="hljs-attr">password</span>: Joi.string().min(<span class="hljs-number">8</span>).required()
});

<span class="hljs-keyword">const</span> loginSchema = Joi.object({
    <span class="hljs-attr">email</span>: Joi.string().email({ <span class="hljs-attr">minDomainSegments</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">tlds</span>: { <span class="hljs-attr">allow</span>: [<span class="hljs-string">'com'</span>, <span class="hljs-string">'net'</span>] } }),
    <span class="hljs-attr">password</span>: Joi.string().min(<span class="hljs-number">8</span>).required()
});

<span class="hljs-keyword">const</span> register = <span class="hljs-keyword">async</span> (req, res) =&gt; {
    <span class="hljs-keyword">const</span> email = req.body.email;
    <span class="hljs-keyword">const</span> password = req.body.password;

    <span class="hljs-keyword">if</span> (!email || !password) {
        res.status(<span class="hljs-number">400</span>).json(<span class="hljs-string">"Please supply the email or password"</span>);
        <span class="hljs-keyword">return</span>; 
    }

    <span class="hljs-keyword">const</span> { error, value } = SignUpSchema.validate(req.body, { <span class="hljs-attr">abortEarly</span>: <span class="hljs-literal">false</span> });
    <span class="hljs-keyword">if</span> (error) {
        res.status(<span class="hljs-number">400</span>).json(error.details);
        <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-keyword">const</span> salt = <span class="hljs-keyword">await</span> bcrypt.genSalt(<span class="hljs-number">10</span>);
    <span class="hljs-keyword">const</span> hashedPassword = <span class="hljs-keyword">await</span> bcrypt.hash(password, salt);
    <span class="hljs-keyword">const</span> user = {
        <span class="hljs-attr">username</span>: req.body.username,
        <span class="hljs-attr">email</span>: email,
        <span class="hljs-attr">password</span>: hashedPassword
    };

    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> userAlreadyExists = <span class="hljs-keyword">await</span> checkRecordsExists(<span class="hljs-string">"users"</span>, <span class="hljs-string">"email"</span>, email);
        <span class="hljs-keyword">if</span> (userAlreadyExists) {
            res.status(<span class="hljs-number">400</span>).json(<span class="hljs-string">"Email must be unique"</span>);
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">await</span> insertRecord(<span class="hljs-string">"users"</span>, user);
            res.status(<span class="hljs-number">200</span>).json(<span class="hljs-string">"User created successfully"</span>);
        }
    } <span class="hljs-keyword">catch</span> (err) {
        res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">err</span>: err.message });
    }
};

<span class="hljs-built_in">module</span>.exports = { register };
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/SUccessValid-1.JPG" alt="Image" width="600" height="400" loading="lazy">
<em>API testing in Postman</em></p>
<p>Ensuring that the code followed our defined schema resulted in it being successfully executed.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>With this, we have come to the end of the tutorial. I hope you’ve learned about data validation, various data validation tools and data validation best practices.</p>
<p>You can also reach out to me and check out my other articles <a target="_blank" href="https://www.freecodecamp.org/news/author/oluwatobi/">here</a>. Till next time, keep on coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Validate your Machine Learning Models Using TensorFlow Model Analysis ]]>
                </title>
                <description>
                    <![CDATA[ My first deployed Machine Learning model was a failure. It was a simple Diabetes Diagnosis Model for potential diabetes mellitus patients – and quite frankly, I was beyond excited on deployment.  But the excitement soon disappeared when I received fe... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-validate-machine-learning-models-with-tensorflow-model-analysis/</link>
                <guid isPermaLink="false">66ba2dd5c346e93df556affb</guid>
                
                    <category>
                        <![CDATA[ Machine Learning ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TensorFlow ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Validation ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Salim Oyinlola ]]>
                </dc:creator>
                <pubDate>Wed, 05 Oct 2022 14:37:09 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/10/pexels-pixabay-159275.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>My first deployed Machine Learning model was a failure. It was a simple Diabetes Diagnosis Model for potential diabetes mellitus patients – and quite frankly, I was beyond excited on deployment. </p>
<p>But the excitement soon disappeared when I received feedback from users. Simply put, the users felt the model was bad. </p>
<p>I was saddened by this, but looking back, they were correct. The model may have performed well in terms of top-level metrics. But from the perspective of the consumer, if a machine learning model provides a poor forecast, that person's experience with the model will be bad. </p>
<p>The issue was that specific model features, or slices of data, were causing the model to perform poorly. </p>
<p>In short, before deploying any machine learning model, the onus is on machine learning engineers to assess it, make sure it satisfies strict quality standards, and acts as predicted for all pertinent slices of data.</p>
<h2 id="heading-what-is-tensorflow-model-analysis">What is TensorFlow Model Analysis?</h2>
<p>To enable Machine Learning engineers to look at the performance of their models at a deeper level, Google created <a target="_blank" href="https://www.tensorflow.org/tfx/guide/tfma">TensorFlow Model Analysis (TFMA)</a>. According to the docs, "TFMA performs its computations in a distributed manner over large amounts of data using Apache Beam."</p>
<p>TFMA, as a tool, enables you to really dig into the model's performance and understand how it varies on different slices of data. It provides support for calculating metrics that were used at training time (that is built-in metrics) as well as metrics defined after the model was saved as part of the TFMA configuration settings. </p>
<p>In this tutorial, you will analyze and evaluate results on a previously trained machine learning model. The model you will use is trained for a <a target="_blank" href="https://github.com/tensorflow/tfx/tree/master/tfx/examples/chicago_taxi_pipeline">Chicago Taxi Example</a>, which uses the <a target="_blank" href="https://data.cityofchicago.org/Transportation/Taxi-Trips/wrvz-psew">Taxi Trips dataset</a> released by the city of Chicago. You can check out the full dataset <a target="_blank" href="https://bigquery.cloud.google.com/dataset/bigquery-public-data:chicago_taxi_trips">here</a>. </p>
<p>When you are done with this tutorial, you will be able to use Apache Beam to do a full pass over the specified evaluation dataset. Also, you will not only have a more accurate calculation of metrics, but you'll be able to scale up to massive evaluation datasets, since Beam pipelines can be run using distributed processing back-ends.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li>Fundamental knowledge of Apache Beam. The <a target="_blank" href="https://beam.apache.org/documentation/programming-guide/">Beam Programming Guide</a> is a great place to start.</li>
<li>Fundamental understanding of the workings of machine learning models. </li>
<li>A new Google Colab notebook to run the Python code in your Google Drive. You can set this up by following this <a target="_blank" href="https://www.freecodecamp.org/news/google-colaboratory-python-code-in-your-google-drive/">tutorial</a>.</li>
</ul>
<h2 id="heading-step-1-how-to-install-tensorflow-model-analysis-tfma">Step 1 – How to Install TensorFlow Model Analysis (TFMA)</h2>
<p>With your Google Colab notebook ready, the first thing to do is to pull in all the dependencies. This will take a while.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/image-23.png" alt="Image" width="600" height="400" loading="lazy">
<em>A blank (new) notebook in dark mode</em></p>
<p>Rename the file from <code>Untitled.ipynb</code> to <code>TFMA.ipynb</code>. </p>
<pre><code class="lang-python">!pip install -U pip
!pip install tensorflow-model-analysis`
</code></pre>
<p>The first line upgrades <code>pip</code> to the latest version. <code>pip</code> is the package management system used to install and manage software packages written in Python. It stands for “preferred installer program”. The second line will install TensorFlow Model Analysis, TFMA.  </p>
<p>Now, after that is done, restart the runtime before running the cells below. It is important to restart the runtime before running the cells.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/image-26.png" alt="Image" width="600" height="400" loading="lazy"></p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> sys
<span class="hljs-keyword">assert</span> sys.version_info.major==<span class="hljs-number">3</span> 
<span class="hljs-keyword">import</span> tensorflow <span class="hljs-keyword">as</span> tf
<span class="hljs-keyword">import</span> apache_beam <span class="hljs-keyword">as</span> beam
<span class="hljs-keyword">import</span> tensorflow_model_analysis <span class="hljs-keyword">as</span> tfma
</code></pre>
<p>This block of code imports the needed libraries – <code>sys</code>, <code>tensorflow</code>, <code>apache_beam</code> and <code>tensorflow_model_analysis</code>. You use the <code>assert sys.version_info.major==3</code> command to verify that the notebook is being run using Python 3. </p>
<h2 id="heading-step-2-how-to-load-the-dataset">Step 2 – How to Load the dataset</h2>
<p>You will download the <code>tar</code> file and extract it.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> io, os, tempfile
TAR_NAME = <span class="hljs-string">'saved_models-2.2'</span>
BASE_DIR = tempfile.mkdtemp()
DATA_DIR = os.path.join(BASE_DIR, TAR_NAME, <span class="hljs-string">'data'</span>)
MODELS_DIR = os.path.join(BASE_DIR, TAR_NAME, <span class="hljs-string">'models'</span>)
SCHEMA = os.path.join(BASE_DIR, TAR_NAME, <span class="hljs-string">'schema.pbtxt'</span>)
OUTPUT_DIR = os.path.join(BASE_DIR, <span class="hljs-string">'output'</span>)

!curl -O https://storage.googleapis.com/artifacts.tfx-oss-public.appspot.com/datasets/{TAR_NAME}.tar
!tar xf {TAR_NAME}.tar
!mv {TAR_NAME} {BASE_DIR}
!rm {TAR_NAME}.tar
</code></pre>
<p>The dataset downloaded is in the <code>tar</code> file format. It includes the training datasets, evaluation datasets, the data schema and the training and serving saved models along with eval saved models. You will need all of them in this tutorial.</p>
<h2 id="heading-step-3-how-to-parse-the-schema">Step 3 – How to Parse the Schema</h2>
<p>You need to parse the downloaded schema so that you can use it with TFMA. </p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tensorflow <span class="hljs-keyword">as</span> tf
<span class="hljs-keyword">from</span> google.protobuf <span class="hljs-keyword">import</span> text_format
<span class="hljs-keyword">from</span> tensorflow.python.lib.io <span class="hljs-keyword">import</span> file_io
<span class="hljs-keyword">from</span> tensorflow_metadata.proto.v0 <span class="hljs-keyword">import</span> schema_pb2
<span class="hljs-keyword">from</span> tensorflow.core.example <span class="hljs-keyword">import</span> example_pb2

schema = schema_pb2.Schema()
contents = file_io.read_file_to_string(SCHEMA)
schema = text_format.Parse(contents, schema)
</code></pre>
<p>You will parse the schema using the <code>text_format</code> method of the <code>google.protobuf</code> library to convert the protobuf message to text format and TensorFlow's <code>schema_pb2</code>.</p>
<h2 id="heading-step-4-how-to-use-the-schema-to-create-tfrecords">Step 4 – How to Use the Schema to Create TFRecords</h2>
<p>The next course of action would be to give TFMA access to our dataset. For this, we need to create a <code>TFRecords</code> file.  We used our schema to create it, since it gives us the correct type for each feature.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> csv
datafile = os.path.join(DATA_DIR, <span class="hljs-string">'eval'</span>, <span class="hljs-string">'data.csv'</span>)
reader = csv.DictReader(open(datafile, <span class="hljs-string">'r'</span>))
examples = []
<span class="hljs-keyword">for</span> line <span class="hljs-keyword">in</span> reader:
  example = example_pb2.Example()
  <span class="hljs-keyword">for</span> feature <span class="hljs-keyword">in</span> schema.feature:
    key = feature.name
    <span class="hljs-keyword">if</span> feature.type == schema_pb2.FLOAT:
      example.features.feature[key].float_list.value[:] = (
          [float(line[key])] <span class="hljs-keyword">if</span> len(line[key]) &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">else</span> [])
    <span class="hljs-keyword">elif</span> feature.type == schema_pb2.INT:
      example.features.feature[key].int64_list.value[:] = (
          [int(line[key])] <span class="hljs-keyword">if</span> len(line[key]) &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">else</span> [])
    <span class="hljs-keyword">elif</span> feature.type == schema_pb2.BYTES:
      example.features.feature[key].bytes_list.value[:] = (
          [line[key].encode(<span class="hljs-string">'utf8'</span>)] <span class="hljs-keyword">if</span> len(line[key]) &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">else</span> [])
  <span class="hljs-comment"># Add a new column 'big_tipper' that indicates if the tip was &gt; 20% of the fare. </span>
  <span class="hljs-comment"># TODO(b/157064428): Remove after label transformation is supported for Keras.</span>
  big_tipper = float(line[<span class="hljs-string">'tips'</span>]) &gt; float(line[<span class="hljs-string">'fare'</span>]) * <span class="hljs-number">0.2</span>
  example.features.feature[<span class="hljs-string">'big_tipper'</span>].float_list.value[:] = [big_tipper]
  examples.append(example)
tfrecord_file = os.path.join(BASE_DIR, <span class="hljs-string">'train_data.rio'</span>)
<span class="hljs-keyword">with</span> tf.io.TFRecordWriter(tfrecord_file) <span class="hljs-keyword">as</span> writer:
  <span class="hljs-keyword">for</span> example <span class="hljs-keyword">in</span> examples:
    writer.write(example.SerializeToString())
!ls {tfrecord_file}
</code></pre>
<p>It is worthy of note that TFMA supports a number of different model types including TF Keras models, models based on generic TF2 signature APIs, as well TF estimator-based models. However, for this tutorial, you will configure a Keras-based model. </p>
<p>In your Keras <a target="_blank" href="https://www.tensorflow.org/tfx/model_analysis/setup">setup</a>, you will add your metrics and plots manually as part of the configuration (see the <a target="_blank" href="https://www.tensorflow.org/tfx/model_analysis/metrics">metrics</a> guide for information on the metrics and plots that are supported).</p>
<h2 id="heading-step-5-how-to-set-up-and-run-tfma-using-keras">Step 5 – How to Set Up and Run TFMA using Keras</h2>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tensorflow_model_analysis <span class="hljs-keyword">as</span> tfma
</code></pre>
<p>You'll finally call and use the instance of <code>tfma</code> that you previously imported at this point. </p>
<pre><code class="lang-python"><span class="hljs-comment"># You will setup tfma.EvalConfig settings</span>
keras_eval_config = text_format.Parse(<span class="hljs-string">"""
  ## Model information
  model_specs {
    # For keras (and serving models) we need to add a `label_key`.
    label_key: "big_tipper"
  }

  ## You will post training metric information. These will be merged with any built-in
  ## metrics from training.
  metrics_specs {
    metrics { class_name: "ExampleCount" }
    metrics { class_name: "BinaryAccuracy" }
    metrics { class_name: "BinaryCrossentropy" }
    metrics { class_name: "AUC" }
    metrics { class_name: "AUCPrecisionRecall" }
    metrics { class_name: "Precision" }
    metrics { class_name: "Recall" }
    metrics { class_name: "MeanLabel" }
    metrics { class_name: "MeanPrediction" }
    metrics { class_name: "Calibration" }
    metrics { class_name: "CalibrationPlot" }
    metrics { class_name: "ConfusionMatrixPlot" }
    # ... add additional metrics and plots ...
  }

  ## You will slice the information
  slicing_specs {}  # overall slice
  slicing_specs {
    feature_keys: ["trip_start_hour"]
  }
  slicing_specs {
    feature_keys: ["trip_start_day"]
  }
  slicing_specs {
    feature_values: {
      key: "trip_start_month"
      value: "1"
    }
  }
  slicing_specs {
    feature_keys: ["trip_start_hour", "trip_start_day"]
  }
"""</span>, tfma.EvalConfig())
</code></pre>
<p>It's also important that you create a <code>tfma.EvalSharedModel</code> that points at the Keras model.</p>
<pre><code class="lang-python">keras_model_path = os.path.join(MODELS_DIR, <span class="hljs-string">'keras'</span>, <span class="hljs-string">'2'</span>)
keras_eval_shared_model = tfma.default_eval_shared_model(
    eval_saved_model_path=keras_model_path,
    eval_config=keras_eval_config)

keras_output_path = os.path.join(OUTPUT_DIR, <span class="hljs-string">'keras'</span>)
</code></pre>
<p>And then you finally run TFMA, ending this step.</p>
<pre><code class="lang-python">keras_eval_result = tfma.run_model_analysis(
    eval_shared_model=keras_eval_shared_model,
    eval_config=keras_eval_config,
    data_location=tfrecord_file,
    output_path=keras_output_path)
</code></pre>
<p>Now that you have run the evaluation, look at the visualizations using TFMA. For the following examples, you can visualize the results from running the evaluation on the Keras model. </p>
<p>To view metrics, you will use <code>[tfma.view.render_slicing_metrics](https://www.tensorflow.org/tfx/model_analysis/api_docs/python/tfma/view/render_slicing_metrics)</code>. By default, the views will display the <code>Overall</code> slice. To view a particular slice, you can either use the name of the column (by setting <code>slicing_column</code>) or provide a <a target="_blank" href="https://www.tensorflow.org/tfx/model_analysis/api_docs/python/tfma/SlicingSpec"><code>tfma.SlicingSpec</code></a>.</p>
<h2 id="heading-step-6-how-to-visualize-the-metrics-and-plots">Step 6 – How to Visualize the Metrics and Plots</h2>
<p>At this point, it is important that you note that the columns used in the dataset are as follows: </p>
<ul>
<li><code>pickup_community_area</code></li>
<li><code>fare</code></li>
<li><code>trip_start_month</code></li>
<li><code>trip_start_hour</code></li>
<li><code>trip_start_day</code></li>
<li><code>trip_start_timestamp</code></li>
<li><code>pickup_latitude</code></li>
<li><code>pickup_longitude</code></li>
<li><code>dropoff_latitude</code></li>
<li><code>dropoff_longitude</code></li>
<li><code>trip_miles</code></li>
<li><code>pickup_census_tract</code></li>
<li><code>dropoff_census_tract</code></li>
<li><code>payment_type</code></li>
<li><code>company</code></li>
<li><code>trip_seconds</code></li>
<li><code>dropoff_community_area</code>, and </li>
<li><code>tips</code> </li>
</ul>
<p>For a first trial and as an example, you can set <code>slicing_column</code> to look at the <code>trip_start_hour</code> feature from our previous <code>slicing_specs</code>. You are then able to visualize the column. </p>
<pre><code class="lang-python">tfma.view.render_slicing_metrics(keras_eval_result, slicing_column=<span class="hljs-string">'trip_start_hour'</span>)
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/image-27.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/image-28.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>On running this, you will see that the metrics visualization supports the following interactions:</p>
<ul>
<li>Click and drag to pan</li>
<li>Scroll to zoom</li>
<li>Right click to reset the view</li>
<li>Hover over the desired data point to see more details.</li>
<li>Select from four different types of views using the selections at the bottom.</li>
</ul>
<p>Note that your initial <code>tfma.EvalConfig</code> has created a whole list of <code>slicing_specs</code>, which you can visualize by updating slice information passed to <code>tfma.view.render_slicing_metrics</code>. Here you can select the <code>trip_start_day</code> slice (days of the week).</p>
<pre><code class="lang-python">tfma.view.render_slicing_metrics(keras_eval_result, slicing_column=<span class="hljs-string">'trip_start_day'</span>)
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/image-29.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/image-31.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>TFMA also supports creating feature crosses to analyze combinations of features. To test this, you will create a cross between <code>trip_start_hour</code> and <code>trip_start_day</code>.</p>
<pre><code class="lang-python">tfma.view.render_slicing_metrics(
    keras_eval_result,
    slicing_spec=tfma.SlicingSpec(
        feature_keys=[<span class="hljs-string">'trip_start_hour'</span>, <span class="hljs-string">'trip_start_day'</span>]))
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/image-32.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, crossing the two columns creates a lot of combinations! But you will narrow down your cross to only look at <em>trips that start at 1pm</em>. Then, you will select <code>binary_accuracy</code> from the visualization as shown below.</p>
<pre><code class="lang-python">tfma.view.render_slicing_metrics(
    keras_eval_result,
    slicing_spec=tfma.SlicingSpec(
        feature_keys=[<span class="hljs-string">'trip_start_day'</span>], feature_values={<span class="hljs-string">'trip_start_hour'</span>: <span class="hljs-string">'13'</span>}))
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/image-33.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/image-34.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-7-how-to-track-your-models-performance-over-time">Step 7 – How to Track Your Model's Performance Over Time</h2>
<p>You'll use your training dataset for training your model. It will hopefully be representative of your test dataset and the data that will be sent to your model in production.  </p>
<p>But while the data in inference requests may remain the same as your training data, in many cases it will start to change enough so that the performance of your model will change.</p>
<p>That means that you need to monitor and measure your model's performance on an ongoing basis, so that you can be aware of and react to changes.  </p>
<p>Let's look at how TFMA can help.</p>
<pre><code class="lang-python">output_paths = []
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">3</span>):
  <span class="hljs-comment"># Create a tfma.EvalSharedModel that points to our saved model.</span>
  eval_shared_model = tfma.default_eval_shared_model(
      eval_saved_model_path=os.path.join(MODELS_DIR, <span class="hljs-string">'keras'</span>, str(i)),
      eval_config=keras_eval_config)

  output_path = os.path.join(OUTPUT_DIR, <span class="hljs-string">'time_series'</span>, str(i))
  output_paths.append(output_path)

  <span class="hljs-comment"># Run TFMA</span>
  tfma.run_model_analysis(eval_shared_model=eval_shared_model,
                          eval_config=keras_eval_config,
                          data_location=tfrecord_file,
                          output_path=output_path)

  eval_results_from_disk = tfma.load_eval_results(output_paths[:<span class="hljs-number">2</span>])

tfma.view.render_time_series(eval_results_from_disk)
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/image-35.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Using the <code>tfma</code>, you can validate and evaluate your machine learning models across different slices of data. </p>
<p>You can see from the image above that you can evaluate the <code>auc</code> (area under the curve), <code>auc_precision_recall</code>, <code>binary_accuracy</code>, <code>binary_crossentropy</code>, <code>calibration</code>, <code>example_count</code>, <code>mean_label</code>, <code>mean_prediction</code>, <code>precision</code>, and <code>recall</code> metrics of the machine learning model. </p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Finally, it is important that TFMA can be configured to evaluate multiple models at the same time. Typically, you do this to compare a new model against a baseline (such as the currently serving model) to determine what the performance differences in metrics (for example AUC) are relative to the baseline. </p>
<p>When thresholds are configured, TFMA will produce a <a target="_blank" href="https://www.tensorflow.org/tfx/model_analysis/api_docs/python/tfma/ValidationResult"><code>tfma.ValidationResult</code></a> record indicating whether the performance matches expectations.  </p>
<p>If at this point, you have questions about the difference between evaluating machine learning models using <a target="_blank" href="https://www.freecodecamp.org/news/how-to-evaluate-machine-learning-models-using-tensorboard/">TensorBoard</a> and TensorFlow Metrics Analysis (TFMA), this is a valid concern. Both are tools for providing the measurements and visualizations needed during the Machine Learning workflow. </p>
<p>But it is important to note that you use them in different stages of the development process. At a high level, you use TensorBoard to analyze the training process itself while TFMA is concerned with the deep analysis of the 'finished' trained model.</p>
<p>Thank you for reading!  </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to implement declarative Xamarin form validation ]]>
                </title>
                <description>
                    <![CDATA[ By Ameer Jhan If you have an existing Xamarin.Forms codebase and want to add validation without affecting your code behind or view model, then this is for you. ? What made me write this article? Our team designed and developed a Xamarin mobile app wi... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/declarative-xamarin-form-validation-c174d2a74618/</link>
                <guid isPermaLink="false">66c348c38cfe41ff707fbe27</guid>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Validation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ xamarin forms ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sat, 25 Aug 2018 20:42:38 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*wIHOFE3kSzR9ysT_PeSNbg.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Ameer Jhan</p>
<p>If you have an existing <strong>Xamarin.Forms</strong> codebase and want to add validation without affecting your code behind or view model, then this is for you. ?</p>
<h3 id="heading-what-made-me-write-this-article">What made me write this article?</h3>
<p>Our team designed and developed a Xamarin mobile app with multiple forms with zero validations, since we had less time and we were okay with back end validations alone.</p>
<p>As time passed our need to add front end validation grew with the app. So we decided to add validations without affecting our code behind or view model. There were no articles to help us with this strategy, so I decided to write one.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>I assume that you are comfortable with <strong>Xamarin</strong> <strong>Behaviors</strong>. If not, please read the below documentation — it is very simple and straightforward.</p>
<p><a target="_blank" href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/behaviors/"><strong>Xamarin.Forms Behaviors - Xamarin</strong></a><br><a target="_blank" href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/behaviors/">_Behaviors lets you add functionality to user interface controls without having to subclass them. Behaviors are written…_docs.microsoft.com</a></p>
<h3 id="heading-what-we-will-end-up-with">What we will end up with</h3>
<p>The result will be highly readable and declarative validations on the xaml, keeping the code behind and view model away from validation!</p>
<h3 id="heading-things-to-note">Things to note</h3>
<p>Whenever the code is too long to digest in a single explanation, I will break it into multiple sections and will use three ellipses(<strong>…</strong>) in place of code from previous or upcoming sections.</p>
<h3 id="heading-so-what-is-the-plan">So what is the plan?</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*eO3Oa1jcdCXtPz-Y-bC1Vw.gif" alt="Image" width="749" height="480" loading="lazy"></p>
<p>We can plan our way pretty well if we can think about the basic things that happens while validating:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*h8ib08-kXOGLsaZLy_E6Tw.png" alt="Image" width="551" height="641" loading="lazy"></p>
<p>The above flowchart is a very abstract representation of our entire design. To shed more light onto the actual code, take a look at the following image:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*wIHOFE3kSzR9ysT_PeSNbg.png" alt="Image" width="381" height="261" loading="lazy"></p>
<h3 id="heading-enough-is-enough-lets-code">Enough is enough — let’s code!</h3>
<p>The following interface helps in maintaining the consistency across different validators we define.</p>
<p>Now let us write some implementations for a few common validators.</p>
<p>Some validators may need few extra parameters. For example, <strong>FormatValidator</strong> requires a format parameter, and those parameters can be added as fields in the class.</p>
<p>There are number of ways to display an error. You might prefer to display it right below the control, or you might prefer to show it as a summary at the top of the form. To accommodate these different styles of showing errors, we define an interface for it to maintain consistency.</p>
<p>For the sake of simplicity, I have implemented a very basic error style which just adds and removes a label below the control being validated.</p>
<p>Now it is time for the <strong>Xamarin Behavior</strong> part, which glues together all the above code.</p>
<p><strong>_style:</strong> This field is initialised with our custom BasicErrorStyle implementation. This will help us show and remove the error whenever its needed.</p>
<p><strong>_view:</strong> This is the control on which this validation is placed.</p>
<p><strong>PropertyName:</strong> This is the property of the control which is to be validated against validation rules, let's say Text property of a Entry control or SelectedItem property of a picker control.</p>
<p><strong>Validators:</strong> This is the list of validation rules against which the control property will be validated.</p>
<p>The <strong>Validate()</strong> method runs through all the validation rules and executes the Check method on the property value of the control. If all the validation rules pass, then the <strong>RemoveError</strong> method is called on _style. Otherwise the <strong>ShowError</strong> method is called on _style.</p>
<p>The remaining part of code just attaches and detaches the <strong>OnPropertyChanged, OnUnFocussed</strong> method to PropertyChanged and UnFocussed event of the control whenever this behavior is added to the xaml.</p>
<p>When these events are triggered, they call the <strong>Validate()</strong> method we defined earlier which in-turn adds or removes the error as needed.</p>
<h3 id="heading-how-to-use-it">How to use it</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*faxCWiiC5i0D70YwDtwLxA.gif" alt="Image" width="500" height="281" loading="lazy"></p>
<p>Yes the wait is finally over! Now you can add these validations to your xaml by importing the necessary xaml namespaces.</p>
<p>If you run the app now, you should experience something like this:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*5yLoqd4n7YXnarwHpkA4Ng.gif" alt="Image" width="480" height="798" loading="lazy"></p>
<h3 id="heading-validating-the-entire-form">Validating the entire form</h3>
<p>Now comes the next challenge: how we know whether the entire form is valid? That is, how do we know that all the controls in the form have valid data?</p>
<p>To accomplish this, we create another behavior called <strong>ValidationGroupBehavior,</strong> in which we group the controls that are to be validated together to validate an entire form.</p>
<p><strong>_validationBehaviors:</strong> this is a list of validation behaviors from various controls to be validated.</p>
<p><strong>IsValidProperty:</strong> this is a bindable property which you can access in the xaml to check whether the form is valid or not.</p>
<p>We expose two methods, namely <strong>Add()</strong> and <strong>Remove(),</strong> to help the controls add or remove themselves from a particular validation group.</p>
<p>We also expose a method, <strong>Update(),</strong> to help the controls for refreshing the validity of the form whenever their data changes. This method in turn runs all the validations in the <strong>_validationBehaviors</strong> and sets the value of the <strong>IsValid</strong> property accordingly.</p>
<h3 id="heading-refactoring-our-validationbehavior">Refactoring our ValidationBehavior</h3>
<p>Let’s do a little refactoring to our ValidationBehavior class to accommodate the validation grouping of controls:</p>
<p>We have added a property called <strong>Group</strong> to store the validation group to which the control belongs. The <strong>Group.Add()</strong> and <strong>Group.Remove()</strong> methods are called when this behavior is attached or detached, respectively, from a control. In turn, this adds or remove the control from a particular validation group. Whenever the control loses focus, it updates the validity of the group by calling the <strong>Group.Update()</strong> method.</p>
<h3 id="heading-validationgroupbehavior-in-action"><strong>ValidationGroupBehavior in action</strong></h3>
<p>Update the xaml file as shown below to see the awesomeness of the validation groups:</p>
<p>The above code adds the <strong>ValidationGroupBehavior</strong> to the parent element of all controls, and then it adds its reference to the <strong>Group</strong> property of the <strong>Validator</strong> in the control. You can then use the <strong>IsValid</strong> property of the validation group to enable or disable a submit button. Fancy stuff, right?</p>
<p>If you run the app now, you should see something like this:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*SBHPeDHSnbAUrewSoqn6pw.gif" alt="Image" width="480" height="800" loading="lazy"></p>
<h3 id="heading-what-about-async-validators">What about async validators?</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*1YQKAMnGRv5rfERe9TNxyA.gif" alt="Image" width="636" height="479" loading="lazy"></p>
<p>I can hear the question buzzing through your mind. One good thing about our design is that it can be extended very easily with little effort. This can be achieved by just declaring another interface as shown below:</p>
<p>You can now create an implementation for an async validator, let's say <strong>AsyncUserExists,</strong> which returns a task that resolves to a boolean. Add a new property to <strong>ValidationBehavior</strong> called <strong>AsyncValidators</strong> and add async validators to that property. A little async and await addition to the validation process will solve our problem.</p>
<h3 id="heading-are-we-done-at-last">Are we done at last?</h3>
<p>We’ve covered quite a bit of info in a very simple way. But there are few nice-to-have features that you can try yourself:</p>
<ul>
<li>Debounce for async validators</li>
<li>Check if the control is dirty (user typed something) or not before showing an error</li>
</ul>
<h3 id="heading-confused">Confused?</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*f7rU8GMQ234_69Lx5rWOyw.gif" alt="Image" width="800" height="446" loading="lazy"></p>
<p>If you are confused or have some gray areas, feel free to reach out to me in the comments. You can also refer to my demo app in GitHub which I have linked below.</p>
<p><a target="_blank" href="https://github.com/ameerthehacker/XamarinFormValidationDemo"><strong>ameerthehacker/XamarinFormValidationDemo</strong></a><br><a target="_blank" href="https://github.com/ameerthehacker/XamarinFormValidationDemo">_XamarinFormValidationDemo - This is a demo app for my medium blog on xamarin form validations_github.com</a></p>
<h3 id="heading-tldr">TL;DR</h3>
<p>If you are lazy like me, or don't want to write a whole lot to get the above functionality, then you can wait until I develope a NuGet package for xamarin form validations using the above strategy. You are welcome to contribute to it, and I have linked to it below.</p>
<p><a target="_blank" href="https://github.com/ameerthehacker/XamarinFormValidation"><strong>ameerthehacker/XamarinFormValidation</strong></a><br><a target="_blank" href="https://github.com/ameerthehacker/XamarinFormValidation">_XamarinFormValidation - Delcarative, flexible and highly configurable validations in Xamarin without a sweat :hearts:_github.com</a></p>
<p>If you found this article helpful, give me some claps ?</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
