1st ci&t lightning talks: writing better code with object calisthenics
DESCRIPTION
"We’ve all seen poorly written code that’s hard to understand, test, and maintain. Object-oriented programming promised to save us from our old procedural code, allowing us to write software incrementally, reusing as we go along. But sometimes it seems like we’re just chasing down the same old complex, coupled designs in Java that we had in C. Good object-oriented design is hard to learn. Transitioning from procedural development to object-oriented design requires a major shift in thinking that is more difficult than it seems. Many developers assume they’re doing a good job with OO design, when in reality they’re unconsciously stuck in old habits that are hard to break. It doesn’t help that many examples and best practices (even Sun’s code in the JDK) encourage poor OO design in the name of performance or simple weight of history." -- Jeff Bay Here are some key rules which are going to improve your OO designing skills and make you a better programmer. Some are harder to implement but will open your mind for new ways of coding. Happy coding! :)TRANSCRIPT
Writing better code withObject Calisthenics
Lucas [email protected]/larruda
Adapted from Jeff Bay’s paper from “The ThoughtWorks Anthology” and Guilherme Blanco’s presentation.
Calis...what?!
7 code qualitiescohesion
loose coupling
no redundancy
encapsulation
testability
readability
focus
9 rules of thumb
1. One level of indentation per method
class Board {
...
String board() {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++)
buf.append(data[i][j]);
buf.append(“\n”);
}
return buf.toString();
}
}
1. One level of indentation per method
class Board { ... String Board() { StringBuffer buf = new StringBuffer(); collectRows(buf); return buf.toString(); } void collectRows(StringBuffer buf) { for (int i = 0; i < 10; i++) collectRow(buf, i); } void collectRow(StringBuffer buf, int row) { for (int i = 0; i < 10; i++) Buf.append(data[row][i]); buf.append(“\n”); }}
1. One level of indentation per method
public function validateForm($filters='', $validators='', $options=''){ $data = $_POST; $input = new Zend_Filter_Input($filters, $validators, $data); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim()); if ($input->hasInvalid() || $input->hasMissing()) { foreach ($input->getMessages() as $field => $messageList) { foreach ($messageList as $message) { if (strpos($message, "empty")) { throw new Tss_FormException( "The field {$field} cannot be empty!", 3, 'javascript:history.back();' ); } else { throw new Tss_FormException( "{$message}", 3, 'javascript:history.back();' ); } } } } return $input;}
1. One level of indentation per method
public function validateForm($filters='', $validators='', $options=''){ $data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim()); if ( ! ($input->hasInvalid() || $input->hasMissing())) { return $input; } foreach ($input->getMessages() as $field => $messageList) { foreach ($messageList as $message) { if (strpos($message, "empty")) { throw new Tss_FormException( "The field {$field} cannot be empty!", 3, 'javascript:history.back();' ); } else { throw new Tss_FormException( "{$message}", 3, 'javascript:history.back();' ); } } }}
1. One level of indentation per method
public function validateForm($filters='', $validators='', ...{ $data = $_POST;
$input = new Zend_Filter_Input ($filters, $validators, $data); $input->setDefaultEscapeFilter( new Zend_Filter_StringTrim ()); if ( ! ($input->hasInvalid() || $input->hasMissing())) { return $input; } foreach ($input->getMessages() as $field => $messageList) { foreach ($messageList as $message) { $errorMessage = (strpos($message, "empty") === false) ? "The field {$field} cannot be empty!" : "{$message}";
throw new Tss_FormException ( $errorMessage, 3, 'javascript:history.back();' ); } }}
1. One level of indentation per method
public function validateForm($filters='', $validators='', ...{ $data = $_POST;
$input = new Zend_Filter_Input ($filters, $validators, $data); $input->setDefaultEscapeFilter( new Zend_Filter_StringTrim ()); if ( ! ($input->hasInvalid() || $input->hasMissing())) { return $input; } foreach ($input->getMessages() as $field => $messageList) { $messageKey = key($message); $message = $message[$messageKey]; $errorMessage = (strpos($message, "empty") === false) ? "The field {$field} cannot be empty!" : "{$message}";
throw new Tss_FormException ( $errorMessage, 3, 'javascript:history.back();' ); }}
2. Don’t use the ELSE keyword
if (status == DONE) {
doSomething();
} else {
…
}
YOUMUST BE JOKING!!!
2. Don’t use the ELSE keyword
class Board { ... String board(StringBuffer buf) { if (buf.length()) { return buf.toString(); } else { collectRows(buf); return buf.toString(); } } ...}
2. Don’t use the ELSE keyword
class Board { ... String board(StringBuffer buf) { if (!buf.length()) { collectRows(buf); }
return buf.toString(); } ...}
2. Don’t use the ELSE keyword
function login() {
$login = $this->input->post('email', true);
$password = $this->input->post('password', true);
$reference = $this->input->post('reference', true);
if ($this->clients_model->login($login, $password)) {
redirect($reference);
} else {
$this->session->set_flashdata(
'error', 'User or password invalid.'
);
$this->session->set_flashdata('reference', $reference);
redirect('clients');
}
}
2. Don’t use the ELSE keyword
function login() {
$login = $this->input->post('email', true);
$password = $this->input->post('password', true);
$reference = $this->input->post('reference', true);
if (!$this->clients_model->login($login, $password)) {
$this->session->set_flashdata(
'error' , 'User or password invalid.'
);
$this->session->set_flashdata('reference', $reference);
$reference = 'clients';
}
redirect($reference);
}
3. Wrap all primitives and Strings
If the primitive type has a behavior it should be encapsulated
3. Wrap all primitives and Strings
class UIComponent{ // ... public function repaint($animate = true) { // … } // ... $component->repaint(false);}
3. Wrap all primitives and Strings
class UIComponent{ // ... public function repaint(Animate $animate) { // ... } }
class Animate{ public $animate; public function __construct($animate = true) { $this->animate = $animate; }}
// ...$component->repaint(new Animate(false));
4. First class collections
Any class that contains a collection/array should not contain any other member
variables
Java Collections follow this rule
4. First class collections
Transversable
Countable
Iterator
Filtering
Mapping
Combining
5. One dot/arrow per line
Sign of misplaced responsibilities
The Law of Demeter“Only talk to your friends”
5. One dot/arrow per line
class Board { ...
class Piece { ... String representation; } class Location { ... Piece current; } String boardRepresentation () { StringBuffer buf = new StringBuffer(); for (Location l: squares()) buf.append(l.current.representation.substring(0, 1)); return buf.toString(); }}
5. One dot/arrow per line
class Board { ...
class Piece { ... private String representation; String character() { return representation.substring(0, 1); }
void addTo(StringBuffer buf) { buf.append(character()); } } class Location { ... private Piece current; void addTo(StringBuffer buf) { current.addTo(buf); } } String boardRepresentation() { StringBuffer buf = new StringBuffer(); for (Location l: squares()) l.addTo(buf); return buf.toString(); }}
6. Don’t abbreviate
Are you writing the same name repeatedly?method being used multiple times
sign of code duplication
Is the method name too long?class with multiple responsibilities
missing additional classredundancy
7. Keep all entities small
JavaNo class over 50 lines
No packages over 10 files
PHPNo class over 100 lines
No packages over 15 files
Packages, like classes, should be cohesive and have a purpose
8. No classes with more than two/five instance variables
Improve cohesion
Split on more entities
9. No getters/setters/properties
Improve encapsulation
“Tell, don’t ask”
Q&Aciandt.com
http://www.cs.helsinki.fi/u/luontola/tdd-2009/ext/ObjectCalisthenics.pdf
http://www.slideshare.net/guilhermeblanco/object-calisthenics-applied-to-php
https://www.youtube.com/watch?v=ftBUHrxfOcc
THANKS FOR
BEINGHERE!
ciandt.com
@lunascarruda
google.com/+LucasArruda
fb.com/lucasnarruda
linkedin.com/in/larruda
github.com/larruda
coderbits.com/larruda
drupal.org/user/1009514