In time and after years of use, these rules seems rather "academic". They're not helpful and shifts developer's focus too close to each code character. They need to have broader overview of code as whole instead.
Nowadays I shifted to 1 much better metric - Cognitive Complexity.
Updated with ECS 5, Neon to YAML migration and checkers
to services
migration.
Updated ECS YAML to PHP configuration since ECS 8.
Object Calisthenics are 9 language-agnostic rules to help you write better and cleaner code.
They help you to get rid of "else" statements, method chaining, long classes or functions, unreadable short names and much more.
Object Calisthenics 3.0 runs on CodeSniffer 3.0 and PHP 7.1. It brings 6 of them with fancy configuration and code examples.
If you are a coding standard nerd like me, you'll probably have more than just PSR-2 standard in your ruleset. But even if you don't, Object Calisthenics is a developer-friendly game changer for your code.
1. You don't have to know a single thing about coding standards to start
2. Simple to install
composer require object-calisthenics/phpcs-calisthenics-rules
3. You can start with 1 sniff
Quick quiz: what is this variable?
$this->di->...;
Dependency Injection? Dependency Injection Container? Who would guess it's Donation Invoice!
Rule #6 - Do Not Abbreviate checks these cases. It detects short names that are ambiguous and hard to decode.
For a quick check, just run the full config:
vendor/bin/ecs check src --config vendor/object-calisthenics/phpcs-calisthenics-rules/config/object-calisthenics.yml
You can run this locally or put to your CI and you are ready to go.
We put lots of work to README for the new release. It isn't a long text describing what exactly the rule does and how it originated - there is already a blog post for that.
Instead, README goes right to the point:
As you can see in the bottom part of screenshot, most of rules are configurable. It allows you to adapt their strictness to your specific needs and needs of your project.
Do you prefer to require min 4 chars?
<?php
// ecs.php
declare(strict_types=1);
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set('ObjectCalisthenics\Sniffs\NamingConventions\ElementNameMinimalLengthSniff')
->property('minLength', 4);
};
Do you want to add own allowed short names?
<?php
// ecs.php
declare(strict_types=1);
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
// Rule 6: Do not abbreviate
$services->set(ObjectCalisthenics\Sniffs\NamingConventions\ElementNameMinimalLengthSniff::class)
->property('minLength', 4)
// default: ["i", "id", "to", "up"]
->property('allowedShortNames', ['y', 'i', 'id', 'to', 'up']);
};
ElementNameMinimalLengthSniff
class in your IDE.That was Rule 6.
foreach ($sniffGroups as $sniffGroup) {
foreach ($sniffGroup as $sniffKey => $sniffClass) {
if (! $sniffClass instanceof Sniff) {
throw new InvalidClassTypeException;
}
}
}
foreach ($sniffGroups as $sniffGroup) {
$this->ensureIsAllInstanceOf($sniffGefroup, Sniff::class);
}
// ...
private function ensureIsAllInstanceOf(array $objects, string $type)
{
// ...
}
if ($status === self::DONE) {
$this->finish();
} else {
$this->advance();
}
if ($status === self::DONE) {
$this->finish();
return;
}
$this->advance();
->
) per Line
$this->container->getBuilder()->addDefinition(SniffRunner::class);
$containerBuilder = $this->getContainerBuilder();
$containerBuilder->addDefinition(SniffRunner::class);
class SimpleStartupController
{
// 300 lines of code
}
class SimpleStartupController
{
// 50 lines of code
}
class SomeClass
{
public function simpleLogic()
{
// 30 lines of code
}
}
class SomeClass
{
public function simpleLogic()
{
// 10 lines of code
}
}
class SomeClass
{
// 20 properties
}
class SomeClass
{
// 5 properties
}
class SomeClass
{
// 20 methods
}
class SomeClass
{
// 5 methods
}
Classes should not contain public properties.
class ImmutableBankAccount
{
public $currency = 'USD';
class ImmutableBankAccount
{
private $currency = 'USD';
Method should represent behavior, not set values.
private $amount;
public function setAmount(int $amount)
{
$this->amount = $amount;
}
}
private $amount;
public function withdrawAmount(int $withdrawnAmount)
{
$this->amount -= $withdrawnAmount;
}
}
Check the README to see how to use them and configure them.
There are 3 more rules to complete the list from the original manifesto:
They are mostly related to DDD (Domain Driven Design), too strict to use in practise or too vague to cover them with semantic rule.
Last but not least, I'd like to personally thank contributors who helped to make this version happen as it is:
Without your help, this would not have been possible. Thank you guys.
To find more details about this release see Release notes on Github.