visit
Classes are handy. We can call them and invoke them any time. Is this good?
public class MyCollection {
public bool HasNext { get; set;} //implementation details
public object Next(); ////implementation details
}
public class MyDomainObject sum(MyCollection anObjectThatCanBeIterated) {
//Tight coupling
}
//cannot fake or mock this method since it always expects an instance of MyCollection
public interface Iterator {
public bool HasNext { get; set;}
public object Next();
}
public Iterator Reverse(Iterator iterator) {
var list = new List<int>();
while (iterator.HasNext) {
list.Insert(0, iterator.Next());
}
return new ListIterator(list);
}
public class MyCollection implements Iterator {
public bool HasNext { get; set;} //implementation details
public object Next(); ////implementation details
}
public class myDomainObject sum(Iterator anObjectThatCanBeIterated) {
//Loose coupling
}
//can use any Iterator (even a mocked one as long as it adheres protocol)
Coupling: The one and only problem
When your code depends on an interface, that dependency is usually very minor and unobtrusive. Your code doesn’t have to change unless the interface changes, and interfaces typically change far less often than the code behind them. When you have an interface, you can edit classes that implement that interface or add new classes that implement the interface, all without impacting code that uses the interface.
For this reason, it is better to depend on interfaces or abstract classes than it is to depend on concrete classes. When you depend on less volatile things, you minimize the chance that particular changes will trigger massive recompilation.
Michael Feathers
Flags indicate what happened. Unless their name is too generic.
<?
function dummy() {
$flag = true;
while ($flag == true) {
$result = doSomething();
if ($result) {
$flag = false;
}
}
}
<?
function dummyFunction()
{
$atLeastOneElementWasFound = true;
while (!$atLeastOneElementWasFound) {
$elementSatisfies = doSomething();
if ($elementSatisfies) {
$atLeastOneElementWasFound = true;
}
}
}
If you lie to the compiler, it will get its revenge.
Henry Spencer
If your method is jealous and you don't trust delegation, you should start to do it.
TL;DR: Don't abuse your friend objects.
class Candidate {
void printJobAddress(Job job) {
System.out.println("This is your position address");
System.out.println(job.address().street());
System.out.println(job.address().city());
System.out.println(job.address().ZipCode());
}
}
class Job {
void printAddress() {
System.out.println("This is your job position address");
System.out.println(this.address().street());
System.out.println(this.address().city());
System.out.println(this.address().ZipCode());
//We might even move this responsability directly to the address !
//Some address information is relevant to a job and not for package tracking
}
}
class Candidate {
void printJobAddress(Job job) {
job.printAddress();
}
}
We argue that design practices which take a data-driven approach fail to maximize encapsulation because they focus too quickly on the implementation of objects. We propose an alternative object-oriented design method which takes a responsibility-driven approach.
Rebecca Wirfs-Brock
Two classes entangled in love.
class Candidate {
void printJobAddress(Job job) {
System.out.println("This is your position address");
System.out.println(job.address().street());
System.out.println(job.address().city());
System.out.println(job.address().zipCode());
if (job.address().country() == job.country()) {
System.out.println("It is a local job");
}
}
final class Address {
void print() {
System.out.println(this.street);
System.out.println(this.city);
System.out.println(this.zipCode);
}
bool isInCounty(Country country){
return this.country == country;
}
class Job {
void printAddress() {
System.out.println("This is your position address");
this.address().print());
if (this.address().isInCountry(this.country()) {
System.out.println("It is a local job");
}
}
}
class Candidate {
void printJobAddress(Job job) {
job.printAddress();
}
}
No matter how slow you are writing clean code, you will always be slower if you make a mess.
Names should always indicate role.
public bool CheckIfStringHas3To7LowercaseCharsFollowedBy3or4Numbers(string string)
{
Regex regex = new Regex(@"[a-z]{2,7}[1-9]{3,4}")
var hasMatch = regex.IsMatch(string);
return hasMatch;
}
public bool CheckIfStringHas3To7LowercaseCharsFollowedBy3or4Numbers(string password)
{
Regex stringHas3To7LowercaseCharsFollowedBy3or4Numbers = new Regex(@"[a-z]{2,7}[1-9]{3,4}")
var hasMatch = stringHas3To7LowercaseCharsFollowedBy3or4Numbers.IsMatch(password);
return hasMatch;
}
The first name we can come across is related to an accidental point of view. It takes time to build a theory on the models we are building using our MAPPERS. Once we get there, we must rename our variables-
Types are essentially assertions about a program. And I think it’s valuable to have things be as absolutely simple as possible, including not even saying what the types are.
Dan Ingalls