понеделник, 21 юни 2010 г.

Кратък поглед върху Rich Ajax Platform


Първо прочетете това :)
Тази статия
е прекалено кратка и няма за цел да запознава читателя с Eclipse Plug-in Development или Rich Client Platform Development. Предполагат се общи познания по Eclipse и Eclipse разработка. http://www.eclipse.org/articles и http://www.vogella.de/articles/Eclipse са две добри места за "входна точка" в Eclipse. Започнете първо с навлизане в Eclipse откъм потребителска гледна точка, после се запознайте с архитектурната концепция на платформата, след което можете да се ориентирате към Plugin Development и RCP development спецификите. Ако вече сте направили това, тази статия ще ви даде непретенциозно въведение в RАP.

Web Application Development + Java ?
Изглежда, че към днешна дата, по-големият процент Java програмисти, включително опитните такива, не са способни да разработят Web-базирано приложение, било то богато, или не. Аз самия се вписвам в този процент. Причината е
, че този тип работа изисква специфични познания - в миналото HTML, а сега - JavaScript, CSS, Flash, ... Въпросните Java програмисти пък нямат огромно желание да учат тези технологии,  и така продължават да странят от света на Уеб приложенията. Това е проблем за софтуерната индустрия - голямо количество програмисти, част от които доста способни, не могат да бъдат оползотворени да работят точно по това, което най-много се харчи в днешно време - Web Frontend-ове. От друга страна е много трудно да си намерим качествен Web Developer - такъв, който е едновременно добър софтуерен инженер, и владее добре въпросния спектър от технологии.



Един наш шанс за Ajax в Java света, или по-точно Java EE света, е JSF. Това обаче, поне откъм начин на писане на кода, не е чиста Java технология, и отново създава бездна между Java програмирането и Web разработката. Разбира се, JSF има и големи плюсове, които няма да обсъждаме тук.

Алтернативи... 
Като говорим за RIA разработка на чиста Java, първото за което всички сме дочули и се сещаме е GWT. Вече се появяват и server-side Java технологии за RIA разработка, използващи  GWT за рендериране на страницата при клиента. Така или иначе, вече се налага схващането, че е полезно да можем да пишем уеб приложения на чиста Java.

Какво ви трябва, за да пишете за RAP...
Средата е невзискателна. Всякакъв Servlet Container (напр. Tomcat 6 инсталация), и Eclipse дистрибуция, на която да си инсталирате RAP инструментариум. След малко ще научим , че разработката на RAP приложения е много подобна на RCP/Plugin Development, следователно ще са ви нужни нещата от PDE (Plugin Development Environment) дистрибуцията. Силно препоръчително е да позлвате най-новата версия на Eclipse - за момента Galileo, след две седмици ще излезе Helios. RAP инструментариума се инсталира от този Updatesite.
За да се компилират вашите RAP приложения, ви е нужна RAP target platform-а - как се инсталира тя пише тук.
RAP инструментариума предлага вграден Web Server (Jetty), така че Tomcat не ви е нужен задължително. В случай, че ползвате Jetty, или друга OSGi-базирана разработка, например DMServer/Virgo, Felix, ще можете да се възползвате от много добра интеграция с еклипс, и лесен build/deployment. В противен случай ще ви се наложи да пакетирате приложението си в WAR архив и да използвате така наречения OSGi Servlet Bridge, за да пуснете OSGi фреймуърк в сървъра, който ползвате.






Какво е RAP
RAP е платформа за разработка на RIA, емулираща RCP в уеб среда.
Тази картинка ще видите на http://eclipse.org/rap/introduction.php, както и на всяка презентация/статия, въвеждаща в темата:










Основната цел на RAP е да позволи разработка на богати интернет приложения, преизползвайки Eclipse / RCP програмния модел. Така, на теория, един Eclipse разработчик може веднага да почне да пише Уеб приложения за RАP, без нужда от допълнително обучение.

Основните разлики са две - вместо SWT (Standard Widget Toolkit) - Eclipse-ката Native UI библиотека, се използва RWT (RAP Widget Toolkit). RWT на свой ред, вместо викания към операционната система, прави викания към Servlet контейнера, в който работи, който на свой ред обслужва клиента - уеб браузър, поддържащ JavaScript.

Нека да налегнем че RAP е платформа за писане на проложения, а не на уеб сайтове. С преизползването на RCP модела могат с не много код да се имплементират бизнес приложения, поддържащи задачи, които са свързани с комплексна интеракция с потребителя. 

