Odlišujete v aplikaci vývojové, testovací a produkční prostředí?

Tento článek píšu se záměrem zjistit, zda jsme k těmto závěrům dospěli sami, nebo je to evoluční záležitost, ke které časem dospěje každý tvůrce produktů sloužících k dalšímu vývoji. Ve Forrestu k realizaci webů a webových aplikací používáme interní CMS systém, který je nadstavbou nad vybranými Javovskými knihovnami a frameworky. Namátkou například Spring Framework, Freemarker, Groovy, Spring Security, Stripes, DWR, iBatis a řada dalších. Tím, že jsme CMS systém (ona už je to vlastně tak trochu programová platforma) postavili nad existujícími knihovnami jsme dosáhli toho, že můžeme využívat většiny jejich širokých možností a máme zdarma zajištěn i další vývoj, který nás v podstatě bezpracně posouvá zase dál.

Tím, že se systém sestává z takového množství dalších knihoven a frameworků, jsme začali narážet na problémy se složitostí konfigurace. Teď nemluvím o nastavení pro cílového zákazníka (zabezpečení url, nastavení rolí, definice aplikačních triggrů a maker, proměnné prostředí jako adresa SMTP serveru atd.), ale o vývojové záležitosti jako je konfigurace cache (Freemarker šablon, lokalizované zprávy, Groovy třídy), podrobnost chybového výstupu (pro vývoj plné stacktracy, na produkci nic neříkající HTTP 500), dostupnost debugovacích nástrojů (máme vlastní inspektor jako Firefox plugin) apod.

Řada z použitých knihoven a scénářů, které jsme používali, měla sadu možností pro úpravu svého chování, které bylo velmi užitečné využít. V celkovém součtu se jednalo o tucet (a stále přibývají ;-) ) nastavení, které bylo nutné nastavit a u jejichž nastavování musel člověk přemýšlet. Také bylo nutné tato nastavení rozlišovat podle režimu v jakém aplikace běží a nepoužívat konstanty ale proměnné.

Vcelku brzy jsme přišli na to, že, přestože je možné všechny nastavení relativně jednoduše editovat, většinou se nastavilo pouze něco a velice často konstantně tak, že se nám na produkci dostávaly i nastavení, které tam neměly co dělat (třeba nulová cache FTL šablon omylem ponechaná z vývoje).

U nás rozeznáváme tři režimy běhu (a myslím, že se jedná o vcelku běžný standard):

  • development (vývoj) – v tomto prostředí potřebujeme co největší možnosti manipulace se systémem, rychlou odezvu vůči změnám, maximální přístup k debugovacím a chybovým informacím
  • staging (test) – v tomto prostředí již aplikaci vidí zákazník, je tedy vhodné standardní programátorské záležitosti skrýt a neděsit ho plnou obrazovkou stacktraců – na druhou stranu potřebujeme stále výrazně upozornit pokud se někde vyskytne chyba, aby bylo možné ji odstranit před přechodem do produkce, chceme si zachovat nějakou rozumnou míru odezvy na změny v systému a přístup k debugovacím nástrojům
  • production (ostrý běh) – tady chceme maximální výkon, změny v systému za běhu budou minimální (stále si chceme nechat otevřená dvířka, ale upřednostňujeme explicitní refresh konfigurace), minimalizujeme debugovací možnosti (ty mají dopad na výkon), optimalizujeme případný chybový výstup ke koncovému uživateli (stacktracy opravdu nejsou nejlepší vizitka, že Filemone?)

Po nějaké době jsme se dohodli, že toto nepsané rozdělení instalací zformalizujeme a umožníme je definovat na jednom místě v konfiguraci CMS a přizpůsobíme všechny moduly, aby svá běhová nastavení odvodila od aktuálního běhového prostředí. Konfigurace je velmi jednoduchá – např.:

Tímto jednotně říkáme, že všechna prostředí s operačním systémem Windows a stroj se jménem “novoj.fg.cz” mají být považována za vývojová, stroj “nasserver.fg.cz” má být považován za testovací prostředí. Všechny ostatní prostředí, které neodpovídají těmto pravidlům jsou považovány za produkční.

