czwartek, 31 lipca 2008

Podpięcie projektu do Subversion (SNV) - cz. 1

Kontrolę wersji w Visual Studio można zrealizować przy użyciu (niezbyt udanego) M$ produktu - Source Safe. Niestety z tego co wiem, to za Source Safe'a trzeba słono zapłacić oraz nie da się go spiąć z wersją Visual Studio Express. Więc co maja zrobić "biedni" użytkownicy, którzy chcą mieć kontrolę wersji we własnym projekcie? Odpowiedź jest prosta, powinni się zainteresować Open Sourceowym SVN'em. Bez zbędnych przedmów weźmy się za instalację.

Na początek przyjdzie nam ściągnąć pliki:
- http://www.visualsvn.com/server/ - zawiera niemal wszystko czego potrzebujemy ("It includes Subversion, Apache and a management console. ")
- http://tortoisesvn.tigris.org/ - klient do SVN'a

Instalacja.
Najzwyczajniej w świecie instalujemy VisualSvn oraz TortoiseSvn. Nie ma co tu opisywać, stara dobra metoda przy instalacji "dalej, dalej, dalej ... " raczej się sprawdzi ;)

Po instalacji musimy zresetować komputer, gdyż muszą zostać wprowadzone zmiany.

....

Okey, jesteśmy po resecie :)

Klikamy sobie np. na pulpicie prawym klawiszem i pojawiają nam się 2 dodatkowe opcje:


Zatem teoretycznie wszystko jak na razie idzie dobrze. Zapewne serwer SVN działa, więc przejdźmy do utworzenia repozytorium plików. W tym celu uruchamiamy "VisualSVN Server Manager".



Tworzymy nowe repozytorium:


Nadajemy nazwę:


Gotowe, repozytorium TestoweRepo już sobie stoi:


Zajmiemy się teraz wrzuceniem do naszego repozytorium przykładowego projektu.
Przyjmijmy, że wchodzimy do katalogu E:\Projekty\ gdzie znajdują się ważne projekty. Prawy klawisz na katalogu E:\Projekty -> SVN CheckOut pojawia się nam okno:



Urla musimy pobrać z VisualSVN:


Następnie go wklejamy i akceptujemy:


Na katalogu E:\Projekty powinna się pojawiać zielona ikonka



Teraz na wszystkim co się znajduje w E:\Projekty pojawiła się ikonka z pytajnikiem, znaczy to, że plik jest w katalogu zespolonym z SVN, lecz on sam nie jest. Musimy ręcznie go dodać:



Dodajemy do SVN:


Akceptujemy wszystko i pojawia się nam okno:


Odświeżamy nasz katalog. Powinna się na nim pojawić ikonka z plusem, co znaczy, że "już prawie dodaliśmy katalog" ;) do repozytorium:


Musimy potwierdzić przez wybranie Commit'a:


Zgadzamy się na wszystko i po skończonym commitowaniu na katalogu powinna się pojawić znajoma już ikonka:



Ufff :) mamy już to co chcieliśmy w repozytorium. W następnej części zajmiemy się integracją z Visual Studio Express.

niedziela, 27 lipca 2008

Dependency Injection + Autofac + mały przykład

[Wymagania: .NET 3.5]
Załóżmy że mamy zrealizować bardzo proste zadanie: zmienić wszystkim osobom o jakimś wieku ich imię. Więc...

Mapujemy osobę:




class Osoba
{
public int Id { get; set; }
public string Imie { get; set; }
public int Wiek { get; set; }

public override string ToString()
{
return string.Format("{0} {1} {2}", Id, Imie, Wiek);
}
}

Symulujemy działanie Data Access Layer (zwracającego wszystkie osoby)

interface IDal
{
IEnumerable<Osoba> Osoby { get; }
}

class Dal : IDal
{
private IEnumerable<Osoba> osoby = new List<Osoba>()
{
new Osoba() { Id = 1, Imie = "osoba1", Wiek = 23},
new Osoba() { Id = 2, Imie = "osoba2", Wiek = 23},
new Osoba() { Id = 3, Imie = "osoba3", Wiek = 32}
};

public IEnumerable<Osoba> Osoby { get { return osoby; } }
}

Tworzymy Data Access Object (LINQ wyciągający osoby przy użyciu IDal)
interface IDaoOsoby
{
IEnumerable<Osoba> FindByWiek(int wiek);
}

