Paralelní svět

June 30th, 2008

V poslední době se hodně mluví o Erlangu. No a protože jsem slaměný vdovec a u žehlení se nudím, pustil jsem si přednášku od otce Erlangu Joe Armstronga. V tomto zápisku se chci o své dojmy z této přednášky podělit s vámi, mými oddanými fanoušky. Chci předem upozornit, že to jsou jen dojmy, pořádně ještě nemám na věc ujasněný názor.
Začátek přednášky je relativně zajímavý. Už jsem nejméně stokrát slyšel, že se programátoři musí začít chovat jinak, protože se objevily vícejádrové procesory. Ale vždy jsem si říkal, že tu máme přeci víceprocesorové stroje už hodně dlouho, tak jakápak změna. Až díky této přednášce jsem mi došlo, že změna není v tom, že máme více jader. Změna je v tom, že se sekvenční zpracování procesorů nezrychluje tak, jak jsme byli zvyklí. Od jisté doby roste rychlost hlavně díky paralelizaci. Všimněte si, že taktovací frekvence procesorů se v poslední době zas tak zásadně nemění. Naopak se objevují X jádrové procesory. Už prý existuje 1000 jádrový procesor, pokud bude růst počet jader exponenciálně, můžeme se v nedaleké budoucnosti dostat na zajímavá čísla. Předpokládejme, že je takový nárůst počtu jader možný. Dosud jsme byly zvyklí, že naše programy automaticky s novým procesorem zrychlí. Od příště už to tak být nemusí. To že klient můj sekvenční program nasadí na procesor s miliónem jader, neznamená, že bude milionkrát rychlejší. Spíš bude pomalejší než na jednojádrovém.
Tak a teď mé dojmy. Jak to ovlivňuje programátory? Protože jsem zvyklý na serverovou Javu, budu psát hlavně o ní. Představme si, že máme 1000 jádrový procesor. Jak budeme muset změnit svůj kód, aby běžel efektivně? Představme si pro začátek, že mám jednoduchou aplikaci založenou na servletech. Přijde dotaz, já ho v jenom vlákně zpracuji a v tom samém vlákně pošlu odpověď. Abych si to zkomplikoval, budu předpokládat, že ne všechna práce je výpočetně náročná, občas budu čekat na disk, databázi na jiném stroji atp. To znamená, že potřebuji mít víc vláken než procesorů (jader), abych byl schopen je vytížit. To znamená, že potřebuji víc než tisíc současných požadavků, aby ta vlákna měla co dělat (tady to trochu moc zjednodušuji, ale snad mi to prominete). Pokud je tento předpoklad splněn, nemusím svoji aplikaci měnit vůbec. Tedy za předpokladu, že JVM zvládne 1000 jádrový procesor.
Pokud mám méně než několik tisíc současných dotazů, procesor plně nevyužiji. Musím práci rozsekat na víc kousků. Jde to v Javě vůbec? Pan Armstrong tvrdí, že ne. Tvrdí, že Java je staromódní jazyk, který se spoléhá na sdílenou paměť, sdílený stav, zámky, transakce a podobná zvěrstva. Naproti tomu je Erlang moderní jazyk, který je navržen s tím, aby skvěle fungoval paralelně, který nemá problém s miliónem běžících pidiprocesů, které žádný stav nesdílejí, jenom si předávají zprávy. Tvrdí navíc, že problém Javy a podobných jazyků je přímo v jejich pojetí. Že jsou to jazyky sekvenční, kdežto Erlang je jazyk paralelní. Tvrdí navíc, že svět jako takový, je paralelní, tudíž je těžké ho popsat sekvenčním jazykem. Abych pravdu řekl, nevím jestli je svět paralelní nebo sekvenční. Na jednu stranu se každý člověk stará sám o sebe a rozhodně nesdílí svůj stav s ostatními. Jenom jim posílá všelijaké zprávy. To by nahrávalo paralelnímu pohledu. Jen ovšem do té doby, než se octnete v dopravní zácpě, která je podle mě silně sekvenční.
A v tom je právě zakopaný pes. Potíž není v jazyku, ale v řešeném problému. V Javě také nemusím sdílet žádný stav. Každé vlákno může mít svoji logicky oddělenou paměť. Když se nad tím zamyslím, tak už se to dávno děje. Proto jsou tak populární řešení založená na JMS. Jednotlivé oddělené procesy si jenom předávají zprávy. To je přesně to, co mi poskytuje Erlang. V Javě to jenom není zakomponováno přímo v jazyku. Je to v ní na logicky vyšší úrovni. A tedy i s mnohem vyšší režií.
Ano je to tak, pokud mám problém, který se dá rozseknout na hodně malých úkolů, je snadné ho paralelizovat. Ale na to není nutné měnit jazyk. Mohu použít JMS, JINI nebo jiné jednodušší mechanizmy. Stále tu ale ještě máme spoustu aplikací, které prostě vyžadují sdílený stav, jejichž doména je sekvenční, které se paralelizovat nedají. Jsem rád, že mohu používat jazyk, který mi to umožňuje.
Bylo by samozřejmě pěkné, kdyby Java umožňovala snazší spouštění paralelních úloh. Na druhou stranu k tomu už spěje. V Javě 5 byly zavedeny executory (spouštěče?), Futures a datové struktury, které nevyžadují synchronizaci. Možná není paralelní programování v Javě tak přímočaré jako v Erlangu, ale relativně jednoduché je. Takže můj závěr je následující – pokud máte problém, který je principiálně podobný telefonní ústředně, zkuste Erlang. Pokud píšete obecnou aplikaci, zůstaňte u Javy.

