Статьи

Создание кода умнее с Maven

Как вы, возможно, читали в моей последней записи , я недавно начал новый концерт с Overstock.com . В мой первый день я быстро погрузился в процесс разработки, присоединившись к команде разработчиков. Команда преобразования отвечает за разработку пользовательского интерфейса оформления заказа и обработку платежей от клиентов. Я быстро обнаружил, что Overstock — это, в основном, магазин Linux + Eclipse, и сделал все возможное, чтобы установить и настроить мой любимый Mac + IntelliJ + JRebel . Благодаря моему новому Team Lead, я смог все настроить и запустить в первый день, а также проверить свой первый вклад: создание mvn jetty: запуск работы, поэтому мне не пришлось использовать свою среду IDE для развертывания в Tomcat.

При настройке своего окружения я не мог не заметить бегущую пристань: каждый раз бегал довольно долго. В частности, процесс сборки занял 45 секунд, чтобы запустить плагин Jetty, затем еще 23 секунды, чтобы запустить его после этого. Первой подозрительной вещью, которую я заметил, было то, что шаблоны пользовательского интерфейса перегенерировались и компилировались при каждом выполнении. Структура шаблонов пользовательского интерфейса в Overstock — Jamon и описывается следующим образом:

Jamon — это механизм текстовых шаблонов для Java, полезный для генерации динамического HTML, XML или любого текстового контента. В типичной архитектуре Model-View-Controller Jamon явно нацелен на уровень View (или представления).

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

Для создания файлов .java из шаблонов .jamon мы используем плагин Jamon для Maven. Помня, что плагин компилятора Maven имеет функцию инкрементной компиляции, я обратился к его исходному коду, чтобы узнать, как реализовать это в плагине Jamon. Я был приятно удивлен, обнаружив StaleSourceScanner . Этот класс позволяет легко сравнивать два файла, чтобы увидеть, нужно ли пересмотреть исходный код для генерации или компиляции.

Я заметил, что плагин Jamon имеет следующий код, чтобы выяснить, какие файлы он должен генерировать в файлы .java:

private List<File> accumulateSources(File p_templateSourceDir)
{
final List<File> result = new ArrayList<File>();
if (p_templateSourceDir == null)
{
return result;
}
for (File f : p_templateSourceDir.listFiles())
{
if (f.isDirectory())
{
result.addAll(accumulateSources(f));
}
else if (f.getName().toLowerCase(Locale.US).endsWith(".jamon"))
{
String filePath = f.getPath();
// FIXME !?
String basePath = templateSourceDir().getAbsoluteFile().toString();
result.add(new File(filePath.substring(basePath.length() + 1)));
}
}
return result;
}

Я изменил его, чтобы он был умнее и генерировал только измененные шаблоны со следующим кодом:

private List<File> accumulateSources(File p_templateSourceDir) throws MojoExecutionException
{
final List<File> result = new ArrayList<File>();
if (p_templateSourceDir == null)
{
return result;
}
SourceInclusionScanner scanner = getSourceInclusionScanner( staleMillis );
SourceMapping mapping = new SuffixMapping( ".jamon", ".java");

scanner.addSourceMapping( mapping );

final Set<File> staleFiles = new LinkedHashSet<File>();

for (File f : p_templateSourceDir.listFiles())
{
if (!f.isDirectory())
{
continue;
}

try
{
staleFiles.addAll( scanner.getIncludedSources(f.getParentFile(), templateOutputDir()));
}
catch ( InclusionScanException e )
{
throw new MojoExecutionException(
"Error scanning source root: \'" + p_templateSourceDir.getPath()
+ "\' " + "for stale files to recompile.", e );
}
}

// Trim root path from file paths
for (File file : staleFiles) {
String filePath = file.getPath();
String basePath = templateSourceDir().getAbsoluteFile().toString();
result.add(new File(filePath.substring(basePath.length() + 1)));
}
}

Этот метод ссылается на метод getSourceInclusionScanner (), который реализован следующим образом:

protected SourceInclusionScanner getSourceInclusionScanner( int staleMillis )
{
SourceInclusionScanner scanner;

if ( includes.isEmpty() && excludes.isEmpty() )
{
scanner = new StaleSourceScanner( staleMillis );
}
else
{
if ( includes.isEmpty() )
{
includes.add( "**/*.jamon" );
}
scanner = new StaleSourceScanner( staleMillis, includes, excludes );
}

return scanner;
}

Если вы используете Jamon и его плагин Maven, вы можете посмотреть мой патч на SourceForge. Если вы хотите включить эту функцию в свой проект, я предлагаю вам взглянуть на код, который я изучил в классе AbstractCompilerMojo Maven Compiler .

После внесения этого изменения мне удалось сократить время выполнения сборки более чем на 50%. Теперь требуется 20 секунд, чтобы поразить плагин Jetty и 42 секунды, чтобы закончить запуск. Конечно, в идеальном мире я бы хотел уменьшить это до 20 секунд или меньше. Как ни странно, самый простой способ сделать это кажется простым: использовать Linux .

На предоставленном мне рабочем столе Linux требуется 12 секунд, чтобы запустить плагин Jetty, и 23 секунды, чтобы закончить запуск. Я хотел бы думать, что это аппаратная вещь, но она работает на 20% быстрее на OS X при использовании 8 ГБ ОЗУ + SSD (по сравнению с 4 ГБ + 5400 дисков). Поскольку Overstock предоставил мне MacBook Pro 4 ГБ , я подумываю установить на него Ubuntu, просто чтобы увидеть, в чем разница.

Солнце над снежной птицейВ связанных новостях Overstock.com надеется нанять целую группу разработчиков Java в этом году. На фотографии нового офиса Прово выглядят довольно мило. Конечно, вы также можете работать в HQ, который находится всего в 25 минутах езды от некоторых из лучших лыж в мире. Лично я думаю, что порошок Колорадо лучше, но я не могу спорить с удобством отсутствия движения. В дополнение к постоянным выступлениям они стали нанимать больше удаленных подрядчиков, таких как я, поэтому у них есть что-то для всех. Так что если вы любите Java, хотите поработать перед работой и не мудак — вам следует связаться со мной, и я постараюсь вас перехватить.

 

От http://raibledesigns.com/rd/entry/making_code_generation_smarter_with