class DaoOsoby : IDaoOsoby
{
private IDal dal;

public DaoOsoby(IDal dal)
{
this.dal = dal;
}

public IEnumerable<Osoba> FindByWiek(int wiek)
{
return from osoba in dal.Osoby
where osoba.Wiek == wiek
select new Osoba() { Id = osoba.Id, Imie = osoba.Imie, Wiek = osoba.Wiek };
}
}


Serwis odpowiedzialny za zmianie imion (główna logika)
interface IServiceOsoby
{
void ZmienImie(int wiek);
}

class ServiceOsoby : IServiceOsoby
{
private IDaoOsoby daoOsoby;

public ServiceOsoby(IDaoOsoby daoOsoby)
{
this.daoOsoby = daoOsoby;
}

public void ZmienImie(int wiek)
{
IEnumerable<Osoba> osoby = daoOsoby.FindByWiek(wiek);

foreach (var osoba in osoby)
{
osoba.Imie = "zmienione imie";
}
}
}

Dzięki temu, że wszystko oparte zostało na interface'ach uzyskaliśmy bardzo elastyczną
i niepowiązaną żadnymi zależnościami strukturę
. Świetnie, o to właśnie nam chodziło :)
Teraz wystarczy określić zachowanie przez "wstrzykniecie" konkretnych klas do konstruktorów.

Jeśli chodzi o testy jednostkowe, to stworzenie ich nie będzie żadnym problemem.
Dzięki użyciu Dependency Injection możemy testować jedną warstwę niezależnie od drugiej.
Tutaj przyjdą nam z pomocą Mock'i, lecz zostawmy sobie to na później :)

Rzućmy okiem w jaki sposób możemy się tym wszystkim posługiwać.


class Program
{
static void Main(string[] args)
{
// "Normalne" użycie
IDal dal = new Dal();
IDaoOsoby daoOsoby = new DaoOsoby(dal);
IServiceOsoby service = new ServiceOsoby(daoOsoby);

service.ZmienImie(23);

// Autofac
ContainerBuilder cb = new ContainerBuilder();

cb.Register<Dal>().As<IDal>().SingletonScoped();
cb.Register(v => new DaoOsoby(v.Resolve<IDal>())).As<IDaoOsoby>();
cb.Register(v => new ServiceOsoby(v.Resolve<IDaoOsoby>())).As<IServiceOsoby>();

Container container = new Container();
cb.Build(container);

container.Resolve<IServiceOsoby>().ZmienImie(23);
}
}




Jest to tylko bardzo "drobny i ogólny" przedsmak tego co będzie działo w kolejnych postach :)

kod źródłowy

środa, 23 lipca 2008

TDD. Przykładowa aplikacja cz. 5 / System płacowy cz. 1

Hmm klient się do nas wciąż nie odzywa. W sumie to i dobrze, bo ciągle robimy sobie wakacje ale dość tego! Czas się zająć refaktoryzacją naszej aplikacji. Podczas trwania urlopu na obozie programistycznym (jasne ;)), dowiedzieliśmy się o istnieniu całkiem ciekawych projektów: Autofac oraz PostSharp. Tak bardzo nas zainteresowały, że postanowiliśmy je wdrożyć do całej aplikacji. Ba! co tam chodźmy za ciosem, przebudujemy całą i DAJMY JEJ W KOŃCU JAKĄŚ nazwę ;)!.. póki klient milczy. Zacznijmy więc od początku.

Podzielmy naszą aplikację na warstwy.

I. Warstwa dostępu do danych. Tutaj stworzymy mechanizm odpowiedzialny za dostęp/komunikację z bazą, zupełnie elastyczny, niezależny od rodzaju bazy.

II. Domain Model (Model dziedziny). Zmapowane tabele bazy danych, DAO, reguły biznesowe.

III. Services (Serwisy). Ta warstwa będzie udostępniać funkcje aplikacji (coś na kształt uporządkowanego API systemu).

IV. Interface Klienta. Czyli po prostu w skrócie... formatki ;)


Cały model będzie tak wyglądać:



Nie noo.. wszystko super, zobaczymy jak to wyjdzie w praktyce.

Strukturę już mamy, wiemy co mamy robić, toteż przyszedł czas na nadanie nazwy dla programu... może po prostu... System Płacowy...? Mało oryginalny :| lecz nasz zlasowany mózg po urlopie na razie nie jest w stanie wymyśleć czegoś chwytliwego ;)

Bierzmy się do roboty.

Ściągamy projekty:
-NAnt
-NHibernate (później nam się przyda)
-NUnit
-NMock
-Ninject
-PostSharp

Na pierwszy rzut idzie I warstwa, dostęp do danych.

cdn.