Статьи

Maven: отличная идея, плохая реализация (часть 2)

В моем предыдущем посте я объяснил, почему Maven — хорошая концепция для сборок проектов Java. В этом посте я расскажу о ключевой области, где он падает, о чрезмерной сложности его конфигурации.

Вкратце, у нас есть множество домашних сборочных систем, созданных разными способами с использованием Ant, и все они делают одно и то же. Поскольку подавляющее большинство проектов Java имеют очень похожие требования к сборке, готовая система сборки должна быть в состоянии выполнить эту работу.

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

Maven выполняет это, если ваши потребности в сборке смехотворно просты. Поместите ваш исходный код в папки для кода приложения и тестового кода, назовите ваши тесты правильно и поместите в очень маленький файл pom.xml. Запустите «mvn install», и ваш код скомпилирован, протестирован и готов к развертыванию.

Однако все быстро становится ужасно, как только вам нужно сделать даже небольшую настройку для базовой сборки.

Например, давайте посмотрим, что связано с изменением версии Java, для которой вы хотите создать свой проект, для обеспечения языковой совместимости и / или совместимости со средой выполнения, в которой будет использоваться ваш проект. Maven 3.0.x по умолчанию использует Java 1.5, даже если у вас установлена ​​Java 1.6, что вполне разумно.

Таким образом, у нас есть два параметра, которые нужно изменить, языковая версия для исходного кода и целевая версия для сгенерированных классов. Вот что мы должны добавить к нашему простому pom.xml для достижения этой цели:

<project>
  [...]
  <build>
    [...]
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.2</version>
        <configuration>
          <source>1.4</source>
          <target>1.4</target>
        </configuration>
      </plugin>
    </plugins>
    [...]
  </build>
  [...]
</project>

Итак, первое, что вас поражает, святые спагетти, это много лесов по двум параметрам. Кто-то пробирается через pom-файл, пытаясь понять нашу сборку, чтобы изменить или исправить ее, будет трудно разобраться с содержанием этого фрагмента, и не ясно, что это только для этих двух параметров.

Гораздо хуже, дополнительные леса не безвредны. До того, как мы это сделали, компиляция выполнялась плагином maven-compiler-plugin с использованием последней доступной версии для той версии Maven, которую мы используем. Теперь это из коробки по умолчанию было обнаружено в файле POM. Наш проект привязан к знаниям и управлению плагином и его версией. Если мы не укажем версию, Maven 3.x напечатает страшное предупреждение, предполагая, что в будущем это больше не будет позволять нашему небрежному игнорированию управления гайками и болтами его внутренних органов, поэтому ожидайте, что наша сборка будет ужасно сломана.

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

Теперь предположим, что вы хотите запускать интеграционные тесты в своем коде, которые запускают более тяжелые весовые тесты в отдельной фазе после модульного тестирования. Модель тестирования, которой мы следуем, состоит в том, чтобы иметь легкие модульные тесты, которые быстро выполняются для быстрой обратной связи по основным ошибкам, а затем более тяжелые тесты, которые, вероятно, нуждаются в контейнере, таком как Jetty, и, возможно, в базе данных, для более глубокого тестирования. Это часто упоминается как интеграционное тестирование, то есть вы тестируете компоненты единого приложения, объединенного вместе.

(Однако наименование приводит к путанице, поскольку интеграционное тестирование может также относиться к тестированию интеграции с внешними приложениями, веб-службами и т. Д.)

Таким образом, Maven поддерживает запуск отдельного набора тестов на этапе интеграционных тестов, который запускается после модульных тестов с использованием отказоустойчивого плагина. Как мы используем это? Во-первых, мы пишем классы тестовых примеров JUnit и называем их ITMyClass , а начало «IT» говорит Maven запустить их на этом этапе.

Так Maven просто находит и запускает эти классы, если они существуют? Конечно, нет, вы должны добавить некоторую конфигурацию в ваш pom.xml, чтобы он знал. Справедливо, Maven не должен тратить наше драгоценное время на сборку, ища во всех наших тестовых классах те, которые названы «IT», если мы не используем интеграционные тесты.

Таким образом, это должен быть довольно простой параметр конфигурации, чтобы сообщить Maven, что мы используем фазу интеграционного тестирования. Правильно?

Правильно?

<project>
  [...]
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-failsafe-plugin</artifactId>
        <version>2.7.2</version>
        <executions>
          <execution>
            <id>integration-test</id>
            <goals>
              <goal>integration-test</goal>
            </goals>
          </execution>
          <execution>
            <id>verify</id>
            <goals>
              <goal>verify</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  [...]
</project>

(Из документации по отказоустойчивому плагину .)

Так что нет.

Священные леса! Все, что мы действительно сказали Maven со всей этой конфигурацией, — это включил «отказоустойчивый плагин» и подключил его к жизненному циклу сборки для запуска на этапе тестирования интеграции. Но опять же, мы заблокировали информацию о плагине, включая номер версии, в файле pom нашего проекта.

В этом случае нам также пришлось явно (и многословно) указать этап жизненного цикла. Так что это плагин, цель которого в жизни состоит в том, чтобы использовать его на этапе интеграции жизненного цикла сборки Maven, но мы должны взять его за руку и точно сказать, как и где подключиться к жизненному циклу, даже если мы » следуют его сценарию использования по умолчанию.

Это не конфигурация над соглашением! Это даже не Мексика!

Ой, подождите, это не запускает наши интеграционные тесты с контейнером сервлета. Давайте подключим Jetty. На самом деле это довольно просто, просто скопируйте, вставьте и настройте пример в этой документации из Codehaus (второй фрагмент XML на этой странице).

В конфигурации даже немного больше мяса, что вполне справедливо, поскольку есть несколько вещей, которые вы можете настроить при запуске контейнера сервлета. Но вы по-прежнему загружаете больше конфигурации, большая часть которой вызывает подробности жизненного цикла выполнения Maven, которые, когда дело доходит до него, используются по умолчанию для 90% людей, использующих это.

Таким образом, вы можете видеть, как файл pom.xml вашего проекта Maven быстро заполняется ненужной ерундой, что увеличивает барьер для понимания и изменения сборки. Как только вы выработаете довольно хорошее представление о внутренних структурах и моделях Maven, вы научитесь определять, какие части pom.xml являются строительными лесами, а какие действительно интересуют вас.

Но большинство разработчиков в команде не будут тратить время на освоение Maven, и в этом нет необходимости. Они имеют ценность для бизнеса. Это стена, на которой я работаю, поддерживая высокопроизводительную команду разработчиков, потому что существует небольшая терпимость к тому, чтобы тратить время на другие вещи, помимо создания функций приложений, которые нужны клиентам.

Так лучше ли муравей, чем этот? Как я уже говорил в моем предыдущем посте , сборка Ant обычно усложняется. Но проекты Maven не только страдают от сложности, они также страдают от негибкости Maven. Обычно вы рассматривали бы обмен на некоторую гибкость для простоты, если конечным результатом была более высокая производительность.

Поэтому мой следующий пост в Maven будет посвящен конкретной области, где негибкость Maven вредит производительности моей команды. В настоящее время я не имею в виду больше этих трех постов для этой серии, но тогда моя команда все еще только на итерации 0.

Часть 1 и Часть 3 здесь.

Отзывы об этих сообщениях: я более чем рад сообщить, что я не прав, особенно если есть более простые, простые и лучшие способы реализации описанных мной примеров. Лучший способ оставить отзыв, прокомментировать ниже и упомянуть меня (@kief) в Твиттере со ссылкой на ваш ответ.

Источник: http://kief.com/maven-configuration-complexity.html