čtvrtek 28. ledna 2010

Proč nepotřebuji (zatím) asynchronní JDBC

Lukáš Křečan se zkusil zamyslet nad tím, jestli v Jave potřebuje asynchronní JDBC API a svůj závěr vtisknul přímo do článku Proč nepotřebuji asynchronní JDBC. Já si dovolím Lukášem mírně doplnit.

Nejdříve bychom si mohli demonstrovat na jednoduchém kódu Lukášem zmiňované Servlet 3.0 API s podporou asynchronního volání, které bude v našem dalším povídání hrát důležitou roli.

@WebServlet(name = "AsyncServlet", urlPatterns = { "/AsyncServlet" }, asyncSupported=true)
public class AsyncServlet extends HttpServlet {
 
  protected void doGet(HttpServletRequest request, HttpServletResponse response) {
  AsyncContext ac = request.startAsync(request, response);
  ac.start(new Worker(ac));  
 }
 
 public static class Worker implements Runnable {
  private final AsyncContext ac;
  
  public Worker(AsyncContext ac) { 
   this.ac = ac;
  }

  @Override
  public void run() {
   HttpServletResponse response = (HttpServletResponse) ac.getResponse();
   try {
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = null;
    try {
     out = response.getWriter();
     out.println("<html>");     
     out.println("<body>");
     out.println("<h1>Servlet AsyncServlet output</h1>");
     for(int i = 0; i < 10000; i++) {
      out.println("<p>Asynchronously generated response :-)</p>");
      out.flush();
      try {
       Thread.sleep(200);       
      } catch (InterruptedException e) {}
     }
     out.println("</body></html>");     
    } catch (IOException e) {     
    } finally {
     out.close();
    }
   } finally {
    ac.complete();
   }
  }
 }
} 
  

Trocha popisu. Na řádku 5 instruujeme kontejner, že požadavek bude vyřízen asynchronně. Na řádku 6 odpálíme asynchronní exekuci. V tomto případě se použije vlákno z poolu servletového kontejneru. Samozřejmě to nemusí vždy vyhovovat a my mužeme vytvořit klasický ThreadPoolExecutor a vlákna brát z něj.

Po vykonání řádku 6 se nám tedy v novém vlákně spustí exekuce viz třídá Worker a původní vlákno servletového kontejneru dokončí metodu doGet a může být použito k obsluze jiného HTTP požadavku. Metoda run třídy Worker tedy běží v jiném vlákně. Pomocí AsyncContextu, který jsme si předali a tvoří nás komunikační kanál se servletovým kontejnerem, jsme schopni vytvořit repsonse. Dokončení asynchronní práce se signalizuje voláním metody complete na řádku 40.

Nyní k jádru pudla. Kde nám do hry vstupuje ono vzývané asynchronní JDBC API. Představme si náš příklad lehce upraven o volání nám dobře známého JDBC. Stačí nám pouze třída Worker.

public static class Worker implements Runnable {
  private final AsyncContext ac;
  
  public Worker(AsyncContext ac) { 
   this.ac = ac;
  }

  @Override
  public void run() {
   Connection conn = getConnectionFromSomewhere();
   PreparedStatement ps =  conn.prepareStatement("insert into orders (a) values ('a')");
   ps.executeUpdate();
      ac.dispatch("/dekujeme-za-nakup.jsp");   
  } 
 }    

Co se stane? Servletový kontejner má vlákno vrácené a může obsluhovat další HTTP požadavky, ale vlákno vykonávající metodu run bude zablokované na řádcích 10 a 12. Jíra Mareš má do jisté míry pravdu, že na řádku 10 nám může pomoci poolovaní na úrovni databázových připojení. Nicméně vlákno bude zablokováno nejpozději na řádku 12.

Představme si situaci, že máme eschop a uživatel právě učinil nákup. Požadavek se odeslal a kód zůstal trčet na řádku 12. Asi nechceme, aby měl uživatel deset sekund "zmrzlé" UI prohlížeče, ale raději bychom mu ukázali stránku kde mu poděkujeme za nákup a třeba ještě něco nabídli z dceřiného obchodu.

Bez asynchronního JDBC API musíme obě blokující volání (10,11) zabalit ručně do asynchronního volání. Původní metoda run potom vypadá přímo pohádkově.

@Override
public void run() {
 new Thread(){    
  public void run() {
   Connection conn = getConnectionFromSomewhere();
   PreparedStatement ps =  conn.prepareStatement("insert into foo (a) values ('a')");
   ps.executeUpdate();
  }    
 }.start();   
 ac.dispatch("/dekujeme-za-nakup.jsp");
} 

