12 Comments

windows_open_source_Nedavno sam dobio upit da napravim jednostavnu aplikaciju za potrebe jedne udruge. Radi se o aplikaciji za praćenje zahtjeva, koja vodi evidenciju tko je predao zahtjev, tko ga provodi, evidentiraju se zabilješke, i na kraju se zahtjev zatvori. Uz to, bitno je da aplikacija prilikom otvaranja novog zahtjeva pokuša pronaći u bazi dali je slični zahtjev bio već riješen, te ponudi njegovo rješenje. Aplikacija mora imati i različite izvještaje.

Sve u svemu, radi se o spoju CRMa i Issue Trackera, a specifičnost bi bila jednostavnost korištenja i izrade, "pametni" sustav traženja postojećeg rješenja i izrada izvještaja.

Da stvar bude zanimljivija, odlučio sam aplikaciju raditi kao Open Source projekt, i putem opisivati kako sam neke stvari realizirao, zašto i slično. Tehnologije koje planiram koristiti isto nisu nešto što koristim u svakodnevnom radu, te je ovo prilika za proširenje znanja.

Za sada sam se odlučio za tehnologije:

- Silverligh 4
- ASP.NET i WCF web servisi
- RavenDb baza podataka (SQL Server sa EF Code First je backup rješenje, ako se RavenDb iz nekog razloga naljuti na mene i odbije poslušnost!)

Cilj je također koristiti tehnike i alate:

1. planiranje, projektiranje i izrada document baze. Imam iskustva samo sa relacijskim modelom podataka, i ovo će biti odlična prilika za uhvatiti se u koštac sa NoSQL problematikom! Koliko me ovo veseli, toliko me i plaši (Key/Value store, Map/Reduce funkcije, kreiranje indexa, ...)!
2. Caliburn.Micro za MVVM framework. Do sada sam koristio MVVMLight, koji odlično služi svrsi, ali opinioned pristup sa mnoštvo ugrađenih konvencija me jako privlači
3. CQS pattern: kao u predhodnom postu, htio bi:
- enkapsulirati upite, da ih mogu ponovno upotrebljavati
- slati one-way commande koje izvršavaju zapisivanje i/ili poslovnu logiku
  Do sada sam koristio CQS pattern isključivo u MVC web aplikacijama, te još nisam 100% siguran kako ovo izvesti u Silverligh klijent/server modelu, i to zbog:
- dali upite izvršavati u Silverlightu, preko RavenDb REST sučelja, ili ih slati na server i tamo izvršavati? Nikako ne želim imati standardne RPC SOAP web servise, nego više nešto nalik RESTu.
- dali komande izvršavati na serveru ili klijentu?
- kako serijalizirati querye i komande prilikom slanja preko WCFa, ako se uopće šalju?
Inspirirano prezentacijom “Dr. CQRS or: How I Learned to Stop CRUDing and Love the Domain Model” sa NDC 2011 konferencije.
4. reporting u Silverlight, još trebam odlučiti kako. Savjeti?
5. Aplikacija se mora pokretati na shared hosting okruženju, u Full Trust načinu rada

Sljedeće je plan izrade User Storya, i popisa funkcionalnosti koje aplikacija mora implementirati. Izvorni kod će biti objavljen na BitBucketu kroz tjedan-dva, čim postavim projekte i solution.

Kako je ovo jedan proces učenja novih tehnologija, očekujem puno primjedbi, komentara i sugestija! Zaželite mi puno sreće u mojem prvom Open Source projektu!

8 Comments

Pokušati ću opisati još jedan u nizu patterna za arhitekturu aplikacije, bilo web, desktop ili Silverlight, koji upotrebljavam već neko vrijeme. Pattern se pokazao jako korisnim, i to sa stajališta organizacije veće količine koda, enkapsulacije logike u zasebne, odvojive cjeline, time omogućivši i lakši unit testing. Svrha ovog patterna je i pojednostavljenje koda i uklanjanje bespotrebne apstrakcije upotrebom puno slojeva (hint: dali baš u svakoj aplikaciji treba biti layer sa Repository klasama, Service klasama sa (praznom) poslovnom logikom, i sl?).

