\documentclass[j-spec.tex]{subfiles}

\begin{document}
\section{Управление проектом: сборщики проектов}
\subsection{В предыдущих сериях...}
В прошлом разделе мы рассмотрели:
\begin{itemize}
\item краткую историю;
\item что скачать, и как это выбирать;
\item какие шестерёнки крутятся внутри;
\item структуру простого и обычного проекта;
\item стандартную утилиту для создания документации;
\item сторонние инструменты автоматизации сборки.
\end{itemize}

\subsection{В этом разделе}
Будет коротко рассмотрена мотивация создания и использования сборщиков проектов (зачем это нужно), какой эволюционный путь прошли специализированные сборщики проектов, какие новые понятия появились при их использовании. Рассмотрим два самых популярных на сегодняшний день сборщика и один экзотический, но достаточно быстро набирающий обороты. Поймём какой путь проделывает чужая библиотека, чтобы попасть в наш проект и научимся публиковать собственный код, делая тем самым вклад в сообщество.
\begin{itemize}
\item \nom{Ant}{Apache Ant (англ. ant — муравей и акроним — «Another Neat Tool») — утилита для автоматизации процесса сборки программного продукта. Является кросс-платформенным аналогом утилиты make, где все команды записываются в XML-формате.}
\item \nom{Ivy}{Apache Ivy переходный пакетный менеджер. Является подпроектом Apache Ant, которому нужен для разрешения зависимостей. Внешний XML файл определяет зависимости проекта и перечисляет ресурсы, необходимые для сборки проекта. Ivy ищет и скачивает ресурсы из репозитория (приватного или публичного).};
\item \nom{Maven}{Apache Maven — фреймворк для автоматизации сборки проектов на основе описания их структуры в файлах на языке POM (англ. Project Object Model), являющемся подмножеством XML. В отличие от Ant, декларативный. Проект Maven издаётся сообществом Apache Software Foundation. Название системы является словом из языка идиш, смысл которого можно примерно выразить как «собиратель знания».};
\item \nom{Gradle}{система автоматической сборки, построенная на принципах Apache Ant и Apache Maven, но предоставляющая специалььный предметно-ориентированный диалект на языках Groovy и Kotlin вместо традиционной XML-образной формы представления конфигурации проекта.};
\item \nom{Bazel}{свободный программный продукт для автоматизации сборки и тестирования приложений. Компания Google использует внутренний инструмент под названием Blaze, и выпустила свободно распространяемый вариант с открытым исходным кодом под названием Bazel (анаграмма Blaze). Bazel впервые выпущен в марте 2015.};
\item \nom{DSL}{(англ. domain-specific language, DSL — «язык, специфический для предметной области», предметно-ориентированный язык) — компьютерный язык, специализированный для конкретной области применения (в противоположность языку общего назначения, применимому к широкому спектру областей и не учитывающему особенности конкретных сфер знаний). Построение такого языка и/или его структура данных отражают специфику решаемых с его помощью задач.}
\item \nom{XML}{англ. eXtensible Markup Language) — «расширяемый язык разметки». Рекомендован Консорциумом Всемирной паутины (W3C). Спецификация XML описывает документы и частично описывает поведение XML-процессоров (программ, читающих XML-документы и обеспечивающих доступ к их содержимому). XML разрабатывался как язык с простым формальным синтаксисом, удобный для создания и обработки документов как программами, так и человеком, с акцентом на использование в Интернете.}
\item \nom{Артефакт}{Артефакт — это любой созданный искусственно элемент программной системы. К элементам программной системы, а, следовательно, и к артефактам, могут относиться исполняемые файлы, исходные тексты, веб страницы, справочные файлы, сопроводительные документы, файлы с данными, модели и многое другое, являющееся физическим носителем информации.};
\item \nom{Репозиторий}{(англ. repository — хранилище) — место, где хранятся и поддерживаются какие-либо данные. Чаще всего данные в репозитории хранятся в виде файлов, доступных для дальнейшего распространения по сети};
\item \nom{Прокси}{(англ. proxy — уполномоченный, заместитель) промежуточный комплекс, выполняющий роль посредника между пользователем и целевым сервером, позволяющий клиентам как выполнять косвенные запросы к другим сетевым службам, так и получать ответы. Сначала клиент подключается к прокси и запрашивает какой-либо ресурс (например артефакт), затем прокси либо подключается к указанному серверу и получает ресурс у него, либо возвращает ресурс из собственного кэша.};
\end{itemize}