Nechtěl bych zde polemizovat, že JDBC je samospasné. Je to jenom špička ledovce. Každopádně je to dobrý začátek k tomu, aby si podobným způsobem nemuseli zaneřádit kód aplikační vývojáři. Samo o sobě asynchronní JDBC nepřinese žádné drastické zvýšení výkonu (v tom jsme s Lukášem za jedno), snad možná svižnější UI. Aby mělo asynchronní JDBC nějaký výkonnostní dopad, bylo by potřeba mít driver a databázi, která asynchronní volání podporuje.

A mimochodem není to taková utopie viz níže

středa 27. ledna 2010

Oracle Sun akvizice. Hotovo a potvrzeno.

Larry Ellison ve webcastu k finálnímu dokončení akvizice firmy Sun (nyní již Oracle) uklidnil všechny javisty. Do Javy se investovat bude viz FAQ. Najdete tam i kusé informace o tom co se chystá Oracle udělat se Solarisem, MySQL, NetBeans a dalšími produkty. Ještě dávám k dobru hlášky, které mě pobavily a zaujaly z twitterového vysílání k této události. IBM a cloud computing si to od Larryho pěkne slíznul.

RT @Oracle: Larry Ellison: Solaris will be the OS for a cluster of computers, not just a high end box #oraclesun

Larry: "Best 2 databases on planet are DB2 on mainframes and Oracle on modern computers" #oraclesun

RT @sunmicrosystems: Larry Ellison: we are going to make MySQL better #oraclesun

RT @Oracle: Larry Ellison: Solaris will be the OS for a cluster of computers, not just a high end box #oraclesun

RT @vandenadort: Larry: IBM doesnt have Java, they haven't got Oracle database, what they have is a problem. They're a decade behind us #oraclesun

RT @oracletechnet: Ellison: I love Linux, but Solaris is more mature and reliable for the high end #oraclesun

Larry Ellison: DB2 is about a decade behind when it comes to Oracle technology #oraclesun

Ellison "Why in the world didn't IBM create a scalable dbase machine. IBM is far behind, I don't think they have a chance at all."#oraclesun

#oraclesun: Ellison: "I can't understand why IBM has never come out with a database machine. DB2 doesn't cluster, doesn't scale, nothing."

#OracleSun LE: won't measure Java success in terms of revenue but in terms of tech success->Sun tried this, might work for Oracle?

Ellison: "There is no in-memory dbase that will take the place of a relational dbase." #oraclesun

Larry - The only thing new about Cloud is the name, we've been doing it for years. Itunes, Sales Force, etc all run #Oracle #oraclesun

RT @oracletechnet: Ellison: The only thing new about cloud computing is the word "cloud" - it's just a computer attached to the Internet #oraclesun

neděle 24. ledna 2010

Nedělní rozjímání nad softwarovým vývojem

Nemálo lidí přemýšlí o různých technikách zefektivnění softwarového vývoje. Zažil jsem metodologií, která byla klasický vodopád obohacený a milestony po šesti týdnech. Tedy na začátku se udělal sběr požadavků, jejich analýza, pak design, implementace a verifikace/testování na závěr. Každou z těchto činnosti dělal v podstatě jiný tým lidí. Sběr požadavků dělal tým funkčních architektů, analýzy techničtí architekti, design a implementaci vývojáři a verifikaci a testování oddělení kvality. Ačkoliv tento systém vývoje fungoval, mohl fungovat daleko efektivněji a lépe.

Prvním problémem je více méně striktní rozčlenění odpovědností, ačkoliv by se to mohlo zdát jako logické a správné, tak je to ve své podstatě kontraproduktivní. Práce každé skupiny má totiž jasný začátek a konec, s tím, že na ní navazuje práce jiné skupiny. Bohužel to sebou šílený redundanci v podobě sdílení informací. Když osoba A na začátku celého řetězu něco vymyslí nebo změní, je potřeba tuto informaci rozšířit přes všechny navazující skupiny a to v jakýkoliv okamžik.

Aby se této redundanci v předávání informací zamezilo, vznikají dokumenty. Celé řádka dokumentů v různých revizích, které popisují co prěsně autor zamýšlel. Máme sice jedno místo, kde se udržují informace, ale lidé musí pálit čas tím, aby tyto informace sepsali a další lidé tím, aby je vstřebali.

Obecně si myslím, že rozškatulkovaný vývoj na skupiny lidí prostě nefunguje kvůli sociálním problémům. Jedna skupina si něco vymyslí a další za měsíc zjistí, že to je neproveditelné. Vznikají zbytečné třenice díky tomu, že architekt požaduje Táčmahál a vývojáři jsou schopni dodat v lepším případě srub kanadského dřevorubce nebo v tom horším kůlničku na dříví.

