Skip to main content
Machine Learning & Deep Learning

An Ethics Checklist for Shipping ML

Synthesize responsible ML practices into a concrete checklist before deploying a model to production.

Advanced28 minBy ToolDix Editorial

Learning objectives

  • Understand the role of data provenance, consent, and fairness in responsible ML and apply concrete validation steps
  • Implement fairness audits to detect and quantify disparity across demographic groups; design mitigation strategies
  • Design human-override and monitoring systems that keep humans in control and create accountability trails
  • Build and maintain documentation (model cards, data sheets) that enable transparency and regulatory compliance

ToolDix original visual

ML & Deep Learning practice loop
1

Frame

Name the outcome and constraints.

2

Build

Try one bounded workflow.

3

Review

Keep evidence, revise, and share.

The Full Circle

You've reached the final lesson of this course. Here's what you've learned:

  • Lesson 1-3: Start with defensible baselines and honest metrics. Don't use accuracy on imbalanced data. Understand your problem deeply.
  • Lessons 4-10: Training discipline. Detect overfitting, regularize intelligently, validate on real test distributions.
  • Lessons 11-17: Classical and neural building blocks. Understand what you're training. Know the trade-offs between interpretability and capacity.
  • Lessons 18-19: Handle messy real data. Class imbalance, missing values, distribution shifts. The world is not balanced.
  • Lessons 20-21: Debug and compress. Explain your model to humans. Shrink it to fit your hardware and latency budget.
  • Lessons 22-23: Deploy with discipline. Batch, version, monitor. Watch for drift. Keep the model honest.

All of that technical work—the baselines, the regularization, the compression, the monitoring—serves a single goal: to build ML systems that actually work, that don't fail silently, and that don't hurt people. This final lesson brings it together into a concrete checklist you must complete before shipping any model to production.

ToolDix original diagram
Ethics checklist before shipping an ML system
Subgroup performance
Does the model treat all demographic groups fairly, or does accuracy vary widely?
Data provenance & consent
Do you have permission to use this data? Is its source documented and ethically sourced?
Explainability for users
Can affected individuals understand why they got a particular prediction or decision?
Appeal process & review
Can someone contest a model's decision? Is there human review for high-stakes predictions?
ML systems can amplify existing biases, disproportionately harm underrepresented groups, and make consequential decisions without accountability -- ethics is not optional, it's a prerequisite for trustworthy deployment.

The Checklist

Before deploying, answer these questions honestly. If you can't answer "yes" to most of them, don't ship.

Question: Do we know where the training data came from, and did people consent to their data being used?

Why it matters: If your training data is stolen, scraped without consent, or includes personally identifying information, you're not just building a bad model—you're participating in harm. Users deserve to know their data is being used, especially in high-stakes contexts.

Checklist:

  • [ ] Data source documented: For every dataset in training, document its source, license, and any restrictions. Is it a public benchmark? Bought from a vendor? Collected in-house? Scraped from the web?
  • [ ] Consent obtained: If the data includes any personally identifiable information (PII) or sensitive demographics, confirm users consented to its use for ML training. GDPR and other regulations require this.
  • [ ] Licensed appropriately: If you're using publicly available data, confirm its license allows your intended use. Many datasets prohibit commercial use.
  • [ ] Sensitive information redacted: Remove names, SSNs, phone numbers, email addresses, and other PII before training. These confound learning and violate privacy.

Example failure: A healthcare startup trains a disease prediction model on patient records scraped from online forums without consent. The model is accurate but indefensible—patients never agreed to be in a training set.

2. Fairness and Subgroup Performance

Question: Does the model perform equally well across demographic subgroups? If not, can we justify the disparity?

Why it matters: A model that's 95% accurate on average but 60% accurate for a protected group (race, gender, age, etc.) is discriminatory, even if unintentionally. This ties back to lesson 19 (imbalanced datasets): the overall metric hides harm to minorities. In high-stakes domains (lending, hiring, criminal justice, healthcare), fairness disparity is not just unethical—it's illegal under many jurisdictions.