Пример за такова приложение е http://ondemand.yoxos.com/geteclipse/start. Инструмента позволява да си свалим "тунингована" по наша преценка Eclipse дистрибуция, с всички нужни ни функционалнисти, като има филриране по операционни системи, Plugin/Feature Dependencies се установяват автоматично, има възможност за запазване на Download шаблони, и така нататък.  

За какво можем, и за какво - не бива, да използваме RAP
Тук ще скицираме кратки критерии, които можете да 'огледате' преди да направите архитектурния избор да ползвате RAP за вашето RIA приложение.

Можем
- Да показваме по структуриран начин различни набори информация/артефакти, живеещи на мрежата
- Да управляваме комплексни взаимодействия с потребителя
- Да изпълняваме бавни операции асинхронно, запазвайки responsiveness на интерфейса
- Да имплементираме WYSIWYG редактор...

Ако голяма част от изброените функционалности не съществуват като изисквания към приложението ни, RAP може би не е добър избор.
Например - 
- Ако информацията, която обработваме е чист текст, който няма нужда да бъде структуриран.
- Ако само визуализираме артефакти в приложението си, но не се налага да се редактират.
- Ако взаимодействията ни с потребителя не са сложни

-Ако пишем сайт - бил то и такъв, в който се споделя съдържание
- Ако не се изисква висока responsiveness на интерфейса - тогава трябва да се запитаме, нужен ли ни е Ajax фреймуърк изобщо.

Разширяемост  и управление на жизнения цикъл
Ако вашето богато уеб проложение има изискване за разширяемост (лесно добавяне на нова функционалност) и обширна конфигурация (промяна на начина, по който работи съществуващата такава), RAP може да се окаже много добър избор на платформа. Тези две функционалности идват наготово от еклипс програмния модел - а именно plugin компонентния модел и runtime модела - OSGi.
Новата функционалност, която сме внедрили, на практика би представлявала просто един нов plugin във Equinox(OSGi) инстанцията, в която върви приложението. Това означава, че при добри условия, крайния потребител ще я види, след като рестартира браузър сесията си.
Бихме могли и да напишем функционалност, която е абстрахирана от конкретните начини, по които ще бъде разширявана, четейки от Extension Registry имплементации на добре дефинирани Java интерфейси.
Обновяването на съществъваща функционалност също може да мине напълно безболезнено за цялото приложение, стига въпросната нова промяна да не е счупваща за останалия свят, и Plugin-ите които зависят на функционалността, да са толерантни към промяна на малките сегменти на версията.

Основни потребителски сценарии на RAP
Основният сценарий, заради който е разработена RAP платформата, се нарича Single-Sourcing. Целта е да може от една и съща код база да се създават богати клиентски и уеб приложения. (RAP & RCP) На практика ще има известна разлика между крайните версии на двете кодбази, но тя ще е доста ограничена, а и съществуват техники да се управлява лесно, както е подробно обяснено в прикачената към библиографията книга.
Single-sourcing техниката може да бъде използвана, когато искаме да таргетираме по-голяма клиентска група с приложението си, когато искаме да и осигурим по-всеобхватен достъп към него, или пък защото сме в начален стадий на разработка и не желаем все още да вземем решение, дали ще продаваме приложението си като "дебел клиент" или уеб клиент.

Друг сценарий би бил мигриране на съществуващо клиентско приложение към Уеб среда. Представете си например даден мейл клиент, който се използва в корпорация X като десктоп приложение. Всеки update на клиента,който трябва да се наложи на всички машини в корпоративната мрежа, е скъпо, времеемко и сложно занимание. С мигриране към Wеb интерфейс напълно се губи нуждата от такава процедура, тъй като софтуера се обновява само на едно място - на приложния сървър.
Обикновено е възможно да се мигрират съществуващи Eclipse/RCP приложения към RAP без голямо усилие. Статистически около 75% от кодбазата не се нуждае от никаква модификация.
Въпросното мигриране е добре изследвана територия, и е описано в книгата, спомената в библиографията долу. Сериозни проблеми бихме имали с приложения, които разчитат много силно на наличието на локална файлова система, работейки с org.eclipse.core.resources интерфейса.

Не на последно място, съществува и сценария, в който бихме желали да изградим чисто ново WEB приложение с RAP, защото сме решили че платформата е подходяща за задачата.