Všechny moduly i standardní web aplikace si potom může ze systému vytáhnout identifikaci aktuálního běhového prostředí (voláním metody isProduction(), isStaging(), isDevelopment() na jádrové třídě) a načíst defaultní nastavení pro tento režim běhu. Pokud by kdokoliv jevil zájem tyto výchozí nastavení přepsat, může – nicméně jak praxe ukázala, nikdo to nedělá, protože toto rozlišení defaultních nastavení pro naše potřeby plně postačuje. Integrační vrstva nad knihovnami jako je Freemarker, Groovy atd. také obsahuje trojí sadu defaultních nastavení optimalizovaných pro jednotlivé režimy běhu.

Takto jednoduše jsme se zbavili poměrně velké bolesti, kterou jsme nějakou dobu trpěli. Jedním nastavením vcelku rozumně nyní ovládáme chování celého systému – navíc je to něco, s čím dokáže pracovat kdokoliv i bez hlubší znalosti modulů a knihoven v dané instalaci použitých.

Myšlenka, ke které jsme dospěli, mi s odstupem času nepřijde ani moc geniální jako spíš evoluční. Pozitivní dopady jsou ovšem pro výslednou použitelnost citelně znatelné.

Skončím otázkou nakonec – pokud používáte pro svou práci nějakou infrastrukturní nadstavbu, dospěli jste k podobnému závěru? Jaká je Vaše motivace, řešení a zkušenosti?

Podělte se s ostatními:

  • Digg
  • del.icio.us
  • Technorati
  • Diigo
  • DZone
  • FriendFeed
  • Google Bookmarks
  • LinkedIn
  • Reddit
  • RSS
  • StumbleUpon
  • Twitter

Související články:

  1. Co tvoří produktivní prostředí?
Ohodnoťte článek:
Takovéhle články už radši ne!Nic nového pod sluncem.Průměr - obsahuje zajímavé střípky informací.Hodnotný článek - lecos nového jsem se dozvěděl.Skvělý článek - informace se mi dost hodí. (4 hlasů, průměrně: 4.25 z 5)
Loading ... Loading ...