Kterak být agilní ve vodopádu

June 22nd, 2008

Jak máme prodat agilní vývoj managementu? Nedělejte to, oni beztak nevědí co děláte.

Onehdá jsme s takovou podivnou partou lidí v hospodě řešili, jak propagovat Agilní vývoj v jedné nejmenované firmě. Potíž je v tom, že v té firmě se vyvíjí vodopádem. (I když management tvrdí, že se tam dělá RUP.)

No a včera jsem na InfoQ narazil na zajímavou přednášku o tom, jak dělat Agilní vývoj ve vodopádu. Takže pokud vás toto téma zajímá, najděte si hodinku a čtvrt a podívejte se na to. Nedovíte se tam nic převratného, ale alespoň to naznačí, kudy by se dalo jít.

Spring field injection

June 17th, 2008

Few weeks ago, I worked on an interesting task. I had to find out how to migrate my customer’s proprietary framework to Spring. The framework was quite similar to Spring, although there were some differences. They used combination of XML and annotation configuration. Every property had special annotation saying that it is a property. XML schema for configuration was generated based on this annotation. So basically you had XML configuration that said what to inject to the annotated fields. The problem was that they did not have set methods for the fields.

And of course, the customer did not want to change all their classes just to migrate to Spring. It meant that they needed configure all the beans using Spring, but inject the dependencies directly, not through set methods.

I know that it is ugly and not recommended but in this case I think I have good excuse. It is a customer’s requirement. The question of course is how to do it.

You can try to use Spring post-processor. If you register instance of InstantiationAwareBeanPostProcessor you can use method postProcessPropertyValues to manipulate with property values just before Spring attempts to inject them. So you can inject the values into fields by yourself. And it works. The trouble is that you have to do property instantiation and conversion by yourself too. I almost managed to do it when I encountered a big problem - inner beans. In Spring, you can define a bean inside another bean. In order to inject the inner bean to the outer bean, the inner bean has to be already instantiated. But postProcessPropertyValues method is called before inner bean instantiation. So that is a blind alley.

OK, post-processor can not be used, let’s do it more hard-core. Spring has something called BeanWrapper. It is used by Spring for setting bean properties. Great, that is the point where I can force Spring to inject into the fields. The only thing I need to do, is to inject my BeanWrapper implementation into Spring. There is only one small trouble. It is not possible to do it. Unsurprisingly, dependency injection does not work inside the dependency injection code. I tried hard, but did not find any simple and safe way how to replace default BeanWrapper implementation. (If you know how to do it, please let me know)

So, if it is not possible to force Spring to inject without set method, let’s give him what he is asking for. The final solution is simple. When instantiating beans, I do not instantiate the original class but a subclass that is generated in the runtime and has all needed set methods. For the class generation I use Javassist, it is simple and powerful. To make the integration with Spring as simple as possible, I use factory bean. So the Spring XML config file looks like this

	<bean id="beanFactory" class="net.krecan.beanfactory.SetMethodGeneratingBeanFactory"/>
	<bean id="sampleClass"
		      factory-bean="beanFactory"
		      factory-method="createBean">
		<constructor-arg value="net.krecan.beanfactory.Sample"/>
		<property name="textProperty" value="test.txt"/>
		<property name="intProperty" value="123"/>
		<property name="simpleSample">
			<bean factory-bean="beanFactory"
			   factory-method="createBean">
				<constructor-arg value="net.krecan.beanfactory.SimpleSample"/>
				<property name="textProperty" value="hallo"/>

			</bean>

		</property>
	</bean>

Instead of providing class name in the bean definition, factory-bean attribute is used. Spring than calls method createBean on the factory bean with parameter taken from the constructor-arg element. It contains the class name of the bean. The result of the method call is used as a bean instance and all the properties are set by Spring.

Of course, you do not have to write it this way every time you want to instantiate this kind of bean. Simple custom namespace can be created in order to simplify the syntax.

In the future, when my customer realize that setters are a good thing, the factory can be easily replaced by a dummy implementation.

To reiterate, direct injection of dependencies from XML to the fields without using set methods is not supported by Spring. You can choose between XML based configuration using set methods or annotation based configuration. It is extremely hard to change default Spring behavior. And maybe it is a good thing. So if you need to do ugly XML based field injection, your only choice is to generate set methods in the runtime. Or maybe something else, but I have no idea what.

Read the rest of this entry »