I started to write this post as follow up for clean and sustainable code post. In the middle of writing, I've realized I have this approach to ever repository I meet.
Imagine it like a working desk. But not your usual stable place where you work every day. Instead, you are assigned to a new desk of a former employee, who worked in the company for 5 years and as a bonus - it was the CTO. For you, it's a mess.
What is the first thing we do? We'll prepare it for hard work.
I get to 2-3 new projects/week and during the last couple of years I've noticed I repeat the same preparing process before work itself. It makes me much more effective and creates a very intuitive environment to work in.
Without this file, every file has a different number of spaces, tabs, line-endings... and everything else we can't see.
Well, until you have errors like:
Or creatively structured code like:
<?php
class SomeClass
{
public function someMethod()
{
}
}
We don't need these problems, it's the computers' job.
This takes 1 minute to set up and commit:
# .editorconfig
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4
✅
vendor
The easier miss-location, that works as default on some operation systems, is this:
{
"config": {
"vendor-dir": "Vendor"
}
}
It might be a great feeling to be creative for various reasons, but most PHP tools are not ready for this, e.g. PHPStan and Rector fail here.
Unless there is some supercritical issue, I always make it a standard way:
-{
- "config": {
- "vendor-dir": "Vendor"
- }
-}
✅
/src
In times old so I can't remember, code was located randomly. Then PSR-0 came, then PSR-4. Many tools depend on PSR-4, so another standard naturally came to my toolset.
Keep source code in /src
.
That means only source code needed for production, so:
Once we rule in place know that every command, that works with PHP code will get only one argument: src
vendor/bin/ecs c src
vendor/bin/phpstan a src
vendor/bin/rector p src
✅
Saying the one above, I apply the same for other content:
bin
ci
configs
templates
translations
migration
...and so on.
You may know it as:
1 level architecture.
It's very intuitive to use, based on UX, DX and well... human brain. We tend to choose simpler solutions over complex ones. Often it leads to crappy application design.
I have a special case for Rector, coding standards, PHPStan rules, utils that helps in development, but aren't part of the project itself → utils/<project>/src
✅
fs
, ps
, pu
... 2 Chars Shortcuts for Tools that Help Mefs
ps
pu
6 characters, even "characters" has 10 characters.
I can't imagine to code without them. What are they?
vendor/bin/ecs check src tests --fix
vendor/bin/phpstan analyse src tests
vendor/bin/phpunit
Well, now you know I use aliases in my bash. It's the ultimate skill, because your brain gets much more space to think.
"But every project has different directories.
Do you use some uber hack alias for every single project?"
That's right, in one project it is:
vendor/bin/ecs check src tests --fix
in another it is:
vendor/bin/ecs check src packages tests --fix
Well, this how my bash aliases look like:
alias fs="composer fix-cs"
alias ps="composer phpstan"
alias pu="vendor/bin/phpunit"
I never change them. So where is the dynamic part?
Have you heard of composer scripts?
In every project I came to, I set up dev dependencies and scripts first:
{
"require-dev": {
"symplify/easy-coding-standard": "^7.1",
"phpstan/phpstan": "^0.12",
"phpunit/phpunit": "^8.5"
},
"scripts": {
"fix-cs": "vendor/bin/ecs check bin src tests --fix --ansi",
"phpstan": "vendor/bin/phpstan analyse bin src tests --ansi --error-format symplify"
}
}
That way I can modify directories right in composer.json
.
So when I do any change in the code:
fs
ps
pu
As a side benefit, continuous integration is easier to set up and maintain:
# travis.yml
jobs:
include:
-
stage: test
name: ECS
script:
- composer check-cs
-
name: PHPStan
script:
- composer phpstan
Is there one new directory tests
to check? Just update composer.json
:
{
"require-dev": {
"symplify/easy-coding-standard": "^7.1",
"phpstan/phpstan": "^0.12",
"phpunit/phpunit": "^8.5"
},
"scripts": {
- "fix-cs": "vendor/bin/ecs check src --fix --ansi",
+ "fix-cs": "vendor/bin/ecs check src tests --fix --ansi",
- "phpstan": "vendor/bin/phpstan analyse src --ansi"
+ "phpstan": "vendor/bin/phpstan analyse src tests --ansi"
}
}
This way I also see, what directories contain PHP code, that needs to be checked.
✅
"If you want to go quickly, go alone.
If you want to go far, go together."
Happy Xmass Coding!
Do you learn from my contents or use open-souce packages like Rector every day?
Consider supporting it on GitHub Sponsors.
I'd really appreciate it!