\subsection{Мотивация и схема (зачем это нужно и как это работает)}

% по комментарию Ильнара.
Реальный проект - это не только непосредственный код, который пишется в IDE\footnote{Чаще всего, называется бизнес-кодом или бизнес-логикой}, но и большое количество всего, что мы при этом используем - библиотеки, фреймворки и т.п. То есть, мы не пишем каждый проект «с чистого листа», использование JRE/JDK нам это явно демонстрирует, поскольку в них есть уже готовые написанные классы, реализующие некоторую функциональность (подробнее на странице \pageref{table:jdk-contents}).

\begin{frm}
\info  Всё, что так или иначе используется в проекте, кроме непосредственного кода, написанного в IDE, называется \textbf{зависимостями проекта}, поскольку код всегда «опирается» на заранее созданный инструментарий. Например, мы просто пишем строку с приветствием миру, не думая, как именно она раскладывается в массив символов. Или мы просто выводим приветствие миру в терминал, а инструментарий берёт на себя открытие вспомогательных потоков и прочие сложности.
\end{frm}

Из-за этого, \textit{единый исполняемый файл} проекта\footnote{Чаще всего, такой файл нужен для быстрого переноса и запуска проекта на устройстве, на котором не установлен JDK}, включающий в себя все зависимости, может разрастаться до нескольких сотен мегабайт, а о том, чтобы скомпилировать его со всеми зависимостям, и речи быть не может.

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

Они позволяют не привязываться к конкретным IDE и интерфейсу среды разработки. Имеют текстовое управление, что часто ускоряет процесс работы с ними на пред-продакшн серверах, где часто терминальный интерфейс.

\begin{frm}
\info Система сборки это программа, которая собирает другие программы. На вход система сборки получает исходный код, написанный разработчиком, а на выход выдаёт программу, которую уже можно запустить. Отличается от компилятора тем, что вызывает его при своей работе, а компилятор о системе сборки ничего не знает, то есть является инструментом более широкого спектра.
\end{frm}

Сборщик часто решает целый спектр задач, для решения которых компилятор не предусмотрен. Например:
\begin{itemize}
\item загрузить зависимые библиотеки;
\item скомпилировать классы модуля;
\item сгенерировать дополнительные файлы: SQL-скрипты, XML-конфиги и пр.;
\item упаковать скомпилированные классоы в архивы;
\item компилировать и запустить модульные тесты и рассчитать процент покрытия;
\item развернуть (deploy) файлы проекта на удаленный сервер;
\item генерировать документацию и отчеты.
\end{itemize}

Системы сборок имеют схожую верхнеуровневую архитектуру:
\begin{enumerate}
\item Конфигурации - собственная конфигурация, где хранятся «личные» настройки системы. Например, такие как информация о месте установки или окружении, информация о репозиториях и прочее;
\item Конфигурация модуля, где описывается место расположения проекта, его зависимости и задачи, которые требуется выполнять для проекта;
  % по комментарию Ильнара, слово "зависимости" было раскрыто выше
\item Парсеры конфигураций - парсер способный «прочитать» конфигурацию самой системы, для её настройки соответствующим образом;
\item Парсер конфигурации модуля, где некоторыми «понятными человеку» терминами описываются задачи для системы сборки;
\item Сама система — некоторая утилита + скрипт для её запуска в вашей ОС, которая после чтения всех конфигураций начнет выполнять тот или иной алгоритм, необходимый для реализации запущенной задачи;
\item Система плагинов — дополнительные подключаемые надстройки для системы, в которых описаны алгоритмы реализации типовых задач;
\item Локальный репозиторий — репозиторий (некоторое структурированное хранилище данных), расположенный на локальной машине, для кэширования запрашиваемых файлов на удаленных репозиториях.

