Baza danych dla każdego dewelopera!
Rozwiązanie takie nie jest doskonałe, ponieważ podczas intensywnych prac deweloperzy mogą niszczyć sobie nawzajem dane, na których testują swój kod. Powyżej pewnej krytycznej liczby osób w projekcie, efektywność takiego rozwiązania spada drastycznie. Kolejnym minusem jest problem z uruchamianiem automatycznych testów bazodanowych: jeśli dwóch deweloperów będzie próbować zrobić to w tej samej chwili efekt może być nieprzewidywalny. Wystarczy kilka takich “wpadek”, aby skutecznie zniechęcić zespół do uruchamiania testów…
W moim wypadku wszystkie wymienione powyżej problemy byłyby do zniesienia. Zadecydowała dopiero specyfika projektu: część danych jest synchronizowana pomiędzy dwoma aplikacjami wchodzącymi w skład rozwiązania. Synchronizacja ta odbywa się za pośrednictwem NServiceBus oraz kolejek MSMQ. Istnieje przez to realna groźba całkowitego rozsynchronizowania danych, ponieważ kolejki znajduja się na maszynach deweloperskich, a baza jest współdzielona.
Idealnie byłoby, aby każdy deweloper dysponował kompletnym środowiskiem: zarówno kolejkami, jak i bazą danych. Problem pojawia się w momencie definiowania łańcuchów połączeń do bazy danych. Framework sam z siebie nie udostępnia żadnego gotowego mechanizmu rozwiązującego go. Do dyspozycji mamy jedynie półśrodki: zewnętrzne pliki konfiguracyjne (atrybut conigSource) oraz EntLib-owe pliki “łatek”.
Ja zdecydowałem się na użycie tego pierwszego mechanizmu. Potrzebowałem jedynie jakoś zarządzać tymi zewnętrznymi plikami. Moje rozwiązanie zakłada, że każde solution ma wspólną konfigurację bazodanową. Jest ona zlokalizowana w folderze Configuration. Folder ten zawiera podfoldery dla każdego użytkownika – dewelopera. W mojej firmie korzystamy z domeny AD, więc w Configuration znajdują się katalogi o nazwach takich jak loginy użytkowników, np. Configuration\Szymon.Pobiega. W takim folderze zlokalizowane są pliki konfiguracyjne specyficzne dla mojego środowiska. W tym momencie jest to jeden plik – Database.config – zawierający connection string do instancji SQL znajdującej się na mojej maszynie.
Zastanawiacie się pewnie po co to wszystko? No więc sednem mechanizmu jest malutki programik (możecie go pobrać stąd), który potrafi kopiować plik konfiguracyjny związany ze środowiskiem zalogowanego użytkownika z głównego “repozytorium” (folder Configuration) do katalogu docelowego build-a danego projektu. Programik włączany jest w proces budowanie za pomocą zdarzenia PostBuild. Przykładowe konfiguracje wyglądają następująco:
E:\FoldeGłównyTeamProjectu\Common\ConfigCopier.exe Database.config $(SolutionDir)Configuration $(ProjectDir)\bin
E:\FoldeGłównyTeamProjectu\Common\ConfigCopier.exe Database.config $(SolutionDir)Configuration $(TargetDir)
Argumenty ConfigCopier-a to:
- nazwa pliku konfiguracyjnego
- ścieżka do głównego repozytorium
- ścieżka docelowa
Pierwsza z konfiguracji dotyczy aplikacji ASP.NET, druga “zwykłego” projektu. Zwróćcie uwagę na delikatną różnicę w określeniu lokalizacji docelowej. Sekcje connectionStrings mają postać, odpowiednio:
<connectionStrings configSource=“bin\Database.config“/>
<connectionStrings configSource=“Database.config“/>
W przypadku aplikacji ASP.NET plik kopiowany jest do katalogu bin, aby zapobiec przypadkowemu jego włączeniu do systemu kontroli wersji. Implementacja rozwiązania zajęała mi mniej niż godzine. Po tym czasie mogłem już się cieszyć odizolowanym środowiskiem zarówno do testów jednostkowych, jak i do normalnych moich deweloperskich zadań. Nie muszę dodawać, że ustawienia bazodanowe to tylko przykład. W ten sam sposób można spersonalizować dowolną sekcję konfiguracyjną. Póki co jest to dopiero prototyp. Docelowo chciałbym, aby rozwiązanie zostało wzbogacone o możliwość definiowania konfiguracji nie tylko per deweloper, ale także nazwanych, takich jak “staging” czy “production”. Byłoby to wspaniałe uzupełnienie naszego procesu Continous Integration.



