Code Smell 121 - String Validations

Code Smell 121 - String Validations

Maxi Contieri
·Mar 13, 2022·

3 min read

Subscribe to my newsletter and never miss my upcoming articles

Play this article

Table of contents

  • Problems
  • Solutions
  • Context
  • Sample Code
  • Detection
  • Tags
  • Conclusion
  • Relations
  • More Info
  • Credits

You need to validate strings. So you don't need strings at all

TL;DR: Search for missing domain objects when validating strings.

Problems

  • Primitive obsession.

  • Bijection Fault

  • Validated strings are a subset of all possible strings.

  • Fail Fast principle violation.

  • Single Responsibility Principle violation.

  • DRY Principle Violation.

Solutions

  1. Create a first-class object representing the concept under the MAPPER

Context

Serious software has lots of string validations.

Often, They are not in the correct places.

This leads to non-robust and corrupt software.

The simple solution is to build only real-world and valid abstractions.

Sample Code

Wrong

<?

//First Example: Address Validation
class Address { 
  function __construct(string $emailAddress) {
     //String validation on Address class violates SRP
     $this->validateEmail($emailAddress);
     //...
   }

  private function validateEmail(string $emailAddress) {
    $regex = "/[a-zA-Z0-9_-.+]+@[a-zA-Z0-9-]+.[a-zA-Z]+/";
    //Regex is a sample / It might be wrong
    //Emails and Urls should be first class objects

    if (!preg_match($regex, $emailAddress))
    {
      throw new Exception('Invalid email address ' . emailAddress);
    }    
  }
}

//Second Example: Wordle

class Wordle { 
  function validateWord(string $wordleword){
    //Wordle word should be a real world entity. Not a subset of strings
  }
 }

Right

<?

//First Example: Address Validation
class Address { 
  function __construct(EmailAddress $emailAddress) {
     //Email is always valid / Code is cleaner     
     //...
   }
}

class EmailAddress { 
  //We can reuse this object many times avoiding copypasting
  string $address; 
  private function __construct(string $emailAddress) {
    $regex = "/[a-zA-Z0-9_-.+]+@[a-zA-Z0-9-]+.[a-zA-Z]+/";
    //Regex is a sample / It might be wrong
    //Emails and Urls are first class objects

    if (!preg_match($regex, $emailAddress))
    {
      throw new Exception('Invalid email address ' . emailAddress);
    }   
    $this->address = $emailAddress;
  }
}

//Second Example: Wordle

class Wordle { 
  function validateWord(WordleWord $wordleword){
    //Wordle word is a real world entity. Not a subset of string
  }
 }

class WordleWord { 
  function __construct(string $emailAddress)
    //Avoid building invalid world words
    //For example length != 5
  }
 }

Detection

[X] Semi-Automatic

We can check all constructors validating strings and reify the missing concepts.

Tags

  • Primitive Obsession

Conclusion

Small objects are hard to find.

Primitive obsessors always complain about this kind of indirections.

Creating these new small concepts keeps our model loyal to the bijection and ensures our models are always healthy.

Relations

More Info

Credits

Photo by Brett Jordan on Unsplash


Less than 10% of the code has to do with the ostensible purpose of the system; the rest deals with input-output, data validation, data structure maintenance, and other housekeeping.

Mary Shaw


This article is part of the CodeSmell Series.

 
Share this