Druhý problém je v tom, že fáze analýzy je sice ukotvená na začátku celého procesu nicméně pouze pro to, aby se na jejím základě dokázaly udělat časové odhady náročnosti a proto, aby mohli další skupiny lidí pracovat. Bohužel tento přístup má poměrně zásadní nedostatek. Né vždy totiž vidíme plně pod kapotu celého řešení. Spíše naopak, vidíme pouze tu část, se kterou jsme dobře seznámeni a dopad na navazující části nám často uniká. Takže naše analýza z principu stojí na vodě. Zkuste v takovém případě udělat odhad časové náročnosti.

Teď jsme si popsali, některé z nevýhod a teď jak proces zrefaktorovat, tak aby fungoval k plné spokojenosti všech zúčastněných.

Prvním problém je odstranění informační bariéry a sdílení informací.

Psát v případě funkčních požadavků desetistránkové pamflety je nesmysl. Nejpochopitelnější je načárat funkční specifikaci na chování uživatelského aplikace a přidat stručný popis. Pokud to nedokážete, pak je nejspíše problém v tom, že zadání je příliš složité. Příliš složité zadání na úrovni uživatelského rozhraní nejspíše neznamená, že by zadání bylo složíte. Spíše to svědčí o tom, že to co uživatel chtěl bylo špatně pochopeno. Když chce uživatel skalpel, dejte mu skalpel a nikoliv multifunkční švýcarský nožík, který obsahuje navíc šroubovák, vývrtku a pilník.

Nepište analýzy pokud to není opravdu potřeba a rozhodně je nepoužívejte jako zadání práce pro někoho jiného a nebo k časovým odhadům. Důležitá rozhodnutí, která mají tendenci se v analýzách objevovat, odložte až na poslední možnou chvíli (viz Lean software development) kdy budete mít všechny potřebné informace.

An agile software development approach can move the building of options earlier for customers, thus delaying certain crucial decisions until customers have realized their needs better. This also allows later adaptation to changes and the prevention of costly earlier technology-bounded decisions.

Prací softwarového vývojáře není sepisování esejí či jejích louskání. Nejefektivnější způsob výměny informací je přímá komunikace a zapojení se všech členů týmu ve všech činostech vývojového cyklu. Striktní rozdělení činností vede pouze k vytváření bariér. Vedlejším efektem je to, že se určitá část lidí specializuje pouze na určitou část řešení. Dochází potom k třenicím, že lidé co dělají uživatelské rozhraní se cítí odstrčení od jádra systému a ty co dělají jádro nemají potuchy co potřebují ti co dělají uživatelské rozhraní. Stejný kastovní systém dělá problém i při dělení na vývojáře a architekty.

Možná je to anarchie, možná je to cowboy coding, ale podle mého soudu by všichni měli dělat všechno. Tím se nejlépe sdílí týmové znalosti a nutí to k větší míře komunikace. A lidi to pochopitelně víc baví. Striktní rozdělení na architekty a vývojáře neexistuje. Zásadní rozhodnutí se přijímají společně. Funkci architekta v uvozovkách drží vývojáři, kteří jsou respektování zbytkem týmu a mají dostatečnou autoritu fungovat jako arbitr sporu typu použijeme knihovnu typy X nebo Y.

Vsuvka:Role manažera spočívá pouze v tom, že poskytuje servisní služby zbytku týmu. Dělá zapisy meetingu, zajišťuje hardware/software, dohlíží a připomíná na termíny, zajišťuje komunikaci s dalšími tými. V podstatě slouží jako tlumič různých byrokratických omezení. Manažer nikdy neděla technologická rozhodnutí nicméně jeho názor je vítán a respektován.

Občas mám pocit, že se různé procesy a metodiky vývoje hodně přeceňují. Z výše uvedených řádku by mohl leckdo nabít dojmu, že jsem vodopád zrefaktoroval například na Scrum. Přiznám se, že nevím, agilních metodik je celá řada. Někdy je to hra se slovíčky a ve výsledku se dospěje k tomu samému. Já osobně věřím ve dvě věci při softwárovém vývoji.

  • komunikace, komunikace a zase komunikace namísto byrokracie snažící se komunikaci suplovat
  • silné individuality jako jádro malých týmů, kde každý člen se podílí na všech činoostech

Jestli tomu bude říkat nebo v tom hledat Scrum, Iterative and incremental development či Lean software development je poměrně nezajímavé.