18 Responses to “Odlišujete v aplikaci vývojové, testovací a produkční prostředí?”

  1. Osobně to vnímám jako dnešní standard. Moderní frameworky to běžně oddělují.

  2. Otec Fura says:

    Můžeš být trošku konkrétnější?

  3. filemon says:

    Jo, ja bych rekl, ze to takhle pouzivaji skoro vsichni nasi zakaznici – korporatnici. DEV pro hratky a ukazky spot fixu, TST s omezenym pristupem pro nas coby developery pro akceptacni testy a PROD, produkce. Z tech frameworku, ktere to takto deli primo, uvedu napr. Rails. (a timpadem i nejspis Grails ;)

  4. Otec Fura says:

    Takže spíš evoluce než revoluce. Filemone díky za info, tohle jsem o Rails nevěděl.

  5. uf says:

    Vsechno genialni je pri zpetnem pohledu jednoduchy princip. Jen nekdo musi udelat vic kroku vyvoje a pak ten zasadni.

    Urcite si myslite (i se ctenari), ze jste to mohli zaridit drive, kdyz mate zkusenosti a vite, jak oddelit jednu funkcnost na jedno misto. Stejne jako po hledani chyby si clovek mysli, ze ji mohl predejit peclivejsi pripravou nebo hlubsim promyslenim. Stejne k nim dochazi. To je holt vyvoj.

  6. Já konkrétně měl v hlavě taky Railsy, ale tyto dobré metody přejímají dneska skoro všichni. Nevím jak v Javovských frameworcích, ale Grails podle mně ano.

  7. Otec Fura says:

    Naposledy jsem toto viděl zmíněné v nejnovější verzi iBatis frameworku. Ale obecně bych řekl, že jsem na to dosud v Javovských frameworcích moc nenarazil. Což bych mj. důvod, že jsme tuto strategii adoptovali teprve poměrně nedávno (cca 1/2 roku zpět).

  8. pepa says:

    Ano, pouzivame DEV->TST->PROD model. Konfiguraci udrzujeme v konf. property souborech, pro kazde prostredi zvlast. Zajimavy napad, vybudovat jeste neco nad tim…

  9. jčp says:

    Zatím jsme evolovali do jiného stavu:
    Běžný překlad probíhá do dev prostředí.
    ant prod a ant test ve vygenerovaném waru přeplácnou specifické konfigurační soubory, šablony, lokalizaci…
    Jiný slovy: konfigurace se mění s účelem buildu, nikoliv za běhu podle prostředí.
    Zdrojové soubory zůstávají stejné. Možná máme jen příliš jednoduché aplikace.

    Ale psát v javě konstrukce typu if (isDevelop()) {…} else {…}? Nevím, to se mi nezdá rozumné.

  10. Otec Fura says:

    No spíš se jedná od dva druhy aplikací – my děláme produkt, který má jeden artefakt, který je výsledkem buildu. Tento artefakt se nasazuje na X instalací a tam se teprve customizuje pomocí konfiguračních souborů. Těch konfigurací už tak je poměrně hodně a proto se nám vyplatilo některá “technická” (nikoliv zákaznická) nastavení typizovat podle zmíněných třech běhových prostředí a vyjmout je ven (s možností přepisu). Moduly, které jsou součástí buildu si mohou potom pro tyto 3 typizovaná prostředí použít své hardcodované defaults.

    Takže řekl bych, že spíš oba řešíme trošku něco jiného.

  11. Tomáš says:

    A neexistuje nějaká knihovna, která by výběr toho správného konfiguračního souboru řešila? Předpokládám, že to co parsuje ten XML soubor z a podle toho rozhoduje o jaký server jde jste si psali sami?

  12. Otec Fura says:

    Jo to parsování XML máme interní – používáme na to JDOM. Pro otestování těch řídících proměnných stačí analýza Java System properties, popřípadě hostname – což je jeden řádek:

    InetAddress.getLocalHost().getHostAddress()

    Nicméně v tom ani není gró toho problému. To přizpůsobení chování aplikace / modulů už s XML nemá v podstatě nic společného. XML je jen prostředek jak to rozlišení prostředí definovat.

  13. Tomáš says:

    Ano, je mi to jasné. Jen stojím před podobným problémem, jen nemám vlastní CMS vlastní moduly, ale používám Wicket, Hibernate, logback a pár dalších knihoven a hledám nějaké už hotové řešení, které by pomohlo s konfigurací těchto knihoven dle prostředí.

  14. Otec Fura says:

    Aha, tak v tomto případě nepomůžu – my to máme prostě napsané na vlastní míru. Kdo ví, jestli někde něco takového existuje, podle charakteru problému bych si ale spíš tipnul že ne, protože je to skoro spíš úkol na nějaký integrační framework než nějakou utility knihovnu.

  15. Tomáš says:

    Jediné, co jsem našel je tohle: http://jfig.sourceforge.net/

  16. Almad says:

    Tož my to nemáme takhle explicitně, prostě máme tři balíky s potřebnými konfiguračními soubory a k tomu jakýsi “common”, který je společný všem třem.

    Konfiguraci ve stylu isDevel()/isDebug() z duše nenávídím, blbě se to testuje, způsobuje mrtvý kod a mnohdy se to na produkci chová jinak, než by člověk čekal.

    Nicméně mně je java blízká asi tak jako XML pro konfiguraci, takže nevšímat :)

  17. Jarda says:

    “běží a používat konstanty ale proměnné.”
    nemá tam být “nepoužívat”?

  18. Otec Fura says:

    ad) Jarda, je to tak … díky za upozornění, opraveno

  19. Jety says:

    Ahoj Honzo, díky za článek,

    my ve firmě používáme nadstavbu nad Springem, s kterou přišel Petr Jůza. Myšlenka je taková, že pro různá prostředí nahrajeme různou sadu XML Spring konfiguráků.

    Kontejner (třeba tomcat) se spustí s -DENV=DEVELOP nebo testy s -DENV=UNITTEST, bez parametru se to bere jako production. Podle toho se řídí naše extense Spring ApplicationContextu a naimportuje /CONF/common/*.xml a /CONF//*.xml. V /CONF/common/*.xml tedy máme ty Spring XML konfiguráky, které jsou společné pro všechna prostředí.

    V CONF/DEVELOP/applicationContext.xml tak třeba nemáme nakonfigurovanou autentizaci přes XML security a nemusíme se tak pořád na webu přihlašovat, stejně tak třeba v PRODUCTION máme jndiDataSource beanu ale v DEVU máme SimpleDataSource.

    Další výhoda je, že pokud se nějaká nastavení sdílejí mezi DEVELOP a UNITTEST, lze je jednoduše naimportovat (v /CONF/UNITTEST/applicationContext.xml může být toto:

Leave a Reply