Checklist:

  • [ ] Subgroups identified: Define which demographic groups are relevant to your problem (gender, race, age, geography, socioeconomic status). If your model makes decisions affecting humans, fairness across groups matters.
  • [ ] Performance measured by subgroup: Don't report overall accuracy. Report accuracy, precision, recall, false positive/false negative rates separately for each subgroup using confusion matrices.
  • [ ] Disparities investigated: If subgroup A has 5% error rate and subgroup B has 20%, investigate why. Is it statistically significant? Due to data imbalance? Model bias? Real-world differences?
  • [ ] Disparity justified or mitigated: If there's a large gap, either mitigate it (rebalance data, class weighting) or explicitly document and justify why it's acceptable.
  • [ ] Fairness-accuracy tradeoff made explicit: Document any accuracy sacrifice needed to improve fairness; get stakeholder buy-in.

Fairness Audit Code Example:

import pandas as pd
import numpy as np
from sklearn.metrics import confusion_matrix, recall_score, precision_score

def fairness_audit(y_true, y_pred, subgroup_labels, subgroup_name):
    """
    Audit model fairness across subgroups.
    Returns detailed metrics by group.
    """
    results = []

    for subgroup_value in np.unique(subgroup_labels):
        mask = subgroup_labels == subgroup_value
        y_true_group = y_true[mask]
        y_pred_group = y_pred[mask]

        if len(y_true_group) == 0:
            continue

        # Compute metrics
        tn, fp, fn, tp = confusion_matrix(y_true_group, y_pred_group).ravel()

        accuracy = (tp + tn) / (tp + tn + fp + fn)
        tpr = tp / (tp + fn) if (tp + fn) > 0 else 0  # Recall / True Positive Rate
        fpr = fp / (fp + tn) if (fp + tn) > 0 else 0  # False Positive Rate
        fpr_disparity = abs(fpr - fpr_baseline) if 'fpr_baseline' in locals() else 0
        precision = tp / (tp + fp) if (tp + fp) > 0 else 0

        results.append({
            'subgroup': subgroup_value,
            'n_samples': len(y_true_group),
            'positive_rate': y_true_group.mean(),
            'accuracy': accuracy,
            'tpr': tpr,
            'fpr': fpr,
            'precision': precision,
            'fpr_disparity': fpr_disparity
        })

    df_results = pd.DataFrame(results)

    # Flag disparities
    print(f"\n=== Fairness Audit: {subgroup_name} ===")
    print(df_results.to_string(index=False))

    # Check for significant disparities
    max_tpr_diff = df_results['tpr'].max() - df_results['tpr'].min()
    max_fpr_diff = df_results['fpr'].max() - df_results['fpr'].min()

    if max_tpr_diff > 0.1:  # > 10% difference in recall
        print(f"⚠️  WARNING: TPR (recall) disparity: {max_tpr_diff:.1%}")
    if max_fpr_diff > 0.05:  # > 5% difference in false positive rate
        print(f"⚠️  WARNING: FPR disparity: {max_fpr_diff:.1%}")

    return df_results

# Example: Loan approval model
y_true = np.array([0, 1, 1, 0, 1, 0, 0, 1])  # Actual outcomes
y_pred = np.array([0, 1, 1, 0, 1, 0, 1, 1])  # Model predictions
race = np.array(['W', 'W', 'B', 'W', 'B', 'B', 'W', 'B'])  # Subgroup

fairness_audit(y_true, y_pred, race, 'Race')

Disparity Mitigation Example:

# If fairness audit reveals disparity, retrain with fairness constraints
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler

def train_fair_model(X, y, sensitive_attr, fairness_constraint='balanced'):
    """
    Train model with fairness objective.
    """
    if fairness_constraint == 'balanced':
        # Approach 1: Balance class weights by subgroup
        # Weight each sample inversely to its group's positive rate
        positive_rates = {}
        for group in np.unique(sensitive_attr):
            mask = sensitive_attr == group
            positive_rates[group] = y[mask].mean()

        sample_weights = np.ones(len(y))
        for i, group in enumerate(sensitive_attr):
            if positive_rates[group] > 0:
                # Upweight underrepresented groups
                sample_weights[i] = 1 / positive_rates[group]

        model = LogisticRegression(class_weight='balanced', max_iter=1000)
        model.fit(X, y, sample_weight=sample_weights)

    return model

# Retrain with fairness weighting
model_fair = train_fair_model(X_train, y_train, race_train)
y_pred_fair = model_fair.predict(X_test)

# Re-audit
fairness_audit(y_test, y_pred_fair, race_test, 'Race (after fairness retraining)')

