SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our User Agreement and Privacy Policy.
SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our Privacy Policy and User Agreement for details.
Successfully reported this slideshow.
Activate your 14 day free trial to unlock unlimited reading.
5.
Object Calisthenics
Erm... WTH is Object Calisthenics?
‣ Object Calisthenics
Term derived from greek,
“exercise”, under the
context of gymnastics.
6.
Object Calisthenics
Erm... WTH is Object Calisthenics?
‣ Jeff Bay in The ThoughtWorks Anthology [1]
coined the term Object Calisthenics in computers,
as a group of exercises to Object Oriented
programming.
[1] The ThoughtWorks Anthology: Essays on Software Technology and Innovation
7.
Object Calisthenics
Motivation
‣ Readable Code
‣ Comprehensible
‣ Testable
‣ Maintainable
Learning about good code practices
at Object CaIisthenics talk of
@guilhermeblanco on @gtaphp
8.
Object Calisthenics
Rules
‣ Nine (9) rules “very” simple...
9.
Object Calisthenics
Rule 1: Only one indentation level per method
‣ Only one indentation level per method
10.
Object Calisthenics
Rule 1: Only one indentation level per method
public function validateForm($filters='', $validators='', $options='')
{
$data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options);
$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;
}
11.
Object Calisthenics
Rule 1: Only one indentation level per method
public function validateForm($filters='', $validators='', $options='')
{
$data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options);
$input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());
0 if ($input->hasInvalid() || $input->hasMissing()) {
1 foreach ($input->getMessages() as $field => $messageList) {
2 foreach(strpos($message, "empty")) {
($messageList as $message) {
3 if throw new Tss_FormException(
4 "The field {$field} cannot be empty!",
3, 'javascript:history.back();'
);
} else {
throw new Tss_FormException(
"{$message}", 3, 'javascript:history.back();'
);
}
}
}
}
return $input;
}
12.
Object Calisthenics
Rule 1: Only one indentation level per method
public function validateForm($filters='', $validators='', $options='')
{
$data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options);
$input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());
0 if ($input->hasInvalid() || $input->hasMissing()) {
1 foreach ($input->getMessages() as $field => $messageList) {
2 foreach(strpos($message, "empty")) {
($messageList as $message) {
3 if throw new Tss_FormException(
4 "The field {$field} cannot be empty!",
3, 'javascript:history.back();'
);
} else {
throw new Tss_FormException(
"{$message}", 3, 'javascript:history.back();'
);
}
}
}
}
return $input;
}
13.
Object Calisthenics
Rule 1: Only one indentation level per method
public function validateForm($filters = array(), $validators = array(), $options = null)
{
$data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options);
$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();'
);
}
}
}
}
14.
Object Calisthenics
Rule 1: Only one indentation level per method
public function validateForm($filters = array(), $validators = array(), $options = null)
{
$data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options);
$input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());
if ( ! ($input->hasInvalid() || $input->hasMissing())) {
return $input;
}
0 foreach ($input->getMessages() as $field => $messageList) {
1 foreach(strpos($message, "empty")) {
($messageList as $message) {
2 if throw new Tss_FormException(
3 "The field {$field} cannot be empty!",
3, 'javascript:history.back();'
);
} else {
throw new Tss_FormException(
"{$message}", 3, 'javascript:history.back();'
);
}
}
}
}
15.
Object Calisthenics
Rule 1: Only one indentation level per method
public function validateForm($filters = array(), $validators = array(), $options = null)
{
$data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options);
$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();'
);
}
}
}
16.
Object Calisthenics
Rule 1: Only one indentation level per method
public function validateForm($filters = array(), $validators = array(), $options = null)
{
$data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options);
$input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());
if ( ! ($input->hasInvalid() || $input->hasMissing())) {
return $input;
}
0 foreach ($input->getMessages() as $field => $messageList) {
1 foreach ($messageList as $message) { "empty") === false)
2 $errorMessage = (strpos($message,be empty!"
? "The field {$field} cannot
: "{$message}";
throw new Tss_FormException(
$errorMessage, 3, 'javascript:history.back();'
);
}
}
}
17.
Object Calisthenics
Rule 1: Only one indentation level per method
public function validatePost($filters = array(), $validators = array(), $options = null)
{
$data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options);
$input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());
if ( ! ($input->hasInvalid() || $input->hasMissing())) {
return $input;
}
foreach ($input->getMessages() as $field => $message) {
$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();'
);
}
}
18.
Object Calisthenics
Rule 1: Only one indentation level per method
public function validatePost($filters = array(), $validators = array(), $options = null)
{
$data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options);
$input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());
if ( ! ($input->hasInvalid() || $input->hasMissing())) {
return $input;
}
foreach ($input->getMessages() as $field => $message) {
$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();'
);
}
}
19.
Object Calisthenics
Rule 2: Do not use the “else” keyword
‣ Never use the “else” keyword
20.
Object Calisthenics
Rule 2: Do not 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');
}
}
21.
Object Calisthenics
Rule 2: Do not 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');
}
}
22.
Object Calisthenics
Rule 2: Do not 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');
}
}
23.
Object Calisthenics
Rule 2: Do not 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);
}
24.
Object Calisthenics
Rule 3: Wrap primitive types and strings
‣ Wrap all primitive types and strings
25.
Object Calisthenics
Rule 3: Wrap primitive types and strings
‣ This rule cannot be completely ported to PHP, because
the language does not perform well with an entirely
Object Oriented code with a huge amount of instances
26.
Object Calisthenics
Rule 3: Wrap primitive types and strings
‣ But... if the variable of primitive type has a behavior, it
must be encapsulated
27.
Object Calisthenics
Rule 3: Wrap primitive types and strings
class UIComponent
{
! // ...
!
public function repaint($animate = true)
{
// ...
}
}
// ...
$component->repaint(false);
28.
Object Calisthenics
Rule 3: Wrap primitive types and strings
class UIComponent
{
! // ...
!
public function repaint($animate = true)
{
// ...
}
}
// ...
$component->repaint(false);
29.
Object Calisthenics
Rule 3: Wrap primitive types 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));
30.
Object Calisthenics
Rule 4: Only one dot per line
‣ Only one dot (arrow for PHP) per line
31.
Object Calisthenics
Rule 4: Only one dot per line
‣ Not applicable to PHP...
32.
Object Calisthenics
Rule 4: Only one dot per line
‣ ...but multiple nested calls...
‣ tend to expose an encapsulation problem
‣ increase difficulty to debug and exception handling
‣ do not represent an atomic action
33.
Object Calisthenics
Rule 4: Only one dot per line
‣ We could adapt to the language, contemplating...
34.
Object Calisthenics
Rule 4: Only one dot per line
‣ A chain of different objects, but only if the execution
only includes getters and setters
$user->getLocationPoint()->getCountry()->getName();
35.
Object Calisthenics
Rule 4: Only one dot per line
‣ A chain of a unique object, through the usage of a
fluent interface
$filterChain->addFilter(new Zend_Filter_Alpha())
->addFilter(new Zend_Filter_StringToLower());
36.
Object Calisthenics
Rule 5: Do not abbreviate
‣ Do not abbreviate
38.
Object Calisthenics
Rule 5: Do not abbreviate
‣ Think about it... why do you want to abbreviate?
39.
Object Calisthenics
Rule 5: Do not abbreviate
‣ Think about it... why do you want to abbreviate?
‣ Write the same name repeatedly?
40.
Object Calisthenics
Rule 5: Do not abbreviate
‣ Think about it... why do you want to abbreviate?
‣ Write the same name repeatedly?
‣ Then your method is reused multiple times,
signalling a code duplication.
41.
Object Calisthenics
Rule 5: Do not abbreviate
‣ Think about it... why do you want to abbreviate?
‣ Write the same name repeatedly?
‣ Then your method is reused multiple times,
signalling a code duplication.
‣ Method name too long?
42.
Object Calisthenics
Rule 5: Do not abbreviate
‣ Think about it... why do you want to abbreviate?
‣ Write the same name repeatedly?
‣ Then your method is reused multiple times,
signalling a code duplication.
‣ Method name too long?
‣ Maybe your class has multiple responsibilities or it
is missing a helper class (bad architecture).
43.
Object Calisthenics
Rule 5: Do not abbreviate
‣ Think about it... why do you want to abbreviate?
‣ Write the same name repeatedly?
‣ Then your method is reused multiple times,
signalling a code duplication.
‣ Method name too long?
‣ Maybe your class has multiple responsibilities or it
is missing a helper class (bad architecture).
44.
Object Calisthenics
Rule 6: Keep your entities small
‣ Keep your entities small
45.
Object Calisthenics
Rule 6: Keep your entities small
‣ Original rule: 50 lines per class
46.
Object Calisthenics
Rule 6: Keep your entities small
‣ Adapted to PHP: 100 lines per class and no more than
15 classes per package.
‣ The change is necessary because of the lack of rule for
documentation, which can easily occupy up to 50% of
the lines of a class.
47.
Object Calisthenics
Rule 7: Do not create classes with more than 2 instance variables
‣ Do not create classes with more than 2 instance
variables
48.
Object Calisthenics
Rule 7: Do not create classes with more than 2 instance variables
‣ Objective:
‣ Low cohesion
‣ Better encapsulation
49.
Object Calisthenics
Rule 7: Do not create classes with more than 2 instance variables
‣ The original rule points to 2 instance variables
‣ To PHP, the suggestion is no more than 5 variables
50.
Object Calisthenics
Rule 8: Use first class collections
‣ Use first class collections
51.
Object Calisthenics
Rule 8: Use first class collections
‣ The rule is simple: Any class that contains a collection
(array to PHP), cannot contain any other properties
52.
Object Calisthenics
Rule 8: Use first class collections
‣ Objectives:
‣ Specific behaviors have a good place to stay
‣ Filtering, combining, mapping, ...
53.
Object Calisthenics
Rule 8: Use first class collections
‣ DoctrineCommonCollectionsArrayCollection
‣ Countable
‣ IteratorAggregate (inherits Traversable)
‣ ArrayAccess
54.
Object Calisthenics
Rule 9: Do not create getter/setter methods to properties
‣ Do not create getter/setter methods to properties
55.
Object Calisthenics
Rule 9: Do not create getter/setter methods to properties
‣ Non-applicable to PHP due to language’s nature
56.
Object Calisthenics
Rule 9: Do not create getter/setter methods to properties
/**
* THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE.
*/
class ApplicationCoreDomainUserModelUserProxy
! extends ApplicationCoreDomainUserModelUser
! implements DoctrineORMProxyProxy
{
// ...
public function getId()
{
$this->__load();
return parent::getId();
}
public function setId($id)
{
$this->__load();
return parent::setId($id);
}
// ...
}
57.
Object Calisthenics
“Rule 10”: Document your code!
‣ Document your code!!!!!!!!!!!!!!!!!
58.
Object Calisthenics
That’s all folks!
‣ Questions?
@guilhermeblanco
http://github.com/guilhermeblanco