Menu

component-structure

Romanov

Компонентная структура прикладных проектов

Внедрение сервисов REST API в приложения выявило необходимость пересмотра структуры проектов (на уровне дерева файлов и папок).
Статья знакомит читателя с новой структурой проектов приложений и описывает основные шаги перевода проекта со старой, gwt-центричной структуры на новую, обеспечивающую независимость компонентов приложений.

Общая структура

Папка App является корневой для разработки клиент-серверного приложения.

Приложение может иметь несколько независимых друг от друга реализаций клиентов и сервисов (сервисом здесь называется серверная часть приложения, бэкенд). Каждая реализация клиента или сервиса находится в отдельной папке, название которой начинается с соответствующего префикса

/App
    /client-...
    /client-...
    /service-...
    /service-...
    /service-...
    /service-...

Каждая реализация клиента или сервиса называется компонентом.

В совершенстве, разные компоненты независимы друг от друга: они могут быть построены на разных языках программирования и разных технологиях, и сборка каждого компонента происходит отдельно. Также каждый компонент имеет свой продукт (war, ear, javascript bundle), и продукты разных компонентов могут быть установлены на разных серверах и использоваться в разных окружениях.
Для идентификации компонентов на уровне структуры папок достаточно использовать наиболее лаконичный постфикс, однозначно идентифицирующий конкретный компонент и отличающий его от других

/App
    /client-react           // клиент на React/JS
    /client-gwt             // клиент на GWT/Java
    /service-gwt            // сервис на GWT/Java
    /service-rest-jersey    // сервис на Rest/Jersey/Java
    /service-rest-spring    // сервис на Rest/Spring/Java
    /service-php            // сервис на Soap/PHP

В случае, если у нескольких компонентов имеется общий код, следует выделять его в отдельный компонент, если возникают неоднозначности

/App
    /service-java-core          // бизнес-логика сервиса на java (общая для нескольких других компонент)
    /service-java-rest-jersey   // сервис на Rest/Jersey/Java, построенный на общем компоненте service-java-core
    /service-java-rest-spring   // сервис на Rest/Spring/Java, построенный на общем компоненте service-java-core

Однако такое архитектурное решение влечёт с неизбежностью взаимозависимости между компонентами, поэтому следует применять его только если это оправдано (например, при наличии объёмной прослойки общего кода бизнес-логики).

В действительности и в обозримом будущем для большинства приложений планируются только следующие компоненты:

/App
    /client-react           // клиент на React/JS
    /gwt                    // клиент и сервис на GWT/Java
    /service-rest           // сервис на Rest/Jersey/Java

Здесь компонент /gwt совмещает в себе клиентский и серверный код GWT (традиционно), при этом сохраняется историческое разделение клиентского и серверного кода на уровне java-пакетов

/App
    /client-react
    /gwt
        /src/java/com/technology/jep/jepriashowcase
            /client         // клиент на GWT/Java
            /server         // сервис на GWT/Java
            /shared         // общая клиент-сервисная часть на GWT/Java
    /service-rest

Структура отдельных компонентов

Внутри папки каждого компонента соблюдается структура, адекватная конкретной технологии.
Для gwt-компонента принимается без изменений историческая структура проекта, для компонента service-rest -- структура Maven-стандартная

/App
    /gwt                    // историческая структура
        /src
            /java
            /html
            /resources
        /config
        /lib
        /test

    /service-rest           // структура проекта Maven
        /src
            /main
                /java
                /webapp
            /test
                /java
        /target

Сборка приложения

Каждый компонент имеет свой сценарий сборки (для поддержания независимости компонентов). Результатом сборки является продукт, располагающийся внутри папки компонента

/App
    /client-react
        /build
            /jepriashowcase-bundle.js           // продукт
        package.json                            // сценарий сборки
    /service-rest
        /target
            jepriashowcase-service-rest.war     // продукт
        pom.xml                                 // сценарий сборки
    /gwt        
        /lib
            jepriashowcase-gwt.war              // продукт
        build.xml                               // сценарий сборки      

Поддержка обратной совместимости со старым gwt-продуктом

Исторически администрирование приложений на серверах велось посредством единых war файлов (содержащих и клиентскую, и сервисную части). Для поддержания этого механизма помимо сборки каждого продукта в отдельности, производится общая сборка проекта, суть которого -- упаковать необходимые продукты отдельных компонентов в общий продукт.
Файлы и ресурсы, необходимые для общей сборки, лежат в корне проекта

/App
    /client-react
        /build
            /jepriashowcase-bundle.js           // продукт
        package.json, ...                       // сценарии сборки
    /service-rest
        /target
            jepriashowcase-service-rest.war     // продукт
        pom.xml, ...                            // сценарии сборки
    /gwt        
        /lib
            JepRiaShowcase-gwt.war              // продукт
        build.xml, ...                          // сценарии сборки

    /lib                                        // папка общего продукта (для обратной совместимости)
        JepRiaShowcase.war                      // общий продукт, совмещающий отдельные продукты (имеет исторически сложившееся имя и расположение)
    /webapp
        /WEB-INF
            web.xml                             // web.xml для общего продукта (является ручным объединением web.xml-файлов разных компонентов)
    build.xml                                   // сценарий сборки общего продукта (поддерживает исторические команды администрирования приложения)
    dependency.properties                       // пропертисы для сборки общего продукта
    deploy.properties                           // пропертисы для сборки общего продукта

Администрирование единого war файла обеспечивает одновременное администрирование совмещённых в нём продуктов разных компонентов и создаёт единую точку входа в приложение через веб (по старому стилю).