Example failure: A resume screening model achieves 90% accuracy on average but screens out 40% of applicants from underrepresented groups due to historical hiring bias in the training data. The model replicates systemic discrimination.

Example success: Same model, but fairness audit found the disparity. Team retrained with fairness constraints (see code above), accepted a 2% drop in overall accuracy, and now achieves 88% accuracy with < 5% fairness gaps across all groups.


3. Explainability and Right to Explanation

Question: Can we explain why the model made a specific decision to the person affected by it?

Why it matters: In consequential domains (lending, hiring, healthcare, criminal justice), people deserve to understand why they were approved or denied. "The algorithm decided" is not an explanation. This ties back to lesson 20 (SHAP, LIME).

Checklist:

  • [ ] Explainability method chosen: Decide if you'll use SHAP, LIME, or a simpler method (feature importance, decision rules). Document your choice.
  • [ ] Explanation validated: Test your explanation method on a held-out set. Does the explanation match the model's actual decision-making? (This is hard—explanations are approximations; see lesson 20's caveats.)
  • [ ] User-facing explanation designed: Write the explanation in non-technical language. "Your credit application was denied because your debt-to-income ratio exceeded our threshold" is clearer than "SHAP value for feature 7 is -0.32."
  • [ ] Appeal process defined: If someone disagrees with a model decision, they can appeal to a human. The human can override the model.

Example failure: A job application rejection says "The AI decided you're not a good fit." The candidate has no idea why and can't appeal.

Example success: Same system, but rejection includes: "Your qualifications matched 70% of our requirements. We prioritized the 30 years of experience requirement; you have 8 years. You can appeal to our recruiting team." Candidate understands and can argue why the policy should change.

4. Bias and Representation in Training Data

Question: Is the training data representative, or does it reflect historical biases?

Why it matters: Models learn from data. If training data is biased (e.g., contains historical discrimination), the model learns and amplifies that bias. You have a responsibility to acknowledge and, where possible, correct for it.

Checklist:

  • [ ] Data composition documented: Report the breakdown of your training data by protected attributes (gender, race, age, etc.). What % of your data is from each group? Is it representative of the population your model will serve?
  • [ ] Historical bias acknowledged: If your data reflects past discrimination (e.g., hiring data from an era when discrimination was legal), acknowledge it explicitly. Don't pretend historical bias doesn't exist.
  • [ ] Representation gaps identified: If a group is underrepresented in training data, note it. Your model will be less reliable for that group. This is a known limitation, not a secret.
  • [ ] Mitigation attempted: If possible, collect more data from underrepresented groups. Or use techniques like synthetic data generation or importance weighting. Or be transparent about the limitation.

Example failure: A healthcare model is trained on data that's 85% male because historically, medical research enrolled mostly men. The model performs worse on women but no one discloses this. Women suffer harm.

Example success: Same model, same data limitation, but team explicitly states: "This model is trained on a male-skewed dataset and shows 5% higher error rates on female patients. We're funding a research project to collect more female-inclusive data. For now, any decision involving this model should be reviewed by a human physician."


5. Monitoring, Drift Detection, and Retraining

Question: Can we detect if the model is degrading in production and respond before users are harmed?

Why it matters: Models decay over time due to data drift and concept drift (lesson 23). If you deploy a model and never retrain it, it will eventually fail. You must commit to ongoing monitoring.

Checklist:

  • [ ] Monitoring dashboard built: Track model performance (accuracy by subgroup), latency, error rates, and user feedback in real time. Make it visible to the team.
  • [ ] Drift detection thresholds set: Define when performance is "bad enough" to retrain. e.g., "If subgroup B accuracy drops below 85%, initiate retraining within 48 hours."
  • [ ] Retraining process documented: How often will you retrain? Weekly? Monthly? On-demand? Who triggers it? How long does it take?
  • [ ] Rollback plan in place: If a retrained model performs worse, can you quickly revert to the previous version?
  • [ ] Fairness re-checked on retrains: Every time you retrain, re-check fairness across subgroups. Don't assume the new model maintains fairness.

Example failure: A fraud detection model is deployed and never retrained. After 6 months, fraud patterns have evolved and the model catches only 40% of fraud. Customers lose money. No one knew.

