Project “Drift Statistics”. Part 1. Setup
Introduction
Hey, hi everyone. We are starting a small blog about the development of a pet project. What will the project be about? Good question…
At the moment, about drift statistics. Yes, about drift statistics. The project is actually big, but we will do it in “spare parts” to expand it slowly and surely. This approach will help us improve our development and architecture skills, and will not allow us to “drown” in streams of thoughts and volumes of work.
Well, enough with the introduction, let's get started. The first part of the statistics is pilots' meetings. What? No, no, not those modern “European meetings”, but how many times and where the pilots competed with each other. Why do we need such statistics? It's very simple! When a stage is underway, commentators often say that these pilots have already met more than once, and their meeting score is N:M. And I thought, what if we just take the data, make its structure, make open access to the data through a beautiful visual interface? It's cool when you can go to the site in real time, select two pilots and see detailed or brief statistics of their meetings. Well, let's try to do this as interestingly, technologically (as it turns out) and practically as possible.
Where do we start? The project's file structure. Keep in mind that during the development process, some things may change, and some may change dramatically. This is normal, since I am not writing a ready-made article where everything is already “licked to a shine.” This is a life-time blog about the project.
File structure
Our file structure will not be tied to any framework now, since we are making an isolated project on “honest word”. What? Yes, I decided to follow the principle – write the inside of the project, and then pull something ready-made from frameworks onto it. What is the advantage? I don't know for sure yet, but I like writing isolated things that work without being tied to anything, and then suffer with transferring it to something ready-made. In fact, as practice shows, this approach is great for “studying” the core of the project, and then “studying” the work of the framework on the ready-made core. And another cool thing about this approach is that a huge part of the ready-made solution will not be used, since we will understand that we simply do not need it, and it is an eyesore.
Let me sketch out the entire structure right away, and then describe it in detail?
- config
- src
- App
- Domain
- Infrastructure
- Shared
- tests
- var
- cache
- reports
- tests
- vendor
IN config
there will be some application configs.
IN src
will contain the main application code. This folder contains 3 layers:
App – commands, events, mappers, DTOs and other things. In essence, the “first point of access” files are located here;
Domain – domain entities, interfaces and other entity parts (not to be confused with database models);
Infrastructure – repositories, working with databases and other things.
And what the Shared
folder? It's all simple – common elements: basic commands, wrappers and other “common” nonsense.
IN tests
– tests that will be divided in the same way as folders in src
. Well, or almost the same.
IN var
– reports, cache and other service history.
IN vendor
the necessary packages for development will be located.
I hope you understand the structure, but src
I'll add a little approximate logic:
A request is made to our project (will be done at the very last moment).
Something that is responsible for appeals, calls from
App
layer command.The command calls repositories to work with data, processes something, etc., and in response returns the result DTO.
The repository knocks on the DB to get data.
Mappit “raw” data in essence
Domain
and brings them back to the team
That's all. It's simple and clear. Although, it may seem redundant to you, but such architecture helps to clearly delineate areas of responsibility by layers. You will know exactly what, where and for what purpose is located. Well, and what does, respectively.
Now, let's talk about the settings and necessary packages to start our interesting project.
PHPStorm settings and composer packages
Let's start with the simple and obvious – composer packages. For now, I assume I'll need this:
{
"require-dev": {
"phpunit/phpunit": "^11.0",
"qossmic/deptrac-shim": "^1.0"
},
"require": {
"php-di/php-di": "^7.0"
}
}
Well, it's clear here, phpunit
for tests, php-di
for the dependency container. And what about deptrac-shim
?
Oh, relatively cool thing that controls you a little bit in layers. Remember, I wrote about layers: App
, Domain
, Infrastructure
? So, there is a “special” interaction between them. More precisely, who can “pull” what. For example, App
layer can use everything directly. But most often, it needs to work with Infrastructure
layer that can in Domain
layer. Why? App
omnipotent? Because it needs to both call the thing for working with the database, and also pass it data in the required format (in our case, it will be the ValueObject of the domain layer).
It's a bit complicated, but that's normal for the beginning. You'll understand everything in the process. In short, we strongly separate the layers and their use from each other. Let's set this up!
Deptrac
We execute the command vendor/bin/deptrac init
to create a configuration file deptrac.yaml
. We enter the following configuration into it:
Code deptrac.yaml
The full code can be found in the original article: Fir DEV – Project “Drift Statistics”. Part 1. Setup.
What kind of magic is going on here? It's very simple. At the beginning we indicated where to look (paths
) and what to exclude (exclude_files
). Next, we specified our layers and configured them. For example, this is how we created a layer App
which has a check type directory
and is located in src/App/
:
name: App
collectors:
- type: directory
value: src/App/.*
Then in the section ruleset
we just indicated which layer can use which layers. That's all. And when the command is executed vendor/bin/deptrac analyse
we will receive a report that will show us the correctness of the use of layers.
But deptrac itself will write the cache file directly to the root of the project. And I don't like that! It is clear that it can be excluded from git, but I made a separate folder for this var/cache
. The problem is that I did not find how to change the path to the cache file using the config. But if you run the command vendor/bin/deptrac analyse --cache-file=var/cache/.deptrac.cache
then everything is fine. This is not very convenient, since we can forget about additional keys of the CLI command. Let's create another new directory bin
in which we will store executable files?
And our first file is – deptrac.sh
which has the following simple content:
../vendor/bin/deptrac analyse --config-file=../deptrac.yaml --cache-file=../var/cache/.deptrac.cache
This will allow us to run the script with the correct settings for us, and also expand it in the future. Perhaps someday it will be possible to connect it to the project assembly (build), put a git event in the pre-commit and generally make a cool clean assembly or push.
Now, I suggest setting up phpunit to run tests just as cool as deptrac checks.
PHP Unit
Create a file in the root directory phpunit.xml
with very simple content:
phpunit.xml code
The full code can be found in the original article: Fir DEV – Project “Drift Statistics”. Part 1. Setup.
There's not much to say here, except that these sections: bootstrap="vendor/autoload.php"
, colors="true"
And cacheDirectory="var/cache"
– we specified the bootloader, turned on colors (for the beauty of the output) and specified the cache directory. testsuites
indicated the location of our tests, and in source
indicated the location of our main code. And I also love coverage. Yeah, I'm that crazy person who loves maximum code coverage… Don't judge me too harshly, everyone is crazy in their own way. That's why I added a section coverage
by default and specified 2 formats: html and xml – export to folder var/reports/tests
. Why? I will view the HTML in the browser, it is beautiful and convenient there, and we may need the XML in the future for assembly.
Now, create a folder tests
at the root of the project and add to composer.json
such a thing:
{
"autoload": {
"psr-4": {
"tests\\": "tests/"
}
}
}
This will allow you to use it inside the folder tests
namespace tests\*
. And this also needs to be written in the IDE so that it doesn't complain. Let's go to File -> Settings -> Directories
there is a folder on the right tests
. Click on the pencil and write tests\
. Save and exit. Now, click on our folder tests
right click and select Mark Directory as -> Test Source Root
. Now it glows green and we are good. Oh yeah, since we are talking about directories, then mark them according to the well-known algorithm src
How Source Root
and folders var
And vendor
How Excluded
Now everything is set up super.
Well, and finally create .gitignore
file in which you write:
vendor
.idea
var
test.php
What we did here? We explained to our git repository that we don't need to put folders under version control vendor
, var
And .idea
and also the file test.php
. Okay, stop! What is this file? test.php
? And this, guys, is the standard of one of the types of cool atomic testing! Just kidding, sometimes you just need to quickly run something to check and it's easier to write in test.php
file calls, than to write a test or go to some online resource.