В этой серии статей мы строим программное обеспечение марсохода в соответствии со следующими спецификациями. Это позволит применить нам на практике следующие подходы:

  • Monolithic Repositories — MonoRepo (Монолитные репозитории)
  • Command/Query Responsibility Segregation — CQRS (Сегрегация ответственности на чтение и запись)
  • Event Sourcing — ES (События как источник)
  • Test Driven Development — TDD (Разработка через тестирование)

Оглавление
Марсоход, Введение
Марсоход, Инициализация
Марсоход, Посадка

Cначала нам нужно инициализировать наш проект.

Создание репозитория


Давайте начнем с создания нового git-репозитория:

mkdir rover
cd rover
git init

Поскольку мы собираемся использовать Composer, создадим composer.json:

{
    "name": "mars-rover/mars-rover",
    "license": "MIT",
    "type": "project",
    "description": "Mars Rover",
    "require": {
        "php": "^7.0"
    }
}

Добавим .gitignore для игнорирования файлов сторонних библиотек в репозитории:

# Third Party libraries
/vendor/

Закончив с созданием репозитория, запустим composer:

composer install --optimize-autoloader

Этого будет достаточно для первого коммита:

git add composer.json .gitignore
git commit -m '0: Created project'

Создание navigation-пакета


Посмотрев на декомпозицию задачи, мы увидим, что задачи можно выделить в write-only и read-only:

  1. Посадка ровера на Марс — write-only
  2. Вождение ровера — write-only
  3. Запрос местоположения — read-only

Поскольку мы хотим придерживаться принципу CQRS, положим write-only логику отдельно от read-only. Посадка и вождение — это все про навигацию, поэтому начнем с него:

git checkout -b 1-navigation
mkdir -p packages/navigation
cd packages/navigation

Создаем composer.json для нового пакета:

{
    "name": "mars-rover/navigation",
    "license": "MIT",
    "type": "library",
    "description": "Mars Rover - Navigation",
    "autoload": {
        "psr-4": { "MarsRover\\Navigation\\": "src/MarsRover/Navigation" }
    },
    "require": {
        "php": "^7.0"
    },
    "require-dev": {
        "memio/spec-gen": "^0.6"
    }
}

В качестве тестовой платформы возьмем phpspec, и для большинства тестов мы будем использовать ее расширение SpecGen. Для этого нужно создать в корне проекта phpspec.yml.dist:

extensions:
    Memio\SpecGen\MemioSpecGenExtension: ~

Примечание: Для получения более подробной информации о phpspec смотрите статью.
Наконец, нам нужно настроить git для этого пакета путем создания .gitignore файла:

# Configuration
/phpspec.yml

# Third Party libraries
/vendor/
/composer.lock

На этом мы закончили конфигурирование нашего пакета, и теперь можем запустить Composer:

composer install --optimize-autoloader

Зафиксируем наши действия во втором коммите:

git add -A
git commit -m '1: Created Navigation package'

Добавление navigation-пакета в проект


Вернемся к корню проекта:

cd ../../

Одним из преимуществ MonoRepo является возможность выполнять тесты всех пакетов одной командой. Дл этого нам нужно прописать зависимость от navigation в composer.json файле нашего основного проекта:

{
    "name": "mars-rover/mars-rover",
    "license": "MIT",
    "type": "project",
    "description": "Mars Rover",
    "repositories": [
        {
            "type": "path",
            "url": "./packages/*"
        }
    ],
    "require": {
        "mars-rover/navigation": "*@dev",
        "php": "^7.0"
    }
}

По-умолчанию Composer ищет пакеты только в Packagist. Добавив новую секцию repositories мы говорим ему проверить наличие пакетов еще и локально в ./packages, что позволяет нам использовать найденные пакеты в секции require.

Также нам нужно сообщить менеджеру пакетов какую версию мы бы хотели, но в монорепозитории все пакеты имеют одинаковую версию, поэтому мы просто используем * (любая). Но чтобы иметь возможность использовать последние изменения, не только с тегами версий, нам необходимо указать предпочитаемую стабильность (@dev).

Ну и раз уж мы используем phpspec для наших тестов, поставим дев-зависимость в основном проекте и на него:

composer require --dev phpspec/phpspec:^3.0

phpspec будет искать тесты в корне проекта. Нам нужно создать phpspec.yml.dist, чтобы сообщить о наличии navigation-пакета:

suites:
    navigation:
        namespace: 'MarsRover\Navigation'
        src_path: packages/navigation/src
        spec_path: packages/navigation

Для игнорирования локальной конфигурации также обновим .gitignore:

# Configuration
/phpspec.yml

# Third Party libraries
/vendor/

Вот оно! Теперь мы можем запустить Composer и затем phpspec:

composer update --optimize-autoloader
./vendor/bin/phpspec run

Закоммитим все это:

git add -A
git commit -m '1: Added navigation package to main project'

И смерджимся с мастер-веткой:

git checkout master
git merge --no-ff 1-navigation

Заключение


C Composer мы можем создавать много макетов внутри одного репозитория, а применяя подход MonoRepo — запускать все тесты одной командой.

Что дальше


В следующей статье мы займемся внутренней частью задачи “Посадка ровера на Марс”, продемонстрировав пример работы Event Sourcing и TDD.

Предыдущая часть: Марсоход, Введение
Следующая часть: Марсоход, Посадка
Поделиться с друзьями
-->

Комментарии (2)


  1. Fedot
    14.11.2016 16:02
    +1

    По моему игнорирование composer.lock в конечном коде, самое плохое что можно предложить.
    Этот файл фиксирует точные версии всех установленных пакетов, что бы при деплое, и при разработке можно было быть уверенным что новые версии будет соответствовать тем с которыми были выполнялись тесты.
    Иначе можно получить ошибки при деплое, так как версия пакета может отличаться от той с которой проводились тесты.


    1. iGusev
      14.11.2016 16:12

      В целом да, но в частности — внешних зависимостей, кроме dev, пока ещё нет, а при работе с монорепозиторием зависимость всегда последняя (для внутренних репозиторий).