W tym odcinku skupiam się na stanie aplikacji przed jakimikolwiek procesami “upiększającymi”. Stan ten można uzyskać wykonując
git checkout demo1
na podlinkowanym w poprzednim poście repo. Albo można podglądać sobie online: https://github.com/maniserowicz/di-talk/tree/demo1.
Aplikacja, którą mamy upiększyć, została do celów demonstracyjnych zbudowana dość nietypowo. Nie jest to web app, nie jest to nawet console app. Jest to jedna zwykła dllka, ale…
Nie chcemy wiązać się tutaj z żadnym konkretnym frameworkiem. Zamiast tego zasymulujemy dowolny typ aplikacji, który “obsługuje żądania”. Czyli tak naprawdę każdą aplikację. Może to być aplikacja webowa: obsługuje żądania z przeglądarki. Może to być serwis: obsługuje żądania z innych aplikacji. Może to być nawet coś desktopowego, gdzie żądaniem jest akcja użytkownika.
Sercem systemu jest “symulator” dowolnej implementacji “infrastruktury” oferowanej przez jakikolwiek framework do tworzenia aplikacji. Nazwałem to “WebServer” i wygląda tak:
public class WebServer { public void RegisterUser(string email) { var controller = new UsersController(); controller.RegisterUser(email); } }
(https://github.com/maniserowicz/di-talk/blob/demo1/src/app/WebServer.cs)
Jak widać, jest to część odpowiedzialna za przyjęcie żądania “skądś”. Akcja, jaką ktoś może wywołać z zewnątrz, to rejestracja nowego użytkownika, a właściwie jego maila. Nasz WebServer musi wykonać dwie czynności:
- powołać do życia kawałek aplikacji potrafiący faktycznie zrealizować żądanie (tutaj: UsersController)
- wywołać na nim odpowiednią metodę (tutaj: RegisterUser()), przekazując otrzymane parametry
Punkt trzeci byłby zwróceniem rezultatu, ale w tym przypadku to pomijamy.
Proces rejestracji użytkownika składał się będzie z paru dość standardowych kroków:
- sprawdzamy czy podany adres e-mail jest poprawny
- sprawdzamy czy podany adres e-mail nie jest już zajęty w systemie
- tworzymy obiekt reprezentujący nowego użytkownika z podanym adresem oraz unikatowym “tokenem” pozwalającym na weryfikację, czy inicjator akcji jest faktycznie właścicielem konta e-mail
- wrzucamy użytkownika do bazy
- generujemy “link aktywacyjny” zawierający podany adres e-mail oraz przypisany wcześniej użytkownikowi token
- wysyłamy mail z linkiem aktywacyjnym
Standard, prawda? Wszystkie te czynności są zrealizowane w… a jakże, UsersController!
public class UsersController { const string EMAIL_REGEX = @"[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}"; public void RegisterUser(string email) { // check if email is valid if (Regex.IsMatch(email, EMAIL_REGEX) == false) { throw new ArgumentException("Invalid email address"); } // check if email is not taken if (UsersDatabase.IsEmailTaken(email)) { throw new InvalidOperationException("Email already taken"); } // create new user var newUser = new User { Email = email, RegistrationToken = Guid.NewGuid().ToString(), }; // insert user UsersDatabase.InsertUser(newUser); // generate activation link string registrationLink = string.Format( "http://myapp.com/confirm?email={0}&token={1}" , newUser.Email, newUser.RegistrationToken ); EmailService.RegistrationEmail(newUser.Email, registrationLink); } }
(https://github.com/maniserowicz/di-talk/blob/demo1/src/app/UsersController.cs)
BTW wykorzystane tutaj klasy nie posiadają implementacji – póki co służą tylko jako “coś do wywołania”.
Przyznajcie się, ile razy w życiu widzieliście taki kod? Ba, może nawet taki pisaliście?
Ja się przyznaję: i widziałem, i pisałem. Buuuuu, żal i płacz jak nic. No ale trudno, nie dość że każdy rodzi się głupi, a potem uczy się całe życie, to większość i tak głupia umiera. Natura.
Taki kod (a należy pamiętać, że jest to dość prosty przypadek klasy z jedną tylko metodą) woła o pomstę do nieba. Źle się to czyta, więc źle się to będzie utrzymywać. Strach czegokolwiek ruszać, bo nie da się do tego napisać testów. Ba, ciężko byłoby to nawet przetestować ręcznie! Jakakolwiek modyfikacja owego potwora prawdopodobnie wiązałaby się ze składaniem ofiar całopalnych i niejedną przelaną łzą.
A co jeśli oprócz maila chciałbym wysyłać też SMSa?
A co jeśli chciałbym sprawdzić czy każda z niezależnych od wszystkiego innego akcji (wygenerowanie linka, walidacja maila, wygenerowanie treści wysyłanej wiadomości…) działa jak powinna bez nieustannego debuggowania i klikania?
A co jeśli chciałbym mieć uczucie zbliżone do pewności, że wszystkie te działania ze sobą współgrają, czyli że e-mail nie zostanie wysłany na niewalidujący się adres albo że user zostanie dodany do bazy tylko jeśli w systemie nie ma już zarejestrowanego takiego adresu?
A co jeśli chciałbym dodać bardziej skomplikowaną walidację adresu e-mail niż tylko poprzez głupi regex?
A co jeśli chciałbym uzyskać transakcyjność na poziomie infrastruktury, coby użytkownik nie został w bazie jeśli nie powiedzie się wysyłka wiadomości, przez co nigdy nie mógłby zweryfikować adresu e-mail, a więc aktywować konta?
A co jeśli… popuszczę wodze fantazji i wymyślę kolejnych kilkanaście potencjalnych scenariuszy? Nic, nudno będzie, więc na tym poprzestanę.
Zróbmy coś z tym…
Super się zapowiada;)
Kamil,
To się cieszę:). Nie wiem ile odcinków z tego wyjdzie, podejrzewam że w sumie około 10 nawet może się urodzić.
DI: punkt wyjścia | Maciej Aniserowicz o programowaniu…
Dziękujemy za dodanie artykułu – Trackback z dotnetomaniak.pl…
Temat według mnie bardzo ciekawy, i dla mnie osobiście zaliczający się do kategorii “eye opener” (względnie “mind f*ck”) ;) Chętnie dowiem się czegoś nowego i skonfrontuję z moim aktualnym stanem wiedzy ;)
A ja się zastanawiam, czy da się jeszcze coś napisać o IoC i DI czego nie było już na 100 innych blogach? I to kilka lat temu. I wydaje mi się, że nie. Ale oczywiście mogę się mylić.
Piotr,
Nikt nie twierdzi że tu jest/będzie coś nowego czy odkrywczego. Wiem że moja prelekcja się podobała, więc może i w postaci postów również komuś się przyda, tyle. Poza tym nie bardzo kojarzę temat DI/IoC poruszany na polskim blogu, a polską blogosferę .net śledzę od lat (chociaż niezbyt dokładnie więc być może coś mi “umkło”).
Ok.
Po prostu co mi wpadnie jakiś pomysł na posta na mój skromny na razie blog to wydaje mi się, że temat już na maksa oklepany i z tego rezygnuję.
Piotr,
Zmień to – pisz o tym o czym chcesz napisać, co aktualnie robisz, co cię zainteresuje, a nie o tym, o czym jeszcze nikt nigdy nie napisał.
Czy będzie kolejny post, który pokarze odpowiedzi na zadane pytania/wątpliwości? Jestem bardzo ciekawy.
Dziękuję i pozdrawiam,
Tomek
Tomek,
To będzie cykl pewnie ok 10 postów. Zobacz poprzedni wpis.
Super już nie mogę się doczekać kolejnych części.
Maciej obecnie próbuje się odnaleść w dobrych praktykach programowania jakie blogi miejsca zagraniczne lub też polskie możesz polecić by właśnie tą wiedze poglębić?
Tomasz,
To się cieszę :) Kolejny odcinek już jutro, a następne minimum raz w tygodniu.
Co do blogów to proszę bardzo: http://dotnetomaniak.pl , http://dotnetblogs.pl