Example success: Same system, but fairness dashboard auto-sends weekly reports. Team sees fraud detection rate dropping and retrains within 2 weeks. New model is deployed via canary (lesson 22). Fraud rate stays above 85%.

6. Human Override and Appeal Path

Question: Can a human override the model, and can a person appeal a decision?

Why it matters: Models fail. Edge cases exist. Humans have agency and rights. High-stakes systems must have a path for humans to intervene and override.

Checklist:

  • [ ] Human-in-the-loop designed: For consequential decisions (loan approvals, medical diagnoses, criminal risk assessment), a human reviews or signs off on the model's recommendation.
  • [ ] Override mechanism easy: It should be quick for a human to override. If it takes 10 minutes per override and you have 100 overrides/day, the system is broken.
  • [ ] Appeal process public: Users know how to appeal. There's a clear path: disagree with decision → file appeal → human reviews → decision made.
  • [ ] Appeal reviewed by a human, not a bot: Automated appeals routing is fine; final decision-making must be human.
  • [ ] Log all overrides and appeals: Track what gets overridden and why. Use this data to identify model failures and improve the system.

Example failure: A resume screening model rejects a candidate without human review. The candidate has no idea why and can't appeal. The company inadvertently screens out someone who would have been a great hire.

Example success: Model ranks candidates, human recruiter reviews top 20, makes final decision. If someone's resume is rejected at ranking stage, they can appeal. Appeals are reviewed by a recruiter. This process takes longer but is fair.


7. Documentation and Transparency

Question: Is there a record of what the model does, its known limitations, and who built it?

Why it matters: Accountability. If your model causes harm, regulators, journalists, and affected people will ask: who built this? What was the intent? What's known about the limitations? You must be able to answer.

Checklist:

  • [ ] Model card created: Document the model's intended use, evaluation metrics, known limitations, and fairness considerations. (See Google's Model Card framework, cited in sources.)
  • [ ] Data sheet created: Document the dataset: sources, composition, known biases, limitations. (See Data Cards, cited in sources.)
  • [ ] Author and approval documented: Who trained the model? Who approved it for deployment? This creates accountability.
  • [ ] Limitation section thorough: Be honest about what the model can't do. High-stakes domains: explicitly state what percentage of decisions should be reviewed by humans.
  • [ ] Update history logged: When was it retrained? What changed? Keep a changelog.

Example failure: A lending model is deployed. Three years later, regulators ask for its training data and performance metrics. No one can find the information. The company can't prove fairness or defend itself.

Example success: Same model, but model card and data sheet are maintained. When regulators ask, the team provides documentation within 24 hours.


Pre-Deployment Ethics Checklist (Comprehensive)

Before shipping any model, complete this checklist. Circle back on any "No" answers.

| Category | Check | Why It Matters | Red Flag | Owner | |----------|-------|----------------|----------|-------| | Data | Do we know where training data came from? | Credibility, compliance | Unknown sources, scraped data, no license | | | Data | Did people consent to their data being used? | GDPR, privacy rights, trust | No consent obtained, PII present | Legal | | Data | Is sensitive data (PII, health, race) redacted? | Privacy, overfitting to protected attributes | SSN, email, name in training data | Privacy | | Fairness | Have we identified relevant demographic groups? | All stakeholders considered | Ignored minorities, only one group | Product | | Fairness | Measured performance by subgroup (not just overall)? | Detect hidden disparities | Only overall accuracy reported | DS | | Fairness | Investigated performance gaps if > 10% across groups? | Understand root cause | Gap ignored, blamed on data | DS | | Fairness | Acceptable gaps either mitigated or explicitly justified? | Trade-off made conscious | "Gap is fine" without evidence | Leadership | | Explainability | Can we explain individual decisions to affected people? | Right to explanation, appeal | "Algorithm decided" no explanation | Product | | Explainability | Tested explanation method on held-out data? | Explanations may be misleading | No validation of explanation accuracy | DS | | Monitoring | Built monitoring dashboard for performance by subgroup? | Early warning system | Only average metrics monitored | Eng | | Monitoring | Defined drift detection thresholds and remediation? | Proactive response to decay | No thresholds set | DS | | Documentation | Created model card documenting limitations? | Accountability, discovery | No documentation | DS | | Documentation | Created data sheet for training data? | Transparency | No data documentation | DS | | Override | Human review process defined for high-stakes decisions? | Keep humans in control | 100% automated, no appeal process | Product | | Override | Override/appeal process easy and public? | Fairness, due process | Overrides are slow (days) | Ops | | Governance | Approval from multi-disciplinary team (eng + ethics + legal)? | Distributed responsibility | Only data team approved | Leadership | | Governance | Update history and changelog maintained? | Regulatory audit trail | No version control | Eng |

