Skip to content

Commit

Permalink
Merge pull request #58 from object-calisthenics/easy-coding-standard
Browse files Browse the repository at this point in the history
Easy coding standard enabled + simplify and unite sniff structure + move rule #8
  • Loading branch information
Tomáš Votruba committed Apr 10, 2017
2 parents ad3b077 + f383043 commit d0ff24e
Show file tree
Hide file tree
Showing 55 changed files with 704 additions and 1,001 deletions.
165 changes: 59 additions & 106 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,48 @@
[![Build Status](https://img.shields.io/travis/object-calisthenics/phpcs-calisthenics-rules.svg?style=flat-square)](https://travis-ci.org/object-calisthenics/phpcs-calisthenics-rules)
[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/object-calisthenics/phpcs-calisthenics-rules.svg?style=flat-square)](https://scrutinizer-ci.com/g/object-calisthenics/phpcs-calisthenics-rules)
[![Downloads](https://img.shields.io/packagist/dt/object-calisthenics/phpcs-calisthenics-rules.svg?style=flat-square)](https://packagist.org/packages/object-calisthenics/phpcs-calisthenics-rules)
[![PHPStan](https://img.shields.io/badge/PHPStan-enabled-brightgreen.svg?style=flat-square)](https://github.com/phpstan/phpstan)

Object Calisthenics are **set of rules in object-oriented code, that focuses of maintainability, readability, testability and comprehensibility**.
Object Calisthenics are **set of rules in object-oriented code, that focuses of maintainability, readability, testability and comprehensibility**. We're **pragmatic first** - they are easy to use all together or one by one.

### Where to read more about Object Calisthenics?

### Why Should You Use This in Your Project?

Are you interested in **motivation and reasons behind them**?
[Read post by *William Durand*](http://williamdurand.fr/2013/06/03/object-calisthenics/) or [post by *Diego Mariani*](https://medium.com/web-engineering-vox/improving-code-quality-with-object-calisthenics-aa4ad67a61f1).

- [Read post by William Durand](http://williamdurand.fr/2013/06/03/object-calisthenics/) or
- [post by Diego Mariani](https://medium.com/web-engineering-vox/improving-code-quality-with-object-calisthenics-aa4ad67a61f1).

Do you **prefer slides**?

- [Here are 58 of them in presentation by Guilherme Blanco](https://www.slideshare.net/guilhermeblanco/object-calisthenics-applied-to-php), the founding father of this project.
Do you prefer slides? [Check presentation by *Guilherme Blanco*](https://www.slideshare.net/guilhermeblanco/object-calisthenics-applied-to-php).


## Install

Via composer:

```sh
composer require object-calisthenics/phpcs-calisthenics-rules "squizlabs/php_codesniffer:3.0.0RC4" --dev
```

Then, enable it as part of your CodeSniffer ruleset (ie. `ruleset.xml` in root project directory):
## Usage

```xml
<!-- ruleset.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="Project">
<rule ref="vendor/object-calisthenics/phpcs-calisthenics-rules/src/ObjectCalisthenics/ruleset.xml"/>
</ruleset>
### Via CLI

```bash
vendor/bin/phpcs src tests --standard=vendor/object-calisthenics/phpcs-calisthenics-rules/src/ObjectCalisthenics/ruleset.xml
```

### The Best to Start With: Single Sniff via CLI

```bash
vendor/bin/phpcs src tests --standard=vendor/object-calisthenics/phpcs-calisthenics-rules/src/ObjectCalisthenics/ruleset.xml --sniffs=ObjectCalisthenics.Classes.ForbiddenPublicProperty
```

## Implemented Rules
## Implemented Rule Sniffs

### 1. Only One Level of Indentation per Method

[Read explanation with code examples](http://williamdurand.fr/2013/06/03/object-calisthenics/#only-one-level-of-indentation-per-method).
### 1. [Only One Level of Indentation per Method](http://williamdurand.fr/2013/06/03/object-calisthenics/#1-only-one-level-of-indentation-per-method)

#### Sniff
**Apply in CLI?** `--sniffs=ObjectCalisthenics.Metrics.MaxNestingLevel`
**The class?** [`ObjectCalisthenics\Sniffs\Metrics\MaxNestingLevelSniff`](/src/ObjectCalisthenics/Sniffs/Metrics/MaxNestingLevelSniff.php)

- [`ObjectCalisthenics\Sniffs\Metrics\MaxNestingLevelSniff`](/src/ObjectCalisthenics/Sniffs/Metrics/MaxNestingLevelSniff.php)
#### Configurable

This sniff is **configurable**:
In CodeSniffer XML:

```xml
<!-- ruleset.xml -->
Expand All @@ -61,24 +56,20 @@ This sniff is **configurable**:
```


### 2. Do Not Use "else" Keyword

[Read explanation with code examples](http://williamdurand.fr/2013/06/03/object-calisthenics/#dont-use-the-else-keyword)

#### Sniff
### 2. [Do Not Use "else" Keyword](http://williamdurand.fr/2013/06/03/object-calisthenics/#2-dont-use-the-else-keyword)

- [`ObjectCalisthenics\Sniffs\ControlStructures\NoElseSniff`](/src/ObjectCalisthenics/Sniffs/ControlStructures/NoElseSniff.php)
**Apply in CLI?** `--sniffs=ObjectCalisthenics.ControlStructures.NoElseSniff`
**The class?** [`ObjectCalisthenics\Sniffs\ControlStructures\NoElseSniff`](/src/ObjectCalisthenics/Sniffs/ControlStructures/NoElseSniff.php)


### 5. Use Only One Object Operator (`->`) per Line
### 5. [Use Only One Object Operator (`->`) per Line](http://williamdurand.fr/2013/06/03/object-calisthenics/#5-one-dot-per-line)

[Read explanation with code examples](http://williamdurand.fr/2013/06/03/object-calisthenics/#one-dot-per-line)
**Apply in CLI?** `--sniffs=ObjectCalisthenics.CodeAnalysis.OneObjectOperatorPerLine`
**The class?** [`ObjectCalisthenics\Sniffs\CodeAnalysis\OneObjectOperatorPerLineSniff`](/src/ObjectCalisthenics\Sniffs\CodeAnalysis\OneObjectOperatorPerLineSniff.php)

#### Sniff
#### Configurable

- [`ObjectCalisthenics\Sniffs\CodeAnalysis\OneObjectOperatorPerLineSniff`](/src/ObjectCalisthenics\Sniffs\CodeAnalysis\OneObjectOperatorPerLineSniff.php)

This sniff is **configurable**:
In CodeSniffer XML:

```xml
<!-- ruleset.xml -->
Expand All @@ -91,59 +82,37 @@ This sniff is **configurable**:
</rule>
```

### 6. Do not Abbreviate

[Read explanation](http://williamdurand.fr/2013/06/03/object-calisthenics/#dont-abbreviate)
### 6. [Do not Abbreviate](http://williamdurand.fr/2013/06/03/object-calisthenics/#6-dont-abbreviate)

#### Sniffs
This is concerned to class, trait, interface, constant, function and variable names.

- [`ObjectCalisthenics\Sniffs\NamingConventions\ClassNameLengthSniff`](/src/ObjectCalisthenics\Sniffs\NamingConventions\ClassNameLengthSniff.php)
- [`ObjectCalisthenics\Sniffs\NamingConventions\ConstantNameLengthSniff`](/src/ObjectCalisthenics\Sniffs\NamingConventions\ConstantNameLengthSniff.php)
- [`ObjectCalisthenics\Sniffs\NamingConventions\FunctionNameLengthSniff`](/src/ObjectCalisthenics\Sniffs\NamingConventions\FunctionNameLengthSniff.php)
- [`ObjectCalisthenics\Sniffs\NamingConventions\VariableNameLengthSniff`](/src/ObjectCalisthenics\Sniffs\NamingConventions\VariableNameLengthSniff.php)
**Apply in CLI?** `--sniffs=ObjectCalisthenics.NamingConventions.ElementNameMinimalLength`
**The class?**: [`ObjectCalisthenics\Sniffs\NamingConventions\ElementNameMinimalLengthSniff`](/src/ObjectCalisthenics\Sniffs\NamingConventions\ElementNameMinimalLengthSniff.php)

These sniffs are **configurable**:
#### Configurable

```xml
<!-- ruleset.xml -->
<rule ref="ObjectCalisthenics.NamingConventions.ClassNameLength">
<properties>
<property name="minLength" value="3"/>
</properties>
</rule>
<rule ref="ObjectCalisthenics.NamingConventions.ConstantNameLength">
<properties>
<property name="minLength" value="3"/>
</properties>
</rule>
<rule ref="ObjectCalisthenics.NamingConventions.FunctionNameLength">
<properties>
<property name="minLength" value="3"/>
</properties>
</rule>
<rule ref="ObjectCalisthenics.NamingConventions.VariableNameLength">
<rule ref="ObjectCalisthenics.NamingConventions.ElementNameMinimalLength">
<properties>
<property name="minLength" value="3"/>
<property name="propertiesToBeSkipped" type="array"
value="id"
<property name="allowedShortNames" type="array"
value="i,id,to"
/>
</properties>
</rule>
```


### 7. Keep Your Classes Small

[Read explanation](http://williamdurand.fr/2013/06/03/object-calisthenics/#keep-all-entities-small)
### 7. [Keep Your Classes Small](http://williamdurand.fr/2013/06/03/object-calisthenics/#7-keep-all-entities-small)

#### Sniffs
**Apply in CLI?** `--sniffs=ObjectCalisthenics.Files.ClassElementLength,ObjectCalisthenics.Files.FunctionLengthSniff,ObjectCalisthenics.Metrics.MethodPerClassLimit,ObjectCalisthenics.Metrics.PropertyPerClassLimitSniff`
**Classes?** [`ObjectCalisthenics\Sniffs\Files\ClassTraitAndInterfaceLengthSniff`](/src/ObjectCalisthenics\Sniffs\Files\ClassTraitAndInterfaceLengthSniff.php),[`ObjectCalisthenics\Sniffs\Metrics\MethodPerClassLimitSniff`](/src/ObjectCalisthenics/Sniffs/Metrics/MethodPerClassLimitSniff.php), [`ObjectCalisthenics\Sniffs\Metrics\PropertyPerClassLimitSniff`](/src/ObjectCalisthenics/Sniffs/Metrics/PropertyPerClassLimitSniff.php), [`ObjectCalisthenics\Sniffs\Files\FunctionLengthSniff`](/src/ObjectCalisthenics/Sniffs/Files/FunctionLengthSniff.php)

- [`ObjectCalisthenics\Sniffs\Files\ClassElementLengthSniff`](/src/ObjectCalisthenics\Sniffs\Files\ClassElementLengthSniff.php)
- [`ObjectCalisthenics\Sniffs\Metrics\MethodPerClassLimitSniff`](/src/ObjectCalisthenics/Sniffs/Metrics/MethodPerClassLimitSniff.php)
- [`ObjectCalisthenics\Sniffs\Metrics\PropertyPerClassLimitSniff`](/src/ObjectCalisthenics/Sniffs/Metrics/PropertyPerClassLimitSniff.php)
- [`ObjectCalisthenics\Sniffs\Files\FunctionLengthSniff`](/src/ObjectCalisthenics/Sniffs/Files/FunctionLengthSniff.php)
#### Configurable

These sniffs are **configurable**:
In CodeSniffer XML:

```xml
<!-- ruleset.xml -->
Expand All @@ -169,51 +138,31 @@ These sniffs are **configurable**:
</rule>
```

### 9. [Do not Use Getters and Setters](http://williamdurand.fr/2013/06/03/object-calisthenics/#9-no-getterssettersproperties)

### 8. Do Not Use Classes With More Than Two Instance Variables

[Read explanation with code examples](http://williamdurand.fr/2013/06/03/object-calisthenics/#no-classes-with-more-than-two-instance-variables)

#### Sniff

- [`ObjectCalisthenics\Sniffs\CodeAnalysis\InstancePropertyPerClassLimitSniff`](/src/ObjectCalisthenics\Sniffs\CodeAnalysis\InstancePropertyPerClassLimitSniff.php)
**Apply in CLI?** `--sniffs=ObjectCalisthenics.Classes.ForbiddenPublicProperty,ObjectCalisthenics.NamingConventions.NoSetter`
**Classes?** [`ObjectCalisthenics\Sniffs\Classes\ForbiddenPublicPropertySniff`](/src/ObjectCalisthenics\Sniffs\Classes\ForbiddenPublicPropertySniff.php),[`ObjectCalisthenics\Sniffs\NamingConventions\NoSetterSniff`](/src/ObjectCalisthenics\Sniffs\NamingConventions\NoSetterSniff.php)

This sniff is **configurable**:

```xml
<!-- ruleset.xml -->
<rule ref="ObjectCalisthenics.CodeAnalysis.InstancePropertyPerClassLimit">
<properties>
<property name="maxCount" value="2"/>
</properties>
</rule>
```


### 9. Do not Use Getters and Setters

[Read explanation with code examples](http://williamdurand.fr/2013/06/03/object-calisthenics/#no-getterssettersproperties)
This rules is partially related to [Domain Driven Design](https://github.com/dddinphp).

- Classes should not contain public properties.
- Method should [represent behavior](http://whitewashing.de/2012/08/22/building_an_object_model__no_setters_allowed.html), not set values.

#### Sniffs
---

- [`ObjectCalisthenics\Sniffs\Classes\ForbiddenPublicPropertySniff`](/src/ObjectCalisthenics\Sniffs\Classes\ForbiddenPublicPropertySniff.php)
- [`ObjectCalisthenics\Sniffs\NamingConventions\NoSetterSniff`](/src/ObjectCalisthenics\Sniffs\NamingConventions\NoSetterSniff.php)
### Not Implemented Rules - Too Strict, Vague or Annoying

---
While using in practise, we found these rule to be too much strict, vague or even annoying, rather then helping to write cleaner and more pragmatic code.

## Not Implemented Rules
They're also closely related with [Domain Driven Design](https://github.com/dddinphp).

### 3. Wrap Primitive Types and Strings

[Read explanation](http://williamdurand.fr/2013/06/03/object-calisthenics/#wrap-all-primitives-and-strings)
#### 3. [Wrap Primitive Types and Strings](http://williamdurand.fr/2013/06/03/object-calisthenics/#3-wrap-all-primitives-and-strings)

Since PHP 7, you can use `define(strict_types=1)` and scalar type hints:

```php
define(strict_types=1);
<?php define(strict_types=1);

final class Resolver
{
Expand All @@ -224,16 +173,20 @@ final class Resolver
}
```

For other cases, e.g. email, you can **deal with that in your [Domain via Value Objects](http://williamdurand.fr/2013/06/03/object-calisthenics/#wrap-all-primitives-and-strings)**.
For other cases, e.g. email, you can **deal with that in your [Domain via Value Objects](http://williamdurand.fr/2013/06/03/object-calisthenics/#3-wrap-all-primitives-and-strings)**.


### 4. Use First Class Collections

[Read explanation](http://williamdurand.fr/2013/06/03/object-calisthenics/#first-class-collections)
#### 4. [Use First Class Collections](http://williamdurand.fr/2013/06/03/object-calisthenics/#4-first-class-collections)

This rule makes sense, yet is too strict to be useful in practise. Even our code didn't pass it at all.


#### 8. [Do Not Use Classes With More Than Two Instance Variables](http://williamdurand.fr/2013/06/03/object-calisthenics/#8-no-classes-with-more-than-two-instance-variables)

This depends on your specific domain and approach. It doesn't make sense to make a rule for that, because it's unique per project.



## 3 Rules for Contributing

- **1 feature per PR**
Expand Down
28 changes: 10 additions & 18 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@
"license": "MIT",
"require": {
"php": "^7.1",
"squizlabs/php_codesniffer": "3.0.0RC4",
"nette/utils": "^2.4"
"squizlabs/php_codesniffer": "3.0.0RC4 as 2.8.1",
"nette/utils": "^2.4",
"slevomat/coding-standard": "^2.0"
},
"require-dev": {
"phpunit/phpunit": "^6.0",
"friendsofphp/php-cs-fixer": "^2.1",
"phpstan/phpstan": "^0.6.4",
"tracy/tracy": "^2.4"
"friendsofphp/php-cs-fixer": "^2.2",
"phpstan/phpstan": "^0.6",
"tracy/tracy": "^2.4",
"symplify/easy-coding-standard": "^1.4"
},
"autoload": {
"psr-4": {
Expand All @@ -26,18 +28,8 @@
},
"scripts": {
"complete-check": ["@phpstan", "@check-cs", "phpunit"],
"phpstan": [
"phpstan analyze src --level 5"
],
"check-cs": [
"php-cs-fixer fix src --diff --dry-run -v --rules=@Symfony,-blank_line_after_opening_tag --allow-risky yes",
"php-cs-fixer fix tests --diff --dry-run -v --rules=@Symfony,-blank_line_after_opening_tag --allow-risky yes",
"phpcs src tests --colors -p -s --extensions=php --standard=src/ObjectCalisthenics/ruleset.xml"
],
"fix-cs": [
"php-cs-fixer fix src -v --rules=@Symfony,-blank_line_after_opening_tag --allow-risky yes",
"php-cs-fixer fix tests -v --rules=@Symfony,-blank_line_after_opening_tag --allow-risky yes",
"phpcbf src tests --colors -p -s --extensions=php --standard=src/ObjectCalisthenics/ruleset.xml"
]
"phpstan": "phpstan analyze src --level 5 --configuration phpstan.neon",
"check-cs": "vendor/bin/easy-coding-standard check src tests",
"fix-cs": "vendor/bin/easy-coding-standard check src tests --fix"
}
}

0 comments on commit d0ff24e

Please sign in to comment.