Ограничения на RAP
Тъй като до сега бяхме изцяло оптимистични, е добре да споменем няколко ограничения на RAP с цел "управляване на очакванията".

- Неразполагането с операционна система, към която да се обърнем, ни лишава от някои възможности, които бихме очаквали в RCP. Например, не можем свободно да рисуваме произволни наши форми върху интерфейса. (Това може да се промени в близко бъдеще с навлизането на HTML 5 Canvas)- Разпределеният характер на мрежовите приложения, латентността в мрежовата инфраструктура, и изискванията за скалируемост на цялото уеб приложение, налагат промени и рестрикции върху RCP програмния модел. Както се вижда от архитектурната картинка, тези промени са основно в RWT API-то спрямо SWT
- Участниците в RAP проекта са работили доста върху скалируемостта на платформата. Въпреки това не е добра идея да се използва RAP за имплементиране на тежка бизнес логика, защото приложението, за разлика от RCP света, може да бъде достъпвано от мног клиенти едновременно. Добре е подобна логика да се изнася в бизнес компоненти, които могат да скалират добре, например EJB, и RAP да се ползва за презентационен слой и "леки" обработки на данни, с цел показване в интерфейса, и подаване обратно на бизнес логиката.

бибиография:
1. http://www.eclipse.org/articles
2. http://help.eclipse.org/ 
3. http://www.eclipse.org/rap
4. Eclipse Rich Ajax Platform - bringing Rich Clients to the Web - Fabian Lange.







понеделник, 30 ноември 2009 г.

Quick tip to reduce hierarchical complexity.

This week it is going to be a short and simple one.

Say we build a set of classes implementing a particular interface. For the sake of example we can imagine these classes represent abstractions of test applications used in integration testing fixtures. We may have various implementers - web service provider applications, consumer ones, EJB applications, web applications, so forth.
Inevitably at one point in time we will realize there is common logic between the implementers - for example, creating some j2ee modules and assigning them to an ear module; deploying the application; cleaning up after the application on the fixture teardown, etc.
We may be tempted to remove the code duplication with polymorphism. This is a very common approach, but not a sound one in my opinion.
So, we create a base class to hold the common logic, and the implementers extend it. Why not cool? Well, the problem is that the classes extending this base class have little in common in terms of domain modeling. The only thing in common they have is code. Even the name of the base class will suck, which reveals a code smell. Such classes are usually called (in our example) "BaseApplication", "AbstractApplication" or something like that.
So, what to do? Simple, create utulity class or classes to hold the common code and refer them inside your hierarchy. Now, if certain implementers have special stuff to do to extend the common tasks logic, the utilities might also follow some hierarchy.
Some may say that utility objects are also a code smell, but this approach is cleaner in terms of Object modeling and simpler in terms of type hierarchy, than having a "BaseApplication". Also, it is more flexible, because Java does not support multiple inheritance (thank goodness), so when not extending the 'base application', you retain the option to extend some real class from your domain model.

петък, 19 юни 2009 г.

Integration Testing vs Unit Testing

In my last blog I described an approach to testing which i called 'Integration Unit Testing'. The basic idea was to unit-test a class against its real-life environment rather than relying on a mocking infrastructure. I cannot tell whether and when this approach is good to follow - i guess that it is a question of personal taste and intuition, as are many aspects of programming.
Another approach i would like to address, this time briefly, is the one of 'Integration Testing instead of Unit Testing'.
In a nutshell, here's what this is about:
You are given some tack to accomplish. First you write classes ImportantClass and classes B and C. Class ImportantClass does some importantStuff(), and with the aid of classes B and C seems to get the job done. Being a TDD guy, you of course beforehand write the unit tests for B, C and ImportantClass.
A few hours/days later, you discover that what you came up with is bullcrap and decide to revert your changelist. You write some new Aid classes D and E, and alter class ImportantClass to use them. Of course, BTest and CTest are no longer relevant, and you have to write DTest and ETest in their place.
Now the real bad thing is that ImportantClassTest is also no longer valid. The problem is that, being a unit test, in its bulk it does not assert that some high level business functionality is achieved. Rather, it very much asserts that e.g. some methods of B and C are called with some parameters.
Being a patient guy, you say: 'O.K. Patience my young padawan'. (You say it to yourself, knowing it is healthy for a programmer to talk to themselves.) So you rewrite the ImportantClassTest.
Of course, a day later you have another ephiphany and discover that the concept of classes D and E is bullcrap also. So you do another revert and end up in the same ordeal, rewriting again ImportantClassTest, and very much wanting to bite off your arms now.
If you end up in such a situation, where classes B,C,D, E and so forth are likely to change/drop with each ephiphany you have or each new developer working on the code, it is likely an indication that classes B,C and so forth are not key aspects to the business functionality to begin with. If they are not, perhaps the effort is not worth to unit-test them at all. So what you could do is write an ImportantClassIntegrationTest, test only thru the ImportantClass's public API and assert some business objectives are really achieved. Then you measure the test's code coverage against the code of ImportantClass and the current B, C and so forth classes. If the metric is OK, you also have done OK.
To further emphasise on the small importance and transient-ness of the B and C and so forth classes, you can either:
  • nest them inside the ImportantClass
  • create them inside the package of ImportantClass and give them package visibility.