Scoring: If > 2 red flags or any 3 consecutive unchecked boxes, do not deploy. Fix issues, then re-evaluate.


Ethics Impact by Domain

Different domains have different ethical stakes. Adjust your rigor accordingly:

| Domain | Ethical Risk Level | Recommended Rigor | Key Checks | Approval Needed | |--------|------------------|------------------|-----------|-----------------| | Lending / credit | 🔴 Critical | Maximum | Fairness, bias, documentation, appeal process | Legal + compliance + ethics | | Hiring / recruitment | 🔴 Critical | Maximum | Fairness, bias, appeal process, subgroup performance | HR + legal + ethics | | Healthcare / diagnosis | 🔴 Critical | Maximum | Fairness, explainability, human review, limitations doc | Medical experts + legal | | E-commerce / recommendation | 🟡 High | High | Fairness, monitoring, performance by subgroup | Product + data science | | Fraud detection | 🟡 High | High | Fairness (false positive impact), appeal process | Compliance + ops | | Content moderation | 🟡 High | High | Fairness across cultures/languages, appeal process | Legal + product | | Ad targeting | 🟢 Medium | Medium | Basic fairness, transparency | Marketing + product | | Analytics dashboards | 🟢 Low | Low | Data provenance, basic documentation | Data team |

Impact rule: When in doubt, treat as critical. Better over-invest in ethics than under-invest.


Example: Bias Audit Script for Loan Approvals

Here's a script you can adapt for your domain:

# Complete bias audit for a lending model
import numpy as np
import pandas as pd
from sklearn.metrics import confusion_matrix

def complete_bias_audit(model, X_test, y_test, protected_attrs):
    """
    Run a comprehensive bias audit.
    Returns a report with metrics and recommendations.
    """
    y_pred = model.predict(X_test)
    y_proba = model.predict_proba(X_test)[:, 1]

    report = {}

    for attr_name, attr_values in protected_attrs.items():
        print(f"\n=== Auditing: {attr_name} ===")
        report[attr_name] = {}

        for group_value in np.unique(attr_values):
            mask = attr_values == group_value
            y_t = y_test[mask]
            y_p = y_pred[mask]

            tn, fp, fn, tp = confusion_matrix(y_t, y_p).ravel()

            metrics = {
                'group': group_value,
                'n': mask.sum(),
                'approval_rate': y_p.mean(),  # Approval rate for this group
                'default_rate': y_t.mean(),   # Actual default rate
                'tpr': tp / (tp + fn),        # True positive rate (caught defaults)
                'fpr': fp / (fp + tn),        # False positive rate (wrongly approved)
                'precision': tp / (tp + fp),  # Precision (of approved, how many defaulted)
            }
            report[attr_name][group_value] = metrics

        # Analyze disparities
        approval_rates = [v['approval_rate'] for v in report[attr_name].values()]
        tpr_rates = [v['tpr'] for v in report[attr_name].values()]

        approval_disparity = max(approval_rates) - min(approval_rates)
        tpr_disparity = max(tpr_rates) - min(tpr_rates)

        print(f"Approval rate disparity: {approval_disparity:.1%}")
        print(f"TPR (recall) disparity: {tpr_disparity:.1%}")

        if approval_disparity > 0.05:  # > 5% difference in approval rates
            print(f"⚠️  CONCERN: Significant approval rate disparity detected")

        if tpr_disparity > 0.1:  # > 10% difference in recall
            print(f"⚠️  CONCERN: Significant recall disparity detected")

    return report

# Usage
protected_attributes = {
    'race': np.array([...]),  # Your demographic data
    'gender': np.array([...]),
    'age_group': np.array([...])
}

audit_report = complete_bias_audit(model, X_test, y_test, protected_attributes)

Orchestrating the Checklist

This checklist isn't a one-time gate—it's a continuous practice. Here's a realistic timeline:

