How Many Days of Technical Debt Has your PHP Project
Why?
Sonarcube is an external tool that must be checked manually. It's an extra obstacle and we barely checked it every month or two.
Much better approach is CI-based feedback loop. Use PHPStan and cognitive complexity instead.
Every project has technical dept. But how would you measure it? With cognitive complexity? The age of the framework? Any other guess?
This year I've started to use CI service, which tells you the number in days. And it works pretty well... how many days Rector has? Keep on learning.

How Reliable is Technical Dept Metric?
When I first analyzed Rector, top 5 worst classes had these in common:
- "instanceof programming", e.g., 10-15 cases of
instanceof
, then do return some logic - 30-50 lines long methods within 1 class
- classes of length 200-500 lines
- pain points I knew were there, but I was afraid to do something about it
As the first experiment, I picked a class that had 5 hours and 40 minutes of technical debt, and I gradually converted it to collector pattern.
Do you want to see real code? Look at this PR with NodeTypeResolver
decoupling to 10 new classes.
I Thought Removing Legacy Would be Fun...
...but removing my legacy code was rather painful. I had to load huge methods to my working memory, think about relations of huge monolithic class and try to split into the smallest standalone pieces.
After 3 hours of work, I was exhausted, but CI was passing, and the god class was gone. I pushed my work, merged the PR to the master
, and waited for SonarCloud analysis... from 5:40 I got into 2:40. What?
After all this work, only such a small improvement? Don't take me wrong; the code was much improved, I'm just used to work more effectively with Rector-wave refactoring approach... no more from months to days?
This process taught me a lesson:
The legacy code will always be there. Observe it, measure it and remove it.
The later you start, the more it hurts. No matter what.
Since then, I'm adding SonarCube on every project I work on, so I know (not just feel):
- what is the pain point,
- and where should we put the effort...
...to keep code base fit for years
Do you wonder how many days you have on your back? 10, 50 or over 100? Add your first SonarCube check into the CI and share with us in comments ↓
How to add SonarCube to your Github Project in 6 Steps?
SonarCube is free for open-source and has a 1-week trial for private projects. I tried the 1-week trial on one private project, and then I saw the debt... 365, hours days... you have to love it :D.
1. Add Project on SonarCloud

2. Authorize Your Github Project

Add the file and commit to master
.
3. Add Github Action
We need to have a way to tell the Sonar that new code was pushed. That's what Github Actions are for.
Add new workflow:
# .github/workflows/sonarcube.yaml
name: Sonar
on: push
jobs:
sonar_cloud:
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected]
with:
# sonar needs non-shallow clone
fetch-depth: 10000
- uses: sonarsource/[email protected]
env:
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
As you can see, there are 2 tokens to authorize.
How to get Tokens?
- https://github.com/settings/tokens →
ACCESS_TOKEN
- https://sonarcloud.io/account/security →
SONAR_TOKEN
Where to place Them?
Add both tokens to your secrets sections in your repository: https://github.com/TomasVotruba/tomasvotruba.com/settings/secrets
4. Add Badge for Quick Link to SonarCloud Analysis
What is analysis good for if you can't reach it from your README
? Be sure to add it there, so you can enter it quickly and share your excellent results with others.
- You can use the standard link: SonarCube
- But I went for fancier custom badge (where you can add your technical dept days number):
[](https://sonarcloud.io/dashboard?id=TomasVotruba_tomasvotruba.com)
Almost done...
5. Where is the Code?
We still have to tell SonarCube where to look for the src
code. To do this, we need to add sonar-project.properties
.
# sonar-project.properties
# see https://sonarcloud.io/documentation/project-administration/narrowing-the-focus/
sonar.organization=TomasVotruba
sonar.projectKey=tomasvotruba.com
# relative paths to the source, wildcards don't work
sonar.sources=src
To get organization
and and projectKey
, just split the key (TomasVotruba_tomasvotruba.com
) by _
.
6. Remove Spam Bot
Do this AFTER the first analysis of master
branch is completed. If you do it earlier, the Github Action will not work.
There is a price for all the excellent features... you need to tolerate SonarCube spam bot on every commit.

I hated it and wanted to delete all this Sonar-spam from my repositories, but there is one solution out of it.
Go to Github installations:

And remove it:

We only need it for the first contact. Instead of it, you can authorize with Github Actions.
And that should be it! (If not, let me know in comments.)

Trouble Shooting
"Please add the secret GITHUB_TOKEN to the GitHub action for SonarCloud"
If you see this message, don'T try to add GITHUB_TOKEN
to your Secrets in GitHub repository. It won't let you.
Instead, re-use already existing secret in your .github/workflows/sonarcube.yaml
:
# .github/workflows/sonarcube.yaml
# ...
- uses: sonarsource/[email protected]
env:
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ GITHUB_TOKEN: ${{ secrets.SONAR_TOKEN }}
Dual Analysis?
When CI fails for having both automatic and Github Action analysis, go to your project on SonarCube and disable it:

"Project was never analyzed. A regular analysis is required before a branch analysis."
I tried many paths, but I'm not aware of any specific solution for this. Delete project on Sonarcloud, hide local GitHub Action workflow and star over.
Now you see your weakest points and Fight the Hydra with courage!
Happy coding!
Have you find this post useful? Do you want more?
Follow me on Twitter, RSS or support me on GitHub Sponsors.