Infinite code smells! We see several symptoms and situations that make us doubt the quality of our development. Let's look at some possible solutions. Most of these smells are just hints of something that might be wrong. They are not rigid rules. Previous Parts Part I Part II Part III Part IV Part V Part VI Part VII Part VIII Part IX Part X Part XI Part XII Part XIII Let's continue... Code Smell 66 - Shotgun Surgery Say it only once Problems Bad Responsibilities Assignments Code Duplication Maintainability Violation. Single Responsibility Copy-pasted code. Solutions Refactor Sample Code Wrong final class SocialNetwork { function postStatus(string $newStatus) { if (!$user->isLogged()) { throw new Exception('User is not logged'); } ///... } function uploadProfilePicture(Picture $newPicture) { if (!$user->isLogged()) { throw new Exception('User is not logged'); } ///... } function sendMessage(User $recipient, Message $messageSend) { if (!$user->isLogged()) { throw new Exception('User is not logged'); } ///... } } Right <? final class SocialNetwork { function postStatus(string $newStatus) { $this->assertUserIsLogged(); ///... } function uploadProfilePicture(Picture $newPicture) { $this->assertUserIsLogged(); ///... } function sendMessage(User $recipient, Message $messageSend) { $this->assertUserIsLogged(); ///... } function assertUserIsLogged() { if (!$this->user->isLogged()) { throw new Exception('User is not logged'); //This is just a simplification to show the code smell //Operations should be defined as objects with preconditions etc. } } } Detection Some modern linters can detect repeated patterns (not just repeated code) and also while performing our code reviews we can easily detect this problem and ask for a refactor. Tags Code Duplication Conclusion Adding a new feature should be straightforward it our model maps 1:1 to real world and our responsibilities are in the correct places. We should be alert for small changes spanning in several classes. More info Wikipedia Refactoring Guru NDpend Blog Dzone Credits Photo by on William Isted Unsplash Duplication is the primary enemy of a well-designed system. Robert Martin Code Smell 67 - Middle Man Let's break Demeter's Law. Problems Unnecessary Indirection Empty Classes Readability Solutions Remove Middle man. Sample Code Wrong public class Client { Address address; public ZipCode zipCode() { return address.zipCode(); } } public class Address { private ZipCode zipCode; public ZipCode zipCode() { return new ZipCode('CA90210'); } } public class Application { ZipCode zipCode = client.zipCode(); } Right public class Client { Address address; //client now has to expose its address public address() { return address; } } public class Address { private ZipCode zipCode; public ZipCode zipCode() { return new ZipCode('CA90210'); } } public class Application { ZipCode zipCode = client.address().zipCode(); } Detection Same as its , We can detect this small using parsing trees. opposite smell Tags Coupling Declarative Readability Conclusion This is exactly the opposite to . We make explicit the message chain. Message Chain Relations Code Smell 08 - Long Chains Of Collaborations Code Smell 114 - Empty Class More info Refactoring Guru Refactoring.com C2 Wiki JetBrains Wikipedia Credits Photo by on Dan Counsell Unsplash Whenever I have to think to understand what the code is doing, I ask myself if I can refactor the code to make that understanding more immediately apparent. Martin Fowler Code Smell 68 - Getters Getting things is widespread and safe. But it is a very bad practice. Problems Naming Information Hiding Coupling Encapsulation Violation Mutability Anemic Models Solutions Avoid Getters Use domain names instead Protect your implementation decisions. Sample Code Wrong <?php final class Window { public $width; public $height; public $children; public function getWidth() { return $this->width; } public function getArea() { return $this->width * $this->height; } public function getChildren() { return $this->children; } } Right <?php final class Window { private $width; private $height; private $children; public function width() { return $this->width; } public function area() { return $this->height * $this->width; } public function addChildren($aChild) { //do not expose internal attributes return $this->children[] = $aChild; } } Detection Getters coincide in certain scenarios with a true responsibility. It will be reasonable for a window to return its color and it may accidentally store it as color. so a method returning the attribute color might be a good solution. color() breaks since it is implementative and has no real counterpart on our . getColor() bijection mappers Most linters can warn us if they detect anemic models with getters and setters. Tags Information Hiding Conclusion Getters and Setters are a bad established practice. Instead of focusing on object behavior (essential), we are desperate to know object guts (accidental) and violate their implementation. Relations Code Smell 28 - Setters Code Smell 01 - Anemic Models Code Smell 64 - Inappropriate Intimacy More info Nude Models - Part II Getters Credits Photo by on Vidar Nordli-Mathisen Unsplash The value of a prototype is in the education it gives you, not in the code itself. Alan Cooper Code Smell 69 - Big Bang (JavaScript Ridiculous Castings) This handy operator is a trouble maker. TL;DR: Don't mix booleans with non-booleans. Problems Not Declarative Code Hard to debug Magic Castings Accidental Complexity Solutions Be Explicit Don't mix Booleans with non-booleans. Fail Fast Be Smarter than your compiler. Stay loyal to the bijection. The One and Only Software Design Principle Sample Code Wrong !true // returns false !false // returns true isActive = true !isActive // returns false age = 54 !age // returns false array = [] !array // returns false obj = new Object; !obj // returns false !!true // returns true !!false // returns false !!isActive // returns true !!age // returns true !!array // returns true !!obj // returns true Right !true // returns false !false // returns true isActive = true !isActive // returns false age = 54 !age // should return type mismatch (or 54 factorial!) array = [] !array // should return type mismatch obj = new Object; !obj // should return type mismatch (what is an obejct negated in a real domain?) !!true // returns true - it is idempotent !!false // returns false - it is idempotent !!isActive // returns true - it is idempotent !!age // nonsense !!array // nonsense !!obj // nonsense Detection Since this is a "feature" in some languages it would be hard to test. We can set programming policies or choose more . strict languages We should detect usages in non-boolean objects and warn our programmers. ! !! Tags Casting Coercion Javascript Conclusion Languages like JavaScript divide their whole universe into or values. This decision hides errors when dealing with non booleans. true false We should be very strict and keep booleans (and their behavior), far away from non booleans. Relations Code Smell 24 - Boolean Coercions Code Smell 06 - Too Clever Programmer More info Reddit Bennadel.com Mozilla Credits Photo by on Greg Rakozy Unsplash It is easier to write an incorrect program than understand a correct one. Alan J Perlis Code Smell 70 - Anemic Model Generators TL;DR: Do not create anemic objects. Much less with automatic tools. Problems Anemic Objects Coupling to Implementation Harder to Debug Solutions Create your objects manually. Focus on essential behavior instead of accidental data storage. Sample Code Wrong AnemicClassCreator::create( 'Employee', [ new AutoGeneratedField('id', '$validators->getIntegerValidator()'), new AutoGeneratedField('name', '$validators->getStringValidator()'), new AutoGeneratedField('currentlyWorking', '$validators->getBooleanValidator()') ]); class Employee extends AutoGeneratedObjectEmployee { } //We have magic setters and getters //getId() , setId(), getName() //Validation is not implicit //Class are loaded via an autoloader $john = new Employee; $john->setId(1); $john->setName('John'); $john->setCurrentlyWorking(true); $john->getName(); //returns 'John' Right final class Employee { private $name; private $workingStatus; public function __construct(string $name, WorkingStatus $workingStatus) { //.. } public function name(): string { return $this->name; //This is not a getter. It is Employee's responsibility to tell us her/his name } } //We have no magic setters or getters //all methods are real and can be debugged //Validations are implicit $john = new Employee('John', new HiredWorkingStatus()); $john->name(); //returns 'John' Detection Often, anemic models are generated with . meta-programming We need to track these magic . code generators Tags Anemic Conclusion Code Wizards, Meta-programming, and anemic models are all code smells. We need to avoid these dark techniques. Having to write the code makes us reflect on every piece of data we encapsulate. explicitly Relations Code Smell 01 - Anemic Models More info Lazyness I - Metaprogramming Lazyness II - Code Wizards Credits Photo by on Lenny Kuhne Unsplash The best smells are something that's easy to spot and most of time lead you to really interesting problems. Data classes (classes with all data and no behavior) are good examples of this. You look at them and ask yourself what behavior should be in this class. Martin Fowler And that’s all for now… Next article will explain 5 more code smells!