Before training:

  • Identify the problem (lesson 1-3 discipline)
  • Plan data collection with fairness and consent in mind
  • Define subgroups for fairness auditing

During training:

  • Monitor for overfitting and bias
  • Evaluate fairness continuously on validation data
  • Document data provenance

Before deployment:

  • Complete the full checklist above
  • Peer review the model and checklist responses
  • Get approval from a multi-disciplinary team (engineer, data scientist, product, legal, ethics)

After deployment:

  • Run monitoring and drift detection (lesson 23)
  • Collect user feedback and appeal data
  • Retrain and re-audit fairness regularly
  • Publish a transparency report annually (if appropriate)

A Model Example: Loan Approval System

You've built a model to approve/deny loan applications. Here's how the checklist plays out:

1. Data provenance: Training data is 50,000 loan applications from the past 3 years, from your bank's own underwriters. All applicants consented (per privacy policy). You own the data.

2. Fairness: You measure accuracy by race, gender, and age. Audit reveals: model's approval rate for White applicants is 70%, for Black applicants is 55%. You investigate: is this real discrimination, or does it reflect the underlying distribution in your data? You find the underlying approval rate is 72% vs. 60%, so the model is learning from historical underwriter bias. You retrain with fairness constraint (lesson 19): approval rates must match across groups. New model: 65% approval for all groups. Accuracy drops 2%, fairness improves.

3. Explainability: Using SHAP (lesson 20), you build an explanation for each loan decision. Applicants denied can see: "Your debt-to-income ratio of 50% exceeds our 45% threshold."

4. Bias: You document that your historical data reflects era when lending discrimination was legal. You explicitly state in the model card: "This model is trained on data that may reflect historical bias. Fairness has been audited and mitigated. Approval rate disparity is < 5% across protected groups."

5. Monitoring: You track approval rates, acceptance rates, default rates, and fairness metrics daily. If any metric shifts > 5%, you alert the team.

6. Human override: Every loan decision gets a human credit officer sign-off. Officer can override model recommendation. If a model-denied applicant has unusual circumstances, the officer can approve. All overrides are logged.

7. Documentation: Model card, data sheet, fairness report—all available to regulators and customers. Every quarter, you audit fairness and publish results.

Outcome: Model is accurate, fair, explainable, and defensible. When regulators ask, you can answer. When a customer appeals, you have a process. Risk is managed.

Common Mistake: Treating Ethics as a Compliance Checkbox

Some teams treat the ethics checklist as legal cover: "We did fairness audit (box checked), now we can ship." But ethics requires genuine engagement, not theater.

Red flags:

  • "We checked for fairness but did nothing about the gaps" (documentation without action)
  • "Our fairness metric is 90% but we don't define what fairness means" (metric without rigor)
  • "We'll add human review later" (deferring accountability)
  • "This model is objective because it's ML" (assuming algorithms are unbiased)

Real responsibility:

  • Identify unfairness (hard)
  • Decide to mitigate it or accept it (requires conviction)
  • Act and accept consequences
  • Monitor and adapt

This is not easy. It requires time, resources, and interdisciplinary collaboration. But it's the difference between building systems that serve everyone and systems that quietly harm people.


A Message to the Reader

You've completed 24 lessons on machine learning and deep learning. You understand baselines, training discipline, model building, and production deployment. You know how to compress, serve, and monitor models. You know why accuracy is misleading and what it means to build fairly.

This knowledge is power—but power comes with responsibility. ML systems make decisions that affect people's lives: who gets hired, who gets a loan, who gets healthcare, who stays safe. You have the technical ability to build them well or poorly, fairly or unfairly.

The practices in this course—defensible baselines, honest metrics, fairness audits, monitoring, human oversight—are not theoretical niceties. They are the difference between a system that works for everyone and a system that harms people quietly.

As you go forward, bring this discipline to every model you build. Advocate for the time to do this right. Push back against shortcuts that sacrifice fairness for speed. Document your decisions so others can learn and audit them. Operate with the understanding that your work shapes the world.

The technical bar is high. The ethical bar must be equally high. You now have the tools to clear both.

Deploy well.

Sources and license context

These references informed the lesson. ToolDix adds its own explanation, workflow, and practice rather than reproducing source material. Every link below leaves ToolDix and opens the publisher's own site in a new tab.

Keep going

Read these next on ToolDix.

Original lessons that build on what you just read.