We are here since some time already but until now we didn’t write any post. We would like to change it so we want to write posts regularly. Today, we will try to describe architecture used in our open source project - “FileArchive“.
“FileArchive” is a project developed by us and others folks during PHPackaton 2014.
The main goal of the project was to show that the frameworks, delivery systems and persitence layers are just implementation details. Such approach is called Hexagonal Architecture or Clean Architecture. We used BDD in this project as well.
Our application allows to create files archives (backups) and upload those achives to different places (ex local filesystem, ftp) and cloud services (ex: dropbox, amazon storage, bit torrent sync)
The main repository – FileArchive
Main repository contains:
- Two layers of tests (automatic specifications)
- UseCases – modules representing use cases of our application
- Model – interfaces and main business objects in the system
- Concrete implementations for Model (InMemory) Ad. 1 Layers of tests (automatic specifications):
- Business acceptance criteria implemented using Behat 3.
- Automatic specification of code units using Phpspec.
Ad. 2 Use cases: Each use case in application is separate single class. We implemented such use cases:
- create archive
- listing archives
- upload archive to the cloud You can find DTO (Data Transfer Object) in the use case layer as well. We are using DTOs as UseCase input and output. This way different delivery system can communiate with UseCase (Behat, ConsoleCommand, Web).
Ad. 3 Model
In application we define 3 abstract model modules:
- It represents source of files. Archive will be created base on that source - FileSource
- It represents archive, when all our files will be stored - Archive
- It represents adapters which will be used to upload archive at different cloud services - UploadProvider
Second repository – delivery system in Symfony2
In this repository you can find 3 bundles and doctrine persistence adapter:
- CoreBundle is main delivery bundle, where we register all needed classes.
- ConsoleCommandBundle depends from CoreBundle. Adds console command for use cases.
- WebBundle depends from CoreBundle. Adds web interface for use cases.
- DoctrineAdapter module integrating Doctrine with application, so archives can be saved in database.
Architecture Schema draft
- Delivery mechanism and application are separated (Web, Console, Behat):
- Very quick test suites:
- Application use cases in one place, so we can tell what is application doing:
- We do not care about persistence layer until we should – Doctrine or InMemory
- Plugin aware architecture
We started the work from business features definition.We did impact mapping session with whole team and afterwards we could decide which features will be implemented. We wrote our features in “Gherkin” format and defined scenarios for them. We can easily use Behat to convert those features into automatic business criteria checks using really simple “InMemory” adapters. We planed architecture of system using phpspec - it allows to plan communication base on abstraction (interfaces). We developed really simple InMemory modules when communication was planned . It helped us to pass our acceptance criteria. Later development was mostly plugins development. We made plugin for Gaufrette and plugin for Doctrine without touching the application use cases.
We hope that now you will understand that we can write application based on business needs and business use case. Framework and Database are just details that aren’t so important. We should treat those details like plugins. If you like us or just the idea please vote at “FileArchive” in PHPackaton 2014 facebook survey.