U osnovi, radi se o starom i poznatom CQS patternu (Command Query Segragation), koji nalaže da se odvoji logika za upite (npr: dohvati sve proizvode iz kategorije), koja vraća podatke, od logike koja sadrži određeno procesiranje, i ne vraća podatke (npr: dodaj proizvod u košaricu za kupnju). Dodatnu popularnost ovaj pattern je dobio kroz upotrebu u CQRS arhitekturi, koji query/command priču diže na jedan viši, enterprise nivo, da bi se dotakli problemi (horizontalnog) skaliranja i race conditiona (više procesa se natječu za prvenstvo pristupa određenom resursu), dodajući odvojene izvore podataka za pisanje i čitanje, te asinkroni sistem zapisivanja i sinkronizacije. Dodatne informacije o CQRSu se mogu pronaći na blogu od Udi Dahana.

Primjer upotrebe ovog patterna možemo prikazati na jednostavnom primjeru web shopa, kroz upotrebu u dva scenarija:

1 Dohvat prozvoda zadane kategorije
2 Dodavanje odabranog proizvoda u košaricu za kupnju

Naravno, ovdje se radi o web aplikaciji, koja može i ne mora biti MVC.

[more]

Prvi scenarij možemo opisati generičkim interfaceom, koji potom upotrebljavamo za sve upite:

Interface IQuery<TParam, TResult> 
{ 
	TResult Execute(TParam args) 
}

ovime smo dobili enkapsulaciju logike upita u zasebnu klasu, koja nasljeđuje IQuery interface.

Drugi scenarij ne zahtjeva nikakvu povratnu vrijednost, osim eventualno bacanja Exceptiona, i opisuje se interfaceom:

Interface IHandle<T> where T:class 
{ 
	void Handle(T command); 
}

vrlo slična stvar kao i IQuery, samo bez povratne vrijednosti.

Cijelu upotrebu ovih interfaceova uvelike olakšava neki IoC/DI framework, jer on omogućava automatsko traženje konkretne implementacije određenog interfacea. Prije sam uvijek morao raditi vlastiti kod za pretraživanje klasa u assemblju, što je znalo imati skrivene bugove, a onda sam nabasao na korisnu funkciju unutar StructureMap frameworka, koji inače koristim za IoC/DI, i inicijalizacija izgleda ovako:

scan.ConnectImplementationsToTypesClosing(typeof(IHandle<>)); 
scan.ConnectImplementationsToTypesClosing(typeof(IQuery<,>));   

upotreba unutar akcije/kontrolea u MVC aplikaciji izgleda ovako:

public HomeController(IQuery<CategoryInfo,ProductViewModel> productFromCategory, 
ICommandBus commandBus) 
{ 
	_productFromCategory = productFromCategory; 
	_commandBus = commandBus; 
} 

public ActionResult CategoryProducts(int categoryId) 
{ 
	var products = _productFromCategory.Execute(new CategoryInfo(categoryId)); 
	return View(products);
} 

public ActionResult Add(int ProductID)
{
	try { 
		_commandBus.Send(new AddProductToBasketCommand(ProductID));
	}
	catch(Exception e)
	{
		// handle exception ...
	}
	return RedirectToAction("Index");
} 

Ovdje se može vidjeti upotreba CommandBus klase, odnosno ICommandBus interface-a, koji se samo “factory” za pozivanje IHandle<T> objekta, a nekako bolje opisuje namjeru i svrhu. Nije na odmet spomenuti da dozvoljava jednostavniji rast aplikacije, dodavanje novih funkcionalnosti se svodi na kreiranje novih IHandle klasa, upotreba iste logike je jednostavnija. Kod timskog rada, programer BLL sloja može u dogovoru sa Front End (FE) programerom definirati parametre za izvršavanje određenog procesa, poslovne logike, upita, i omogućiti FE programeru da samo poziva objekte prema interfaceu, ne brinući se gdje je to i kako implementirano!

Sample aplikaciju, sa primjerom ovih interface-ova, konfiguracije StructureMap-a i MVCa, možete skinuti ovdje:

https://bitbucket.org/hhrvoje/cqssample