% по комментарию Ильнара. добавил слово репозиторий в глоссарий, поскольку само понятие репы можно раскладывать целый урок (локальный, проектный, зеркало, прокси, глобальный, публичный, а чуть подробнее о структуре хранения предполагается рассказать в этом же уроке далее)
\end{enumerate}

Для языка Java основных систем сборок три:
\begin{itemize}
\item Иногда можно встретить Ant в сочетании с инструментом по управлению зависимостями Ivy, в чистом виде Ant почти никогда не применялся, описывает задачи сборки в виде XML файлов;
\item Самый популярный инструмент - это Maven, используется для JavaEE и приложений с использованием Spring Framework, основана на специальном подмножестве XML, называемом POM\footnote{(англ. Project Object Model) модель объектов проекта};
\item Gradle основной инструмент в мобильной разработке, часто описания сборки на специальном DSL на основе Groovy/Kotlin, оказываются удобнее XML;
% по комментарию Ильнара, добавил чуть больше про хмл и дсл + глоссарий.
\end{itemize}

Экзотическая Bazel. Её отличает полная кроссплатформенность и кросстехнологичность, что делает её особенно привлекательной для микросервисных проектах, использующих несколько языков программирования.

\subsection{С чего всё начиналось (Ant, Ivy)}
Первый специализированный инструмент автоматизации задач для языка Java. По сути, это аналог \code{Makefile}, то есть набор скриптов (которые в разговорной речи называются тасками\footnote{от англ task - задача, задание}). В отличие от \code{make}, утилита Ant имеет только одну зависимость — JRE. Ещё одним важным отличием от \code{make} является отказ от использования команд операционной системы. Всё что пишется в Ant пишется на XML, что обеспечивает переносимость сценариев между платформами.

Управление процессом сборки происходит посредством XML-сценария, также называемого Build-файлом. В первую очередь этот файл содержит определение проекта, состоящего из отдельных целей (жарг. таргетов, стр. \pageref{word:makefile-target})). Цели в терминах Ant сравнимы с процедурами в языках программирования и содержат вызовы команд-заданий (жарг. тасков). Каждое задание представляет собой неделимую, атомарную команду, выполняющую некоторое элементарное действие.

Между целями могут быть определены зависимости\footnote{не путать с зависимостями проекта, здесь речь исключительно о задачах и командах Ant} — каждая цель выполняется только после того, как выполнены все цели, от которых она зависит (если они уже были выполнены ранее, повторного выполнения не производится). Типичными примерами целей являются
\begin{itemize}
\item \code{clean} (удаление промежуточных файлов);
\item \code{compile} (компиляция всех классов);
\item \code{deploy} (развёртывание приложения на сервере).
\end{itemize}