неделя, 7 юни 2009 г.

A few words on Unit Testing, Integration Testing and Mocks

The last week at work, I was given the task to rewrite an IMHO crappy piece of code dealing with deletion of objects in some Eclipse-based editor. Actually, I just had to fix a bug and add a small new feature, but things turned out FUBAR, so after 2 changelist reverts i realized refactoring just wont do the job and tests and productive code have to be rewritten.
Half of the task went down to implementing a 'Delete' command for some Metamodel module upon which our editor, and our tool, is based.
So, trying to be a TDD guy, i sat down and started to devise a test. I devised an elaborate test fixture mocking all the functionality i had to interact with in the Metamodel module. This way, i figured, I would abstract my code from this Module as much as possible, and protect from failures in it - even if it failed, i figured, my test would still pass, and my code would still be correct.
So I spent 3 hours mocking this Metamodel, 1 hour more to devise my tests, then i implemented the functionality in the Command; and everything was tip-top - or so i thought.
The next day I got me a cup of coffee, sat at the desk and tried to manually test my code against the productive Metamodel module. Surprisingly to me, my command worked for only 20% of the input data. It turned out that the branches of the class responsible for the remaining 80% of the cases invoked the Metamodel in such manners that it would always throw exceptions. And still my low-granular, carefully devised JUnits were passing.
So all the JUnits i had written really were a prerequisite for my code to be correct, but they still gave little value to the product.
I sat down and wrote integration tests of my class with the real Metamodel module. Almost all of them would fail on the existing code. The assertions were all based on problems i saw in the live behaviour of the editor. After i get them all green tomorrow morning, the code will be next to rocket-stable.
Unit-testing, and Mocking for that matter, is rarely always the answer. Think about it - why would you want to abstract your Command from module 'A', when this Command exists for the sole purpose of interacting with module 'A', and not module 'B', 'C' or some other? Having your Unit tests pass and the integration fail is just having code that is correct from your point of view, but incorrect from the System / Customer / User point of view.
Furthermore, this Metamodel module was so widely reused throughtout our application stack, that the test fixture for the Integration test consisted of just calling a couple of handy lookup and creation services - it took me less than 20 mins to write, and the value for the product was times the value I achieved with 3 hours of EasyMocking. (what's so easy about it anyway?!).
Unit testing in isolation has real value for units which are low in the Application Stack. Mocking has real value when real object interactions are VERY expensive or VERY hard to setup. A Module high in the Application Stack of usages often has no real meaning without the Modules it relies upon; it was likely designed with these Modules in mind, and so it should - we shouldnt abstract for the sole purpose of abstraction. Likewise, tests abstracted from these modules can become meaningless too.
So, if you have a Class relying on lots of other functionality, do not rush to mock this functionality when testing. If it is not hard and expensive, setup the real functionality, feed it to the Class, and feed the Test with lots of test data. Data drive it, giving it boundary cases, normal cases, illegal inputs and anything in between. If the test passes then, you'll get real confidence the class gets the job done.
The only remaining problem is that if the modules which you rely upon fail, your Integration test will fail, too. Then, you will have harder root cause analysis and misleading test run reports. On the other hand, if A is designed as something on top of B and C, and B and C fail, does it really make sense for A's tests to pass?
The described approach has one more advantage.All the tests of classes high in the usage stack also test the low-level modules in various different circumstances equal with their real requirements, so as a result, as the project evolves, the low-level modules should become very robust.
So perhaps Unit-testing a class against its live environment is not such a bad idea. Hesitantly, i will call this approach 'Integration Unit Testing'. I shall derive more practical experience and give it some more thought, and perhaps write about it in my later blogs.