pátek 1. října 2010

Hygiena kolem projektových souborů Mavenu

Když jsem si tu v předchozím příspěvku postěžoval na to, jak je složité znovu a znovu rozjíždět java projekty z pohledu setupu, měl jsem trochu pocit, že to jsou jenom brekot nad rozlitým mlékem. Abych se vykoupil, rozhodl jsem se dát k dobru praxí ověřená pravidla, týkající se hygieny kolem projektových souborů Mavenu. Samozřejmě pokud mě chcete doplnit vlastními tipy, rád si je poslechnu v komentářích.

Závislosti

Scope

První věc, o které přemýšlejte u každé závislosti je její scope. Hodně problémů projevujících se tím, že se divíte, kde se vám sakra bere tolik závislostí ve WARu je způsobeno tím, že u závislostí není správně scope. Sekundárním efektem je nabobtnalá konfigurace WAR případně Assembly pluginu, která maže tyto závislosti z výsledné binární distribuce.

Pro závislosti, na kterých máte runtime závislost a nepotřebujete je pro kompilaci použijte scope runtime. Pro závislosti potřebné pouze k testům použijte scope test a pro závislosti, které vám poskytuje běhové prostředí, např. Servlet API, použijte scope provided. Více informací o Dependency scope.

Centrální místo pro závislostí

Všechny závislosti a to včetně vašich vlastních definujte v dependencyManagement (neřiká nic o jejích použití) sekci vašeho centrálního POMu, ze kterého dědí všechny ostatní POMy. Pokud žádný takový nemáte, zaveďte si jej. Závislosti uvádějte vždy včetně defaultního scope. Tímto použitím získáte několik výhod. Především všechny závislosti máte na jednom místě.

V dceřiných POMech potom používáte závislosti identifikované jenom groupId a artifactId. Změna verze knihovny je potom zásah v jednom souboru. Další výhodou je právě určení verze knihovny. Díky tomuto použití určujete verzi pro všechny moduly a to včetně tranzitivních závislostí. Nestane se vám, že by se vám dostala jiná verze. Více informací o Dependency Managementu

<dependencyManagement>
 <dependencies>   
  <dependency>
   <groupId>cz.sweb.pichlik</groupId>
   <artifactId>example</artifactId>
   <version>0.1-SNAPSHOT</version>
  </dependency>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.8.1</version>
   <scope>test</scope>
  </dependency>
<dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
  </dependency>

  <dependency>
   <groupId>cz.sweb.pichlik</groupId>
   <artifactId>example</artifactId>
  </dependency>

Sdílené závislosti

Sdílené závislosti jsou ty, které nadefinujete v sekci dependencies rodičovského POMu. Doporučuji vám se jim obloukem vyhnout kromě třech výjimek - logování, testy a validaci vstupních argumentů. To je minimální průnik všech modulů.

Vyloučení závislostí

Pokud chcete nějakou závislost vyloučit, protože není potřeba, typicky tu zatažená nějakou špatně definovanou 3rd party závislostí, je nejlepším způsobem definovat tuto závislost v dependencyManagement se scopem provided. Samozřejmě tento trik aplikujte pouze za předpokladu, že nikdo tu závislost opravdu nepotřebuje.

 
<dependency>
 <groupId>commons-logging</groupId>
 <artifactId>commons-logging</artifactId>
 <version>1.1.1</version>
 <scope>provided</scope> 
</dependency>

Analýza závislostí

Pokud se chcete podívat na zoubek závislostem, například chcete zkontrolovat jaké závislosti má váš modul, použijte příkaz mvn dependency:tree. Tento příkaz zobrazí původ všech závislostí v textové podobě.

Pokud chcete naopak zjistit, jestli váš modul nějaké závislosti používá, ale nemá je deklarované (vedlejší efekt tranzitivních závislostí), případně naopak, nepoužívá, ale má nadeklarované, pak použijte příkaz mvn dependency:analyze -DignoreNonCompile. Tento příkaz analyzuje přímo byte kód, proto je potřeba, aby byla závislost v lokální Maven cache (prostě jenom mvn install -DskipTests).

Běžné věci

  • Poukud používáte name element v POMu, pak je dobré, aby měl stejnou hodnotu jako artifactId. Důvod je veskrze praktický, Maven vypisuje po každém příkazu summary provedení za jednotlivé moduly. Pokud příkaz pustíte v multimodule projektu a name necháte na lidové tvořivosti, bude se vám těžko dohledávat, o který modul vlastně šlo.
  • S tím souvisí dobrý návyk a to udržovat artifactId unikátní.
  • Nedávejte souboru specifické pro IDE do verzovacího systému. Většina IDE co stojí v Jave za zmínku totiž dokáže číst přímo POMy. Specifické soubory pro IDE jsou většinou nějak spjaté s konkrétním fyzickým umístěním a použitou verzí IDE a proto nepřenosné.
  • Pokud vznikají vazby mezi moduly, které nedávají smysl, což se většinou ještě projevuje rovněž tím, že někde vybublají nechtěné závislosti, je to tím, že vývojáři jsou líní nebo se bojí dělat specializované moduly. Typickým příkladem je modul, kterému pracovně říkám test-support. To je modul, do kterého dávám podporu pro testy jako například mock objekty, specializované předky apod. Tento modul má potom scope test, to znamená, že jeho závislosti nikam neprobublají.

středa 29. září 2010

Kdo s čím zachází, s tím také schází

Lukáš Křečan nedávno napsal o tom co ho štve na Jave. Já bych ho trošku podpořil, protože občas mám pocit, jako bych roztlačoval parní lokomotivu. V poslední době jsem rozcházel několik Java projektů pro pár vývojářů, kteří chtěli nastartovat webový vývoj a musel jsem se tedy hluboce stydět. Přestože mi Maven říká pane, tak rozběhnout plnohodnotný projekt včetně setupu IDE mi zabralo skoro půl dne.

Nevím proč, ale od jisté doby nabízí Maven snad stopadesát archetypu (kostra aplikace), bohužel skoro všechny jsou víceméně nepoužitelné. Stejně vždycky skončím u ručního tunnningu. Počínaje nastavením kompilátoru na Javu 1.6, přes upgrade jUNit na 4.8.1 a konče nastavením SLF4J závislostí pro logování a vyloučením Commons logging.

Další pohromou jsou vývojové nástroje. Rozběhnout Maven v Eclipse včetně WTP je magie a to nepodotýkám z toho důvodu, abych vám nabídl svoje služby. Navíc v týmu se najdou vždycky nějaké černé ovce, které používají NetBeans a nebo IntelliJ IDEA.

Když tuhle lokomotivu konečně roztlačíte, máte z toho nevýslovnou radost, ale zároveň jistou pachuť na jazyku. Čím dál tím víc jsem přesvědčený, že tahle fragmentace Javy a jejího ekosystému je ukrutná dvousečná zbraň. V Jave neexistuje ani na ty nejjednodušší otázky jediná odpověď. Chcete příklad, tak si položte otázky Jaké IDE, co na ukládání, jaký webový framework, jaký server, jaký buildovací nástroj. Na každou z nich může napsat v odpověď celý elaborát.

Na jednu stranu máte v rukách úžasnou volnost, ale na druhou nesmírně heterogenní prostředí, na kterém si můžete pěkně rozbít hubu. Jinými slovy nejsilnější zbraň Javy je zároveň její nejslabší stránkou.