Скачивание и установка, Ant для Linux-подобных ОС выполняется командой установки в пакетном менеджере (для Debian-подобных дистрибутивов \code{sudo apt install ant}), а для Windows необходимо перейти на сайт \href{https://ant.apache.org}{https://ant.apache.org}, скачать архив с приложением, распаковать его и прописать соответствующий путь в переменные среды. Проверить установку и версию можно командой
\begin{lstlisting}[language=Bash,style=CCodeStyle]
  ant -version
\end{lstlisting}

% по комментарию Ильнара просто переместил описание перед примером
Теперь можно написать простой сценарий HelloWorld, для этого необходимо создать файл \code{build.xml} (см листинг \hrf{lst:ant-hello}). В нём мы указываем следующие данные:
\begin{enumerate}
\item версию XML, иначе XML не работает;
\item название проекта в теге \code{project} параметр \code{name};
\item таргет по умолчанию в теге \code{project} параметр \code{default};
\item внутри тега \code{project} описания таргетов, в теге \code{target} параметр \code{name} указывает имя цели;
\item внутри тега \code{target} команды, которые необходимо выполнить, например, \code{<echo>}.
\end{enumerate}

\begin{lstlisting}[language=XML,style=ASMStyle,caption={сценарий Ant echo «Hello, World!»},label={lst:ant-hello}]
<?xml version="1.0"?>
<project name="HelloWorld" default="hello">
  <target name="hello">
    <echo>Hello, World!</echo>
  </target>
</project>
\end{lstlisting}


Затем, нужно создать каталог \code{hello} и сохранить туда только что созданный файл с именем \code{build.xml}, который содержит сценарий. Далее надо перейти в каталог и вызвать \code{ant}.
\begin{frm}
\excl Следует обратить внимание, что команды навигации (а также, копирования, создания, редактирования файлов) в терминале могут (и, скорее всего, будут) отличаться. 
\end{frm}
Полный перечень команд, например:

\begin{lstlisting}[language=Bash,style=CCodeStyle]
  mkdir hello
  cd hello
  cp ../build.xml .
  ant
\end{lstlisting}

В результате выполнения получим следующий вывод.
\begin{verbatim}
Buildfile: /home/hello/build.xml

hello:
[echo] Hello, World!
BUILD SUCCESSFULL
\end{verbatim}

Система сборки нашла файл сценария с именем по умолчанию (\code{build.xml}) и выполнила цель указанную по умолчанию (\code{hello}). В стандартной поставке Ant присутствует более 100 заранее созданных заданий, таких как: удаление файлов и директорий (\code{delete}), компиляция java-кода (\code{javac}), вывод сообщений в консоль (\code{echo}) и т.д.

Ниже будет представлен пример build-файла, а в качестве проекта для сборки возьмём из прошлого урока с двумя классами. Файл для него будет выглядеть следующим образом:
В случае, если у вас не сохранился проект с первого урока, то создайте структуру как на рис. \hrf{pic:simple-tree}.
После чего, можно приступить к написанию билд-файла, который будет находиться в корне проекта (на одном уровне с out и src). Выглядеть он будет следующим образом:

\begin{lstlisting}[language=XML,style=CCodeStyle]
<?xml version="1.0"?>
<project name="Sample" default="run">
    <property name="src.dir" value="src/ru/gb/jcore" />
    <property name="build.dir" value="out" />
    <property name="classes.dir" value="${build.dir}/classes" />
    <property name="jar.dir" value="${build.dir}/jar" />
    <property name="main-class" value="ru.gb.jcore.sample.Main" />

    <path id="classpath">
        <fileset dir="${jar.dir}">
            <include name="*.jar" />
        </fileset>
        <fileset dir="${classes.dir}">
            <include name="/*.class" />
        </fileset>
    </path>

    <target name="clean">
        <delete dir="${classes.dir}" />
    </target>

    <target name="compile">
        <mkdir dir="${classes.dir}" />
        <mkdir dir="${jar.dir}" />
        <javac destdir="${classes.dir}" includeAntRuntime="false">
            <src path="${src.dir}/regular"/>
            <src path="${src.dir}/sample"/>
            <classpath refid="classpath" />
        </javac>
    </target>

    <target name="jar" depends="compile">
        <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
            <manifest>
                <attribute name="Main-Class" value="${main-class}" />
                <attribute name="Class-Path" value="${jar.dir}"/>
            </manifest>
        </jar>
    </target>

    <target name="run" depends="jar">
        <java classname="${main-class}">
            <classpath refid="classpath" />
        </java>
    </target>

    <target name="clean-build" depends="clean,jar" />
    <target name="main" depends="clean,run" />
</project>
\end{lstlisting}

Теперь по порядку, что есть что.
Первым делом мы встречаем тег xml, в котором указывается его версия, а затем тег project с указанием имени проекта и команды по умолчанию.
После, в build-файле можно заметить тег property, который по своей натуре является переменной, чтобы сократить те или иные пути до папок/файлоы. Первая переменная с идентификатором (именем) src.dir имеет значение, которое ведёт до пакетов с файлами .java. Затем build.dir, которая обозначает папку, куда будут помещаться файлы после компиляции. classes.dir - путь до папок со сгенерированными файлами .class. jar.dir - директория с бинарными файлами. main-class - это местоположение главного класса приложения, чтобы потом указать .jar-файлу точку входа.
Наш сценарий содержит шесть target (команд):

\begin{enumerate}
\item Clean - удаляет папки с результатами компиляции;
\item Compile - создаёт две директории, одна для компиляции файлов .java, другая для создания .jar файла, а также указывается какой из двух классов куда будет скомпилирован;
\item Jar - она имеет свойство depends, что означает зависимость от указанной команды, а в нашем случае это команда compile, т.е. вначале выполнится compile, после чего команда jar. В подтеге jar присутствует настройка манифеста, там указывается путь до главного класса, в качестве входа в программу, а также местоположение бинарного файла;
\item Run - зависит от команды jar и является командой по умолчанию для проекта;
\item Clean-build - зависит от команд clean и jar. По своей сути, она выполняет просто эти две команды;
\item Main - выполняет команды clean и run.
\end{enumerate}

Также, имеется тег path - в нашем случае он указывает где и какие файлы будут находиться после компиляции.
После чего, можно выполнить команду ant run, а вывод будет следующим:

\begin{verbatim}
Buildfile: D:\Desktop\Java\GB\Sample\build.xml

compile:
    [javac] Compiling 2 source files to D:\Desktop\Java\GB\Sample\out\classes

jar:
      [jar] Building jar: D:\Desktop\Java\GB\Sample\out\jar\Sample.jar

run:
     [java] Hello, world!
     [java] Here is your number: 4.

BUILD SUCCESSFUL
Total time: 0 seconds
\end{verbatim}

\subsection{Репозитории, артефакты, конфигурации}
\subsection{Классический подход (Maven)}
\subsection{Всем давно надоел XML (Gradle)}
\subsection{Собственные прокси, хостинг и закрытая сеть}
\subsection{Немного экзотики (Bazel)}



Ant, Ant+Ivy

На данный момент Ant используют в связке с Ivy, которая является гибким, настраиваемым инструментом для управления (записи, отслеживания, разрешения и отчетности) зависимостями Java проекта.

Первым для автоматизации этих задач появился Ant. Это аналог make-файла, а по сути набор скриптов (которые называются tasks). В отличие от make, утилита Ant полностью независима от платформы, требуется лишь наличие на применяемой системе установленной рабочей среды Java — JRE. Отказ от использования команд операционной системы и формат XML обеспечивают переносимость сценариев.
Управление процессом сборки происходит посредством XML-сценария, также называемого Build-файлом. В первую очередь этот файл содержит определение проекта, состоящего из отдельных целей (Targets). Цели сравнимы с процедурами в языках программирования и содержат вызовы команд-заданий (Tasks). Каждое задание представляет собой неделимую, атомарную команду, выполняющую некоторое элементарное действие.
Между целями могут быть определены зависимости — каждая цель выполняется только после того, как выполнены все цели, от которых она зависит (если они уже были выполнены ранее, повторного выполнения не производится). Типичными примерами целей являются clean (удаление промежуточных файлов), compile (компиляция всех классов), deploy (развёртывание приложения на сервере).
Скачивание и установка, в случае каких-то неисправностей, ant для Linux выполняется командой вроде sudo apt-get install ant, а для Windows можно перейти на сайте ant.apache.org и скачать архив.
Проверить версию можно командой ant -version
Теперь можно написать простой сценарий HelloWorld

<?xml version="1.0"?>
<project name="HelloWorld" default="hello">
    <target name="hello">
        <echo>Hello, World!</echo>
    </target>
</project>


Затем, нужно создать подкаталог hello и сохранить туда файл с именем build.xml, который содержит сценарий. Далее надо перейти в каталог и вызвать ant. Полный перечень команд:

\begin{lstlisting}[language=C,style=CCodeStyle]
  $ mkdir hello
  $ cd hello
  $ ant
  Buildfile: /home/hello/build.xml

hello:
[echo] Hello, World!
BUILD SUCCESSFULL
\end{lstlisting}


Теперь нужно бы пояснить, что произошло: система сборки нашла файл сценария с указанным по умолчанию именем build и выполнила цель с именем hello, который указан в теге проекта, с помощью атрибута default со значением hello, а также имя проекта, с помощью атрибута name.
В стандартной версии ant присутствует более 100 заданий, такие как: удаление файлов и директорий (delete), компиляция java-кода (javac), вывод сообщений в консоль (echo) и т.д. Вот пример реализации удаления временных файлов, используя задание delete:

\begin{lstlisting}[language=C,style=CCodeStyle]
  <!-- Очистка -->
  <target name="clean" description="Removes all temporary files">
  <!-- Удаление файлов -->
  <delete dir="${build.classes}"/>
  </target>
\end{lstlisting}

На данный момент Ant используют в связке с Ivy, которая является гибким, настраиваемым инструментом для управления (записи, отслеживания, разрешения и отчетности) зависимостями Java проекта.
Некоторые достоинства Ivy:

гибкость и конфигурируемость – Ivy по существу не зависит от процесса и не привязан к какой-либо методологии или структуре;
тесная интеграция с Apache Ant – Ivy доступна как автономный инструмент, однако он особенно хорошо работает с Apache Ant, предоставляя ряд мощных задач от разрешения до создания отчетов и публикации зависимостей;
транзитивность – возможность использовать зависимости других зависимостей.

Немного о функциях Ivy:

управление проектными зависимостями;
отчеты о зависимостях. Ivy производит два основных типа отчетов: отчеты HTML и графические отчеты;
Ivy наиболее часто используется для разрешения зависимостей и копирует их в директории проекта. После копирования зависимостей, сборка больше не зависит от Apache Ivy;
расширяемость. Если настроек по умолчанию недостаточно, вы можете расширить конфигурацию для решения вашей проблемы. Например, вы можете подключить свой собственный репозиторий, свой собственный менеджер конфликтов;
XML-управляемая декларация зависимостей проекта и хранилищ JAR;
настраиваемые определения состояний проекта, которые позволяют определить несколько наборов зависимостей.

Apache Ivy обязана быть сконфигурирована, чтобы выполнять поставленные задачи. Конфигурация задается специальным файлом, в котором содержится информация об организации, модуле, ревизии, имени артефакта и его расширении.
Некоторые модули могут использоваться по разному и эти различные пути использования могут требовать своих, конкретных артефактов для работы программы. Кроме того, модуль может требовать одни зависимости во время компиляции и сборки, и другие во время выполнения.
Конфигурация модуля определяется в Ivy файле в формате .xml, он будет использоваться, чтобы обнаружить все зависимости для дальнейшей загрузки артефактов. Понятие «загрузка» артефакта имеет различные варианты выполнения, в зависимости от расположения артефакта: артефакт может находиться на веб-сайте или в локальной файловой системе вашего компьютера. В целом, загрузкой считается передача файла из хранилища в кеш Ivy.
Пример конфигурации зависимостей с библиотекой Lombok:

<ivy-module version="2.0">
    <info organisation="org.apache" module="hello-ivy"/>
    <dependencies>
         <dependency org="org.projectlombok" name="lombok" rev="1.18.24" conf="build->master"/>
    </dependencies>
</ivy-module>


Его структура довольно проста, первый корневой элемент <ivy-module version="2.0"> указывает на версию Ivy, с которой данный файл совместим. Следующий тег <info organisation="org.apache" module="hello-ivy"/> содержит информацию о программном модуле, для которого указаны зависимости, здесь определяются название организации разработчика и название модуля, хотя можно написать в данный тег что угодно. Наконец, сегмент <dependencies> позволяет определить зависимости. В данной примере модулю необходимо одна сторонняя библиотека: lombok.
Однако, у такой системы, как Ant есть и свои минусы: Ant-файлы могут разрастаться до нескольких десятков мегабайт по мере увеличения проекта. На маленьких проектах выглядит всё достаточно неплохо, но на больших они длинные и неструктурированные, а потому сложны для понимания.
Что привело к появлению новой системы - Maven.

\newpage
\sloppy
\printnomenclature[27mm]

\end{document}