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:

  1. A request is made to our project (will be done at the very last moment).

  2. Something that is responsible for appeals, calls from App layer command.

  3. The command calls repositories to work with data, processes something, etc., and in response returns the result DTO.

    1. The repository knocks on the DB to get data.

    2. 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 initto 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 Appwhich 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.cachethen 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 binin which we will store executable files?

And our first file is – deptrac.shwhich 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 -> Directoriesthere 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 Rootand folders var And vendor How ExcludedNow 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 .ideaand 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.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *