Wyrażenia lambda w praktyce - MethodWrappers

Kiedyś już wspominałem o fajnym wykorzystaniu wyrażeń lambda w poście Wyrażenia lambda i extension methods - aspektejszyn. Dzisiaj przytoczę kolejne przykłady takiego ich zastosowania, które potrafią znacząco ograniczyć ilość powtarzalnego kodu w kodzie (badaniem ilości cukru w cukrze zajął się kto inny).

Całość wrzuciłem sobie do statycznej klasy MethodWrappers, przyjrzyjmy się jej zawartości...

IgnoreExceptions()

Celem tej metody jest maksymalne skrócenie takiego potwora:

  1:  try
  2:  {
  3:  	CanThrow();
  4:  }
  5:  catch
  6:  {
  7:  }
  8:  try
  9:  {
 10:  	WillPossiblyThrowException();
 11:  }
 12:  catch
 13:  {
 14:  
 15:  }
 16:  try
 17:  {
 18:  	ShouldNotThrowButWhoKnows();
 19:  }
 20:  catch
 21:  {
 22:  
 23:  }

Chcemy, aby wykonały się WSZYSTKIE metody, niezależnie od wyrzucanych wyjątków, które zignorujemy. Tak, wiem, łykanie wszystkiego w try/catch jest praktyką NIEPOLECANĄ, jednak skądś takie brzydale znamy, prawda?

Pierwszy upraszczacz skraca kod do:

  1:  MethodWrappers.IgnoreExceptions(
  2:  	CanThrow,
  3:  	WillPossiblyThrowException,
  4:  	ShouldNotThrowButWhoKnows
  5:  	);

Prawda że ładniej? Oto kod podspodowy:

  1:  /// <summary>
  2:  /// Executes given operations catching all exceptions.
  3:  /// Exceptions thrown by the operations are ignored and do not bubble up to the caller.
  4:  /// Exceptions do not prevent other operations from being executed.
  5:  /// </summary>
  6:  public static void IgnoreExceptions(params Action[] operations)
  7:  {
  8:  	foreach (var operation in operations)
  9:  	{
 10:  		try
 11:  		{
 12:  			operation();
 13:  		}
 14:  		catch
 15:  		{
 16:  		}
 17:  	}
 18:  }

ExecuteTryCatch()

Druga z metod również tyczy się wyjątków. Ona z kolei ma skrócić taki kod:

  1:  try
  2:  {
  3:  	CanThrow();
  4:  }
  5:  catch
  6:  {
  7:  	Hilfe();
  8:  }
  9:  try
 10:  {
 11:  	WillPossiblyThrowException();
 12:  }
 13:  catch
 14:  {
 15:  	Rollback();
 16:  }
 17:  try
 18:  {
 19:  	ShouldNotThrowButWhoKnows();
 20:  }
 21:  catch
 22:  {
 23:  	Log();
 24:  }

W efekcie uzyskamy tylko 3 linijki - pozbywamy się ohydnej "rozwlekłości" nie tracąc jednocześnie czytelności! (z tą czytelnością pewnie nie wszyscy się zgodzą, ale... to kwestia przyzwyczajenia do lamd, zawsze można wstawić dodatkowy ENTER tu czy tam):

  1:  MethodWrappers.ExecuteTryCatch(CanThrow, Hilfe);
  2:  MethodWrappers.ExecuteTryCatch(WillPossiblyThrowException, Rollback);
  3:  MethodWrappers.ExecuteTryCatch(ShouldNotThrowButWhoKnows, Log);

Kod ową rozwlekłość w sobie bohatersko zatrzymujący:

  1:  /// <summary>
  2:  /// Executes the <paramref name="tryOperation"/> and performs the <paramref name="catchOperation"/> in case of exception.
  3:  /// </summary>
  4:  /// <param name="tryOperation">Operation to be executed.</param>
  5:  /// <param name="catchOperation">Operation to be executed in case of exception.</param>
  6:  public static void ExecuteTryCatch(Action tryOperation, Action catchOperation)
  7:  {
  8:  	try
  9:  	{
 10:  		tryOperation();
 11:  	}
 12:  
 13:  	catch
 14:  	{
 15:  		catchOperation();
 16:  	}
 17:  }

AggregateResults()

Kolejny kodoskracacz służy już do czegoś z wyjątkami niezwiązanego. Bardziej nawet kładę w nim nacisk na czytelność kodu niż na jego ilość. Zobaczmy PRZED:

  1:  List<int> positiveResults = new List<int>();
  2:  int temp = FirstOperationReturningInt();
  3:  if (temp >= 0)
  4:  	positiveResults.Add(temp);
  5:  temp = Sum(1, 2);
  6:  if (temp >= 0)
  7:  	positiveResults.Add(temp);

Cóż nas zatem interesuje? Chcemy mieć wyniki działania wszystkich metod zebrane w jednej kolekcji. ALE! Wyniki ujemne odrzucamy. Zbyt wiele razy miałem do czynienia z wyżej pokazanym kodem, czy nie ładniej tak?:

  1:  List<int> positiveResults = MethodWrappers.AggregateResults(
  2:  	number => number >= 0,
  3:  	FirstOperationReturningInt,
  4:  	() => Sum(1, 2)
  5:  	);

Najpierw definiujemy warunek, czyli JAKIE wartości mają być zapamiętywane, a potem listujemy operacje do wykonania. Nie wiem jak wam, ale mi się podoba. Kod:

  1:  /// <summary>
  2:  /// Executes each operation and creates an array of their results if.
  3:  /// Only results that satisfy a given condition are aggregated.
  4:  /// </summary>
  5:  /// <typeparam name="T">Type of a value returned by each of the actions.</typeparam>
  6:  /// <param name="condition">Condition that must be satisfied for the result to be aggregated.</param>
  7:  /// <param name="operations">Array of aggregated results of the operations.</param>
  8:  public static List<T> AggregateResults<T>(Predicate<T> condition, params Func<T>[] operations)
  9:  {
 10:  	List<T> results = new List<T>(operations.Length);
 11:  
 12:  	foreach (var operation in operations)
 13:  	{
 14:  		T result = operation();
 15:  		if (condition == null || condition(result))
 16:  			results.Add(result);
 17:  	}
 18:  
 19:  	return results;
 20:  }

Przytoczona lista nie jest imponująco długa, nie o to jednak chodzi. Chodzi o ideę, o eksperymentowanie, o estetykę... Niechaj nasz kod nie powoduje chęci odwiedzin u porcelanowego bożka!
Mam nadzieję, że w komentarzach zobaczymy więcej przykładów. Mam również nadzieję, że moja krucjata o nauczenie się C# 3.0 przez tych, którzy się go boją, przynosi efekty!

opublikowano 12 listopada 08 06:35 przez Procent | 2 komentarzy   
Zarejestrowano w kategorii: ,
Zawód - programista. Nadzieje.

Kilka miesięcy temu napisałem posta o jakże wdzięcznym tytule "Jak zostać programistą". Efekt tej minipublikacji przeszedł moje najśmielsze oczekiwania - liczba jej odwiedzin, mnogość komentarzy pod wpisem oraz prywatnych maili dotyczących poruszonej tematyki utrzymuje się do dziś na ponadprzeciętnym jak dla mnie poziomie. Wejścia na mojego bloga z Google po wpisaniu frazy "chcę zostać programistą" lub "zawód programisty" biją na głowę te wszystkie świetne wypociny:) o C#, VS czy .NET. Na forum CodeGuru raz po raz także ktoś rozpoczyna podobny wątek.
W obliczu tak wielkiego zainteresowania postanowiłem zostawić na chwilę kwestie techniczne i rozwinąć trochę ów temat. Zagłębić się dalej w... "zawód programisty".
Dzisiaj napiszę o nadziejach. Jak postrzegałem ten zawód wybierając go? Na co liczyłem zarywając noce przez ostatnie kilka lat? Nieustannie szukając swojego miejsca i chłonąc nową wiedzę? Mieszając życie prywatne z zawodowym tak, że teraz nie da się już ich rozerwać? Czego oczekiwałem od codziennej PRACY czyniąc z niej swoje hobby, swoją pasję i swój największy nałóg?


Rozwój

Od samego początku przygody z programowaniem wiedziałem, że za tymi bełkotliwymi dla zwykłego człowieka milionami linii instrukcji kryje się coś więcej. Coś więcej niż przeciętne rzemiosło, polegające na nieustannym bezmyślnym klepaniu tego samego przez X godzin dziennie "aż w końcu zacznie działać".
W przypadkach wyjątkowych można nawet pokusić się o określenie: SZTUKA. Do tego dążyłem i dążę cały czas. Upragnionego poziomu nigdy nie osiągnę, ale w tym przypadku od dotarcia do celu ważniejsza jest droga do niego.
Przez większość studiów czekałem na ich koniec, żeby nareszcie móc bez przeszkód robić to co chcę. Iść do pracy i rozwijać swoje hobby, czy to nie cudowne i godne pozazdroszczenia? Od pracy zawodowej oczekiwałem nieustannego, dynamicznego, pasjonującego poszerzania swojej wiedzy. Uczyć się od mistrzów, odkrywać jak wiele jeszcze nie wiem i nadrabiać te zaległości!

Kasa

Ileż to mówi się o zarobkach informatyków! Kończysz studia, całymi dniami robisz to co chcesz robić, i jeszcze za to płacą jak mało komu! Brzmi znajomo? Trąbią o tym w gazetach i internecie, szczególnie pod koniec każdego roku akademickiego. Po latach dziadowania wreszcie będę miał komputer taki jaki chcę, wreszcie kupię wymarzoną furę, wreszcie odwieczny problem "kino czy browar?" odejdzie w niepamięć! Tak sobie właśnie myślałem, to miała być prawdziwa wymierna nagroda.

Kariera

Hej, po co podczas studiów wychodzę daleeeeko poza standardowy program olewając to, co jest zbędne? No jak to, oczywiste - żeby pracę zacząć od poziomu wyższego niż pierwszy lepszy absolwent, który cały czas od matury do magistra spędził z bełtem w garści. Skończę uczelnię i wyląduję na stanowisku programisty z prawdziwymi obowiązkami, nie będę jednym z miliona pospolitych zbieraczy programistycznej bawełny, "przynieś-podaj-pozamiataj". Raz dwa, miesiąc po miesiącu, kwartał po kwartale, coraz ambitniejsze zadania i coraz ciekawsze wyzwania. Przecież mam tyle do zaoferowania! Czyż nie o to w tym chodzi? Żeby nie popaść w rutynę, żeby się, o zgrozo, nie nudzić! (czy w ogóle można się nudzić będąc programistą?)

Społeczności

Nic mi nie wiadomo o potajemnych spotkaniach prawników czy lekarzy, którzy po godzinach schodzą się w celu wymiany doświadczeń i wzajemnego dokształcania. Wiadomo mi natomiast o takich spotkaniach w środowiskach informatycznych. Czy to specyfika naszego zawodu, że jest on hobby dla którego jest się gotowym po całym dniu pracy siedzieć kolejne 3-4 godziny wśród podobnych sobie zapaleńców? Wszystko dla nowej wiedzy. Nieważne czy w aktualnym projekcie jest to potrzebne, nieważne czy są w ogóle rzeczywiste perspektywy na wykorzystanie omawianych narzędzi. Ważne, żeby wiedzieć co w trawie piszczy!
Kolejna zatem nadzieja: "po studiach to dopiero się pokażę!" Przed prawdziwym rasowym programistą nie ma granic. Zdobyć tonę doświadczenia w pracy a następnie dzielić się nim na forum. Spotkać polskiego Ayende, polskiego Boodhoo, polskiego Hanselmana! Po studiach, w końcu na studentów "na pewno zawsze patrzy się z lekkim przymrużeniem oka"...

Pasja

Na koniec najważniejsze oczekiwanie - na każdym kroku, niezależnie od miejsca pracy, niezależnie od firmy, spotykać pasjonatów, dla których pokonywanie kolejnych barier jest esencją tego zawodu. Dyskusje o nowościach, wymiana doświadczeń, wyprawy na konferencje, być może nawet wspólna lektura blogów czy oglądanie DNRTV... czy to możliwe, że gdzieś tego nie ma? Czy nie po to buduje się zespoły? Przecież na pewno programista wstaje rano pełen energii, pewien, że dzisiaj będzie bardziej interesujące niż wczoraj i mniej interesujące niż jutro. Piękne?


Uff... Temat to bardzo dla mnie trudny. Dwa dni zabrało mi spisanie tego tak, aby móc to umieścić gdzieś poza własną głową. Podkreślam jeszcze raz, że zawarłem tu pewną część swoich myśli sprzed kilkunastu miesięcy, i wcześniej, identyfikując się z "tymi na rozdrożu". Kiedyś prawdopodobnie postaram się skonfrontować to z rzeczywistością. Kiedyś. Do tej pory jakiekolwiek dywagacje "co jest a co nie jest jak powinno" są bez sensu.

A Wy, jak widzicie ten zawód? Jak go sobie wyobrażacie lub czym on jest dla Was? Który z wymienionych przeze mnie punktów jest naiwny, niepotrzebny, a czego zapomniałem tu dodać? Liczę na feedback, który pozwoli wszystkim dowiedzieć się więcej o znaczeniu słowa "programista". A może nawet szerzej - "informatyk"?

Na koniec krótki przekaz do licealistów/studentów szukających motywacji do dalszej pracy nad sobą: Przeczytajcie jeszcze raz to co spisałem. Porównajcie z własną odpowiedzią na pytanie "po co robię to co robię?" (ale ze mnie kiepski raper). Jeżeli choć częściowo pokrywa się z moją to... do roboty! To JEST możliwe. Nikt nie da na to gwarancji (a już na pewno nie ja ;) ). Nie każdemu uda się osiągnąć taki trwający całe życie programistyczny orgazm. Ale może akurat TY będziesz takim szczęśliwcem? Bez pracy nie ma kołaczy, a jedynie mega-zmuła. Niechaj to będzie dla Was inspiracją.

opublikowano 06 listopada 08 12:53 przez Procent | 17 komentarzy   
Zarejestrowano w kategorii:
QueryStringValue w Web Client Software Factory

Web Client Software Factory udostępnia bardzo ciekawy i przydatny mechanizm komunikacji ze stanem przechowywanym w sesji. W poniższym przykładzie podczas tworzenia obiektu do pola zostanie wstrzyknięta odpowiednia wartość pobrana z sesji:

  1:  public class MyClass
  2:  {
  3:  	[SessionStateKey("MyNumber")]
  4:  	public StateValue<int> MyNumber;

Do wartości tej dostać się można następująco:

  1:  int number = MyNumber.Value;

Wszystko za sprawą Object Buildera. Jakie korzyści płyną z zastosowania takiego rozwiązania? Oprócz ustandaryzowanego i prostego sposobu wykorzystania sesji najważniejsza jest możliwość przeprowadzenia testów jednostkowych na obiektach polegających na wartościach pobieranych z sesji.

Ale ja nie do końca o tym chciałem... Kilka tygodni temu Kuba Binkowski w swoim wystąpieniu na wg.net pokazał podobne rozwiązanie w Unity, tyle że pobierające wartość z URL. No i właśnie coś takiego dodamy za chwilę do WCSF.


Cały proces rozpoczyna się od odpalenia Reflectora i analizy szczegółów implementacyjnych StateValue, ponieważ funkcjonalność będzie praktycznie ta sama. A potem - sam miód, czyli implementacja. Zatem po kolei, do dzieła!

1. Pierwszy krok to utworzenie interfejsu analogicznego do IStateValue. Interfejs ten zdefiniuje nam kontrakt komunikacyjny pomiędzy naszym systemem a URLem i będzie prawie taki sam jak wspomniane IStateValue. Jedyna różnica to typ zwracany przez właściwość Value. W naszym przypadku będzie to string, ponieważ to właśnie możemy z URLa wyciągnąć. Dodatkowo należy zwrócić uwagę na właściwość Request - nie wołamy bezpośrednio HttpContext.Current.Request. Zamiast tego uzupełnimy tą wartość później, korzystając z innych mechanizmów dostępnych w WCSF.

  1:  public interface IQueryStringValue
  2:  {
  3:  	string KeyName { get; set; }
  4:  	string Value { get; }
  5:  	HttpRequest Request { get; set; }
  6:  }

2. Następnie wypada interfejs ów zaimplementować. Tworzona klasa będzie wykorzystywać typ ogólny, dzięki czemu uzyskamy możliwość konwersji z ciągu znaków do liczby czy daty bez ingerencji końcowego programisty.

  1:  public class QueryStringValue<T> : IQueryStringValue
  2:  {
  3:  	public string KeyName { get; set; }
  4:  
  5:  	public HttpRequest Request { get; set; }
  6:  
  7:  	string IQueryStringValue.Value
  8:  	{
  9:  		get { return Request.QueryString[KeyName]; }
 10:  	}
 11:  
 12:  	public T Value
 13:  	{
 14:  		get
 15:  		{
 16:  			var v = ((IQueryStringValue)this).Value;
 17:  
 18:  			if (string.IsNullOrEmpty(v))
 19:  				return default(T);
 20:  
 21:  			return (T)Convert.ChangeType(v, T);
 22:  		}
 23:  	}
 24:  }

3. Mamy już strukturę potrzebną do przechowywania danych pobranych z QueryStringa. Zauważmy jednak, że brakuje jeszcze odpowiednika atrybutu SessionStateKey będącego znakiem dla ObjectBuildera że w tym miejscu należy się zatrzymać i "coś zrobić". Implementacja takiego oznaczenia jest banalnie prosta, ponieważ tak naprawdę jedyne czego potrzebujemy to klucz pod którym należy szukać żądanej wartości:

  1:  [AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
  2:  public sealed class QueryStringKeyAttribute : Attribute
  3:  {
  4:  	public string QueryStringKey { get; private set; }
  5:  
  6:  	public QueryStringKeyAttribute(string queryStringKey)
  7:  	{
  8:  		QueryStringKey = queryStringKey;
  9:  	}
 10:  }

4. Zatrzymajmy się na chwilę i spójrzmy co już napisaliśmy. Cała instrastruktura konieczna do wykorzystania mechanizmu jest gotowa. W akcji będzie to wyglądać tak:

  1:  	[QueryStringkey("MyNumber")]
  2:  	private QueryStringValue<int> SomeNumber;

...przy czym obsługiwany URL to http://www.xxx.com/yyy.aspx?MyNumber=666.
Ale to oczywiście nie koniec. Nigdzie jeszcze fizycznie nie dobieramy się do adresu, nigdzie nie wciskamy się w proces tworzenia obiektu przez ObjectBuilder! Kroczmy zatem dalej ścieżką prawych i sprawiedliwych. Jesteśmy blisko!

5. Teraz czeka nas najtrudniejsze zadanie - musimy napisać własną strategię ObjectBuildera, która powypełnia wszystkie pola oznaczone tym ślicznym atrybutem. Bez kilkukrotnego zerknięcia do Reflectora na implementację SessionStateBindingStrategy się nie obejdzie, ale w końcu po coś to narzędzie mamy, prawda? Tak więc wykonujemy wszystkie konieczne czynności, które ot tak wymienię jedna po drugiej:

  • za pomocą WCSFowego pojemnika IoC uzyskujemy instancję usługi, która dostarczy nam aktualny kontekst HTTP (a więc i obiekt HttpRequest)
  • przejeżdżamy się po wszystkich polach tworzonego obiektu pomijając te mające inny typ niż implementację naszego interfejsu IQueryStringValue
  • z deklaracji w/w pól pobieramy instancję atrybutu QueryStringKey zawierającą klucz wskazujący na żądaną wartość w URLu (poniższa implementacja wyrzuci wyjątek, gdy pole takiego typu nie zostanie oznaczone takim atrybutem)
  • wstawiamy w owo pole nowa instancję pożądanego typu, wypełniając jego właściwości przechowujące Key oraz Request

W tym momencie mamy już pole, którego właściwość Value zwróci nam to czego oczekujemy!

  1:  public class QueryStringBindingStrategy : BuilderStrategy
  2:  {
  3:  	public override object BuildUp(IBuilderContext context, System.Type typeToBuild, object existing, string idToBuild)
  4:  	{
  5:  		IHttpContextLocatorService service = context.Locator.Get<IHttpContextLocatorService>(new DependencyResolutionLocatorKey(typeof(IHttpContextLocatorService), null));
  6:  
  7:  		if (service != null)
  8:  		{
  9:  			var httpContext = service.GetCurrentContext();
 10:  			foreach (var field in typeToBuild.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
 11:  			{
 12:  				if (typeof(IQueryStringValue).IsAssignableFrom(field.FieldType) == false)
 13:  					continue;
 14:  
 15:  				IQueryStringValue queryStringValue = (IQueryStringValue)Activator.CreateInstance(field.FieldType);
 16:  				QueryStringKeyAttribute attribute = (QueryStringKeyAttribute)field.GetCustomAttributes(typeof(QueryStringKeyAttribute), false)[0];
 17:  
 18:  				queryStringValue.KeyName = attribute.QueryStringKey;
 19:  				queryStringValue.Request = httpContext.Request;
 20:  				field.SetValue(existing, queryStringValue);
 21:  			}
 22:  		}
 23:  
 24:  		return base.BuildUp(context, typeToBuild, existing, idToBuild);
 25:  	}
 26:  }

Jeszcze jedna mała uwaga: powyższa implementacja pozwala na potraktowanie w ten sposób WSZYSTKICH, także prywatnych, pól. Dostępny w WCSF mechanizm można zastosować jedynie do pól publicznych. Powód? Linijka numer 10. Tutaj jawnie żądamy dostępu do pól publicznych i niepublicznych, podczas gdy implementacja strategii StateValue wykorzystuje bezparametryczną wersję metody GetFields() zwracającą jedynie publiczne pola.

6. Został ostatni kroczek. Musimy powiedzieć ObjectBuilderowi że mamy o taki cudny mechanizm, który chcielibyśmy w proces tworzenia obiektów wprząc. Reflector w kilka chwil pokazuje nam w którą stronę gęby nasze należy zwrócić i co uczynić, aby było to możliwe. Rozwiązaniem jest własna klasa dziedzicząca z WebClientApplication nadpisująca jedną metodę:

  1:  public class CustomWebApplication : WebClientApplication
  2:  {
  3:  	protected override void AddBuilderStrategies(Microsoft.Practices.ObjectBuilder.IBuilder<WCSFBuilderStage> builder)
  4:  	{
  5:  		base.AddBuilderStrategies(builder);
  6:  
  7:  		builder.Strategies.AddNew<QueryStringBindingStrategy>(WCSFBuilderStage.Initialization);
  8:  	}
  9:  }

A co dalej z tą klasą zrobić - było ostatnio.


That's all folks!
Żeby nie było tak słodko dodam, że całą tą pracę wykonałem właściwie na marne. Po napisaniu owego rozwiązania wpisałem z ciekawości w Google "WCSF QueryStringValue" i... co się okazało? Istnieje sobie projekcik WCSF Contrib i tam dokładnie takie samo rozwiązanie siedzi już od jakiegoś czasu. No ale, co się człowiek nauczy to jego.

Jest też jeszcze jedna sprawa. W WCSF możemy wykorzystywać sesję (jak to brzmi...) również w inny sposób. Istnieje sobie atrybut StateDependency, dzięki któremu możemy podobne sztuczki robić z parametrami metod! To jednak dużo wyższa szkoła jazdy - bez zagłębienia się po uszy w kod źródłowy WCSF i jego modyfikacji się nie obejdzie. Zatem odpowiednik, czyli QueryStringDependency (którego już w WCSF Contrib nie uświadczymy, co jest absolutnie zrozumiałe jeśli się poprzednie zdanie jeszcze raz przeczyta), stworzymy sobie może innym razem.

opublikowano 20 października 08 07:36 przez Procent | 0 komentarzy   
Zarejestrowano w kategorii: , , , ,
Relacja z MTS 2008

W dniach 8-9 października w Pałacu Kultury i Nauki w Warszawie odbyła się wielka konferencja Microsoft Technology Summit 2008. Byłem. Widziałem. I, jak z większości wydarzeń w których uczestniczę, uwagi swe niniejszym przekazuję światu.


Bloggers Underground

W wigilię MTS Aneta Sidorowicz, Karol Stilger i Łukasz Foks zorganizowali mały starter - spotkanie polskich bloggerów. Idea zaiste godna podziwu. Zainteresowanie i frekwencja - większa niż się spodziewałem! W kameralnej piwniczce lokalu Leżaki można było spotkać kilkadziesiąt osób prowadzących bądź zamierzających prowadzić bloga, pogadać przy piwku, posłuchać kilku wystąpień na przeróżne tematy. Super! Sam miałem wygłosić małe "przemówionko" na temat sensu prowadzenia bloga w moim rozumieniu, jednak (chyba na szczęście:) ) w ostatniej chwili się wycofałem. Wieczór jak najbardziej udany, brawo!


MTS 2008 - Organizacja

O tym tylko kilka słów, bo moim zdaniem kwestie organizacyjne nie mają specjalnie znaczenia. Tłok, ścisk, kolejki po colę/kawę, smaczne kanapki, niesmaczny obiad, dłuuugie dystanse do pokonania między poszczególnymi sesjami. I to tyle, bez wnikania. W końcu nie zjawiliśmy się tam żeby się najeść i odpocząć, tylko wysłuchać sesji i spotkać się z ludźmi, więc na utrudnienia takiej natury uwagi nie zwracam i nie narzekam. Aha, jednego mi brakowało: w plecaku wśród reklam dało się znaleźć długopis, ale zabrakło notatnika! Dwie małe stroniczki w przewodniku to zdecydowanie za mało jak na notatki z ośmiu sesji.

0. Sesja generalna

Powitanie podzielono na kilka części. Najpierw standardowa gadka jak to miło nas widzieć i jacy jesteśmy wspaniali. Następnie kilka(set) słów od najważniejszych sponsorów, czyli Intela i Della. No właśnie... Zdaję sobie sprawę, że zapewne "biznes" tego wymaga, że w jakiś sposób trzeba owych złotych sponsorów wyróżnić, ale czy aby na pewno przydługie "rozmowy w toku" w wykonaniu dyrektorów i słodzenie sobie nawzajem jest najlepszym sposobem na rozpoczęcie konferencji? Prześciganie się w rankingu "która korporacja posadziła w tym roku więcej drzew" może co najwyżej rozbawić:). Na szczęście drętwe tokszoł nie trwało zbyt długo i na scenie pojawił się Mariusz Jarzębowski z opowieścią o "Historii wstążki". Sam pomysł postawienia Ribbona w roli głównego bohatera wystąpienia może wydawać się... dziwny? Ha! Temat nie był mi jednak obcy, ponieważ niesamowicie pozytywne opinie o tej prezentacji czytałem już wcześniej w relacjach ze zlotu portalu dobreprogramy.pl. Opowiadał mi także o niej, również w samych superlatywach, "tajemniczy ktoś" oglądający ją wcześniej w innych okolicznościach. No i cóż mogę powiedzieć - oni wszyscy mieli rację! Prowadzone w luźnej atmosferze wystąpienie nie zawierało może wielkich wartości technicznych, ale z otwartymi ustami słuchało się doskonałego prelegenta opowiadającego o tym, jak to w 2003 roku Microsoft przejrzał na oczy i doszedł do wniosku że dotychczasowe menu SUX:). Rewelacja! Jeśli jest to część szerzej zakrojonej akcji zmiany wizerunku MS (a w świetle ostatnich reklamówek z Billem, i nie tylko, można tak domniemywać) to z mojej strony oklaski na stojąco. Jest to zdecydowanie dobra droga!

1. "Wydajne aplikacje ASP.NET w świecie Web 2.0" Tymoteusz Chmielewski

Jednak co tam jakaś wstążka, skoro już pierwsza prawdziwa sesja zapowiada się niesamowicie interesująco! Wydajność ASP.NET, poziom sesji 400 (czyli w moim rozumieniu: dla masta-wymiataczy). Jakby tego było mało - miałem w pamięci sesję panów z K2 sprzed roku, kiedy to na DevDays 2007 bardzo zgrabnie i ciekawie opowiadali o podstawach zabezpieczania aplikacji webowych.
Jak można wywnioskować - dwaj panowie (tylko jeden z nich jest wymieniony na stronie i slajdach, nazwiska drugiego niestety nie uchwyciłem) mieli przed sobą postawione nie lada wymagania. No i się zaczęło. Najpierw krótkie wprowadzenie definiujące pojęcie Web 2.0 (na poziomie 400?), potem "co to jest CSS/XHTML, REST, RIA i web services" (na poziomie 400?). Krótka wymiana spojrzeń z sąsiadami i wszystko jasne - nie tylko ja jestem zaskoczony. No ale nic, to dopiero rozgrzewka... Panowie, pokażcie coś interesującego! Nadszedł czas na pierwsze demo... Dwa (pewnie nie w 100% wierne) cytaty:

  • "teraz przeciągnę na stronę ScriptManager - to takie coś dzięki czemu na naszej stronie będzie działał AJAX, nie będę wchodził w szczegóły"
  • "ta dziwna składnia którą Państwo widzą to LINQ, ale o tym nie będziemy dziś mówić, muszą nam Państwo uwierzyć że to działa"

Czy trzeba pisać coś więcej? Chyba nie.
Ale napiszę. Dalsza część niestety nie była lepsza. Teksty wszystkowiedzącym tonem w stylu "nie będziemy się pastwić nad pewnym portalem społecznościowym którego serwery nie wytrzymały" na tle prezentacji na TAKIM poziomie naprawdę nie były na miejscu. Omawianie PRODUKTU Community Server na sesji mającej pokazać jak TWORZYĆ wydajne aplikacje też nie jest doskonałym pomysłem. Ale jeśli nawet taka była koncepcja, to co oznacza sformułowanie "CS ma blogi, fora, wiki, ale pomimo swojego rozbudowania nie ma CMSa - dodaliśmy do niego możliwość edycji artykułów"? Zine stoi na Community Server sprzed kilku lat, a nie zauważyłem tam braku możliwości edycji czegokolwiek. Chyba że coś mi się kompletnie pomieszało - tylko co?
To jednak nie wszystko... Nie chce mi już się nawet opisywać wynoszenia pod niebiosa Linq To Sql jako najnajnajkochańszego O/R Mappera (z pominięciem faktu, że nie jest to O/R Mapper "z prawdziwego zdarzenia" i że to Linq To Entities ma konkurować z takim na przykład NHibernate) czy masakrycznie tendencyjnych testów wydajności Linq To Sql vs DataSet vs DataReader podczas wyświetlania stronicowanych danych. Zamiast tego podzielę się innym faktem, który wcisnął mnie w fotel i jest głównym powodem tak emocjonalnej reakcji na wszystko co nam przedstawiono. Fakt ten to: "ASP.NET AJAX pozwala nam bardzo odciążyć serwer i zwiększyć jego wydajność, ponieważ po wrzuceniu strony w Update Panel nie musi on się zajmować całym cyklem życia strony". Wiedzieliście o tym? To chyba najbardziej nagłośniony MIT o UpdatePanel i uwagę na to zwraca się na każdym kroku - UpdatePanel nie powoduje zmian w cyklu życia strony! Bez jaj, takie kwiatki na takiej konferencji zdarzać się po prostu NIE POWINNY. Przecież ludzie zapłacili żeby tu wejść! W tym momencie wszystkie zmanierowane wypowiedzi utraciły jak dla mnie resztki "profesjonalizmu" i stały się jedynie czczymi wyssanymi z palca niby-faktami powstałymi w procesie "jestem przekonany, że....".
No dobra, dosyć, wykorzystując cytowany fragment: przestaję się pastwić. Dotrwałem do końca i żyję, ciekawe jednak w ilu środowiskach produkcyjnych taka "wiedza" znajdzie zastosowanie. A no bo przecież "na konferencji panowie mówili że tak jest lepiej"...

Ocena: 2 (nie 1, bo przykład SSO pomiędzy własną stroną a CS był całkiem fajny).

2. "Praktyczne aspekty budowania rozwiazań klasy Enterprise z wykorzystaniem produktów Microsoft Patterns and Practices" Marcin Sieradzki

Po tak katastrofalnym falstarcie apetyt jeszcze bardziej się zwiększył. Ponownie poziom 400, a do tego połączenie słów "praktyczne" i "Patterns and Practices" w temacie! Przyznać muszę, że dokumentację EntLib przeczytałem całą, bawiłem się też przykładami, próbowałem sam "co nieco" na własnych mini-poligonach, wszelakich webcastów naoglądałem się również co niemiara. Teorią o Entlibie wyładowany więc jestem po brzegi. A praktyka... No właśnie, łapanie wyjątków i logowanie to sobie można poćwiczyć w domu, ale jak naprawdę sprawuje się cała reszta w warunkach bojowych? Tego chciałem się dowiedzieć - na jakie miny uważać?
Sesja rozpoczęła się pozytywnie - tu żarcik, tam dowcip, w międzyczasie pobieżne omówienie architektury EntLiba. Prelegent zaznaczył, że nie jest zawodowym zwierzęciem scenicznym. Było widać pewien brak swobody, ale w niczym to nie przeszkadzało. Jak więc potoczyły się dalsze losy naszego spotkania?
Tutaj musiałem na chwilę zrobić przerwę i się głęboko zastanowić. Bo czego tak naprawdę dowiedziałem się podczas tych 75 minut? Chyba tylko tego co następuje: jest sobie w Sygnity jakaś firma która tworzy program Documan; na jednym ze slajdów mogłem zobaczyć (tzn mógłbym gdyby ekran był 10x większy) diagram klas części owego systemu; na sali siedział Piotrek który projektował raporty (WTF???); w systemie wykorzystano EntLib. Naprawdę mimo najszczerszych chęci nie przypominam sobie żadnych wartościowych wskazówek dotyczących PRAKTYCZNEGO wykorzystania tych bibliotek, wykraczających poza najprostsze demo. Pewnie dlatego, że w połowie agendy skończył się czas... Owszem, rady dotyczące książek i innych ładnie skatalogowanych źródeł wiedzy niosą za sobą sporą wartość. Ale w temacie było napisane wyraźnie: PRAKTYCZNE. Praktyki nie doświadczyliśmy. A wielka szkoda, bo właśnie skończyłem czytać ściągniętą ze stron MTS prezentację i mogło być bardzo udanie... Ale z drugiej strony - można było to przewidzieć, skoro prezentacja ma 98 (sic!) POTĘŻNYCH slajdów na 75 minut.

Ocena: 4 (bo się naprawdę nieźle zapowiadało...).

3. ".NET bez wizardów – sposoby tworzenia i dynamicznego aktywowania komponentów w aplikacjach" Bartosz Pampuch

Pół dnia minęło i co? I - za przeproszeniem - jajco. Porządnie sfrustrowany skierowałem się do kolejnej sali. Szedłem jednak spokojny, wiedziałem że będzie zajebiście. Na prezentacjach Bartka zawsze jest zajebiście. Jego energia, pasja i NIEWYOBRAŻALNE wręcz przygotowanie do sesji zwalają z nóg. Zanim przejdę dalej napiszę tylko w skrócie: jak było? oczywiście-zajebiście:)
Ciężko w jednym zdaniu zmieścić cały zakres omawianej prelekcji. Tytuł ".NET bez wizardów" jest troszkę mylący. Nie było tam recepty "jak napisać program bez wizarda". Przejechaliśmy się za to po bardzo wielu różnych materiach - od teorii tworzenia oprogramowania (zasady takie jak Separation of concerns czy Don't repeat yourself) przez Dependency Injection aż po programowanie aspektowe. Zajrzeliśmy do wszystkich liczących się pojemników IoC (m.in. Castle, Unity, Ninject, Spring.NET). Dowiedzieliśmy się jakie są miedzy nimi różnice, co każdy z nich oferuje unikalnego, jak z ich wydajnością. AOP także zaprezentowano nam profesjonalnie - zobaczyliśmy dema możliwości gołego .NETa w tym zakresie (Context Bound Object) oraz PostSharpa. Wielka szkoda że póki co prezentacja nie jest dostępna do ściągnięcia, mam nadzieję że w jakiejś postaci pojawi się na stronce. Dlaczego tak enigmatycznie - "w jakiejś postaci", a nie jak wszystkie inne w pptx?
Tutaj muszę się na chwilę zatrzymać i zejść z tematu "merytorycznego". Postaram się opisać PROWADZENIE sesji. Takiej żywiołowości, takiego zaangażowania nie widziałem nigdzie indziej podczas całego MTS. Większa część prezentacji to filmiki z kodem, a Bartek stojąc tyłem do ekranu opowiadał co się tam właśnie dzieje. Synchronizacja IDEALNA - można by pomyśleć że to leci nagrany wcześniej lektor. Mało tego! Na sali znajdowały się dwa ekrany - jeden wielki i jeden mniejszy. W co prezenter zamienił ten mniejszy (2metrowy?) ekran? Uwaga - w mega-wielkiego IPHONA:). Slajdy pojawiały się jak na wyświetlaczu, po 9 za każdym razem. Kamerka zamontowana nad ekranem śledziła ruchy specjalnego mazaka, którego prelegent używał do dotykowego sterowania prezentacją. Ba, w jednym momencie nawet RYSOWAŁ na panelu wyświetlanym z rzutnika! Coś prawdziwie niesamowitego.
Nie mogę powiedzieć, że dużo nowej wiedzy wyniosłem z tej sesji (w końcu nie tak dawno na ZineDay mieliśmy dwie bardzo fajne sesje o AOP). Myślę jednak, że poruszane tematy wciąż są w wielu organizacjach pomijane i ich promocja jest jak najbardziej potrzebna. Szczególnie w TAKI sposób - oglądało się to po prostu przednio. Nie ma sensu się dalej rozpisywać, to po prostu trzeba było zobaczyć.

Ocena: 9 (za... wszystko?).

4. "Wybrane koncepcje architektoniczne - jak organizować rozbudowane systemy Informatyczne (oraz jak ich NIE organizować)" Tomasz Kopacz

Co tu dużo gadać, Tomek Kopacz bezpośrednio po Bartku Pampuchu to jak papieros po obiedzie - czego chcieć wiecej?:) O poziom obawiać się nie trzeba, jedyne zmartwienie to czy zmęczony całym dniem umysł pomieści to morze informacji czekające w sali kongresowej?
Zaczęło się od teoretyzowania, które trwało przez większość sesji. Czy to źle? Nie - nie samym kodem żyje dev.
Na początku otrzymaliśmy odpowiedzi na wprowadzające pytania: Kim jest architekt? Po co jest architekt? Jaki jest architekt? Szczerze mówiąc - wyglądało mi to na "pożyczenie" sobie artykułu z jednego z ostatnich "Architecture Journal". Ale mimo przedstawiania tej samej treści - było interesujące.
Pozostałe 80% prezentacji to SOA w każdej postaci - czym JEST Service Oriented Architecture? A czym NIE JEST Service Oriented Architecture? Co zrobić, aby aplikacja stała się "zorientowana na serwisy", a kiedy nie ma to sensu? Zobaczyliśmy też wiążące się z tym niebezpieczeństwa i czyhające pułapki, otrzymaliśmy kilka porad dotyczących decyzji podejmowanych na różnych etapach projektowania usług.
Po zajmujących rozważaniach przyszedł czas na prezentację tego, czego nie może zabraknąć gdy gdziekolwiek pojawia się słowo "komunikacja", czyli WCF. Jeden sekundowy slajd pokazujący co to jest, a potem już sam miód. Zobaczyliśmy największe zalety WCF, najczęściej stosowane bindingi, nie ominęło nas też wiele innych ciekawostek. Najbardziej zapadła mi w pamięć możliwość odpalenia serwera i klienta WCF w jednym procesie, co daje nam swoiste profilowanie aplikacji i badanie liczby wywołań oraz czasu trwania metod. Praktycznie zerowym nakładem pracy! Po tym przykładzie prelegent dalej sypał z rękawa nieocenionymi poradami. Między innymi (darmowe) narzędzie MSE - ja osobiście nie wiedziałem, że jest takie coś i nie wątpię, że kiedyś mi się przyda.
Bardzo polecam ściągnięcie sobie tej prezentacji z internetu i zgłębianie zawartych tam słów kluczowych we własnym zakresie.
Jak widać - dzień pierwszy zakończył się o niebo lepiej niż się rozpoczął.

Ocena: 8.


5. "Bezpieczeństwo serwisów WWW – praktyczne uwagi o implementacji zaleceń DBTI ABW w ASP.NET" Zbigniew Łapiński

Początek dnia drugiego to dość mocno wyczekiwana prelekcja o bezpieczeństwie. Kto bowiem powie na ten temat więcej, niż megaboss z Agencji Bezpieczeństwa Wewnętrznego? Hmm...
Nie za wiele mogę napisać o tym wystąpieniu. Ja widzę je jak skondensowany semestr ze studiów traktujący o zagrożeniach czyhających na projekt informatyczny. Z ASP.NET niewiele to miało wspólnego. Bardziej - powtórka z zarządzania ryzykiem, podziałem zagrożeń... Nie do końca po to tam przyszliśmy. To, że hasła zapisywane na kartkach przyklejanych do monitorów są fe wiemy od dawna.
Mimo wszystko można było tego posłuchać i usystematyzować posiadaną wiedzę bądź posiąść trochę nowej.

Ocena: 5 (gdyby temat sesji był inny, ocena byłaby wyższa, ale wtedy pewnie bym tam nie poszedł...).

6. Organizacja dostępu do danych w aplikacjach WWW" Tomasz Kopacz

Odwiedzanie tego samego prelegenta dwukrotnie podczas jednej konferencji może wydawać się dziwne. Z drugiej strony - po co ryzykować wpadkę, skoro można pójść na pewniaka? Czasy bukmacherskiego uzależnienia mam już za sobą, więc zdecydowałem jak zdecydowałem.
Baaardzo ciężko byłoby choćby pobieżnie opisać wszystkie poruszone na tej sesji zagadnienia. A że pora już nie taka jak być powinna i liczba stron staje się powoli irracjonalnie ogromna, ograniczę się do wymienienia technologii które mogliśmy sobie powąchać: "czyste" ADO.NET (w tym MARS i asynchroniczne połączenia), LINQ (To Sql i To Entities), asynchroniczne strony ASP.NET (na dwa sposoby), WCF, ASMX, DataSety, AJAX, XML, JSON, Script Framework, RSS, ServiceBroker, HierarchyId (Sql Server 2008), FileStream (Sql Server 2008), Enterprise Library (DAAB, Caching, PIAB), Velocity, Astoria. Doprawdy - INSANE! To nie człowiek, to cyborg! TYLE zagadnień w niecałe półtorej godziny i KAŻDE w zrozumiały sposób wyjaśnione. Coś niesamowitego i szalonego. Można było dostać zawrotu głowy, ale - mimo wielkiej chęci przyczepienia się do czegokolwiek - nie da się narzekać że materiału było za dużo. Nic nie zostało bez wyjaśnienia. Oczywiście nie da się tak ogromnej liczby różnych technologii omówić w sposób bardzo wyczerpujący, ale nie takie było założenie sesji. Wyszliśmy z sali wiedząc co mamy do swojej dyspozycji, a nic nie powstrzymuje nas przed ściągnięciem prezentacji ze stron MTS i "osobistym" badaniom tego co oczom naszym ukazane zostało. Ba, czy ktokolwiek się temu oprze?
I jeszcze jedna krótka uwaga: wreszcie usłyszałem, jak ktoś głośno i wyraźnie mówi: do czego nadaje się Dataset w kontekście programowania WWW? Do NICZEGO!

Ocena: 9 (za prezentację, na którą ktokolwiek inny potrzebowałby całego dnia a i tak tylko by w głowach namieszał).

7. "Programowanie mobilne" Bartłomiej Zass

Tutaj wylądowałem niechcący - programowanie mobilne średnio mnie kręci i zapisany byłem na inną sesję. Poszedłem jednak za towarzystwem żeby zobaczyć co tak naprawdę można sobie wyczarować na coraz bardziej popularne urządzenia. Prowadzący na samym początku określił "target audience", i okazało się że jestem dokładnie tam gdzie być powinienem - wpasowałem się jak przysłowiowa dłoń w przysłowiową rękawiczkę.
Większość prezentacji oscylowała wokół koncepcji reagowania naszej aplikacji na przychodzące smsy. Można tak stworzyć program, aby URUCHAMIAŁ się na przyjście smsa o danej treści, WOW! Mało tego, można z zarządzanego kodu zadzwonić sobie gdzieś w odpowiedzi na takie zdarzenie! Cel prezentacji osiągnięty - wszyscy już wiemy jak bardzo CompactFramework poszło do przodu. Jednak nie tylko to! Postęp emulatorów urządzeń mobilnych także musi robić niezłe wrażenie. Emulatory potrafiące dzwonić? To nie czary, widziałem na własne oczy. Forma prezentacji była... ryzykowna. Bardzo interakcyjna i zabawna, ale ryzykowna. Za to ryzyko wielki plus dla Bartka, który po raz kolejny pokazał, że na scenie czuje się jak ryba w wodzie. Na czym to polegało? Można było wysłać smsa pod podany numer, a prezentowana na ekranie aplikacja odpowiednio na niego reagowała. Jednak gdy tekst wysłanej wiadomości nie odpowiadał założeniom programu, był po prostu wyświetlany. Różne przygody z tym związane kilkakrotnie wywoływały salwy śmiechu. Mogło się skończyć różnie, ale wyszło git:).

Ocena: 7 (tak dużo, bo sesja bardzo fajna, a tak mało, bo nie znoszę programowania mobilnego).

8. "Architektura i wykorzystanie usług oprogramowania w chmurze" Grzegorz Gogołowicz

Dosłownie kilka słów: usiadłem, zobaczyłem że pan z Redmond przyjechał zareklamować Sql Server i pobawić się w marketingowca czytającego slajdy, i po paru minutach wyszedłem. Potem dowiedziałem się że pojawiły się dema i generalnie było OK. Nie będąc na całości i słysząc umiarkowanie pozytywną opinię, sprzeczną z moją - wstrzymuję się od oceny i żałuję że nie dotrzymałem do końca. Stąd:

ocena: X (bo widziałem tylko pierwsze 15-20 minut).

Inne

Nie obyło się bez wymiany opinii z innymi uczestnikami i oto plusy/minusy innych sesji oczami moich rozmówców - w wielkim skrócie:

  • "Piękno C# - yield, generics, var i inne dziwne elementy składni C#" Bartłomiej Zass - zgodna z tematem zawartość prezentacji oraz bardzo profesjonalny sposób prowadzenia sesji i interakcji z publicznością, plus
  • "Metody i sposoby testowania oprogramowania" Piotr Ślężak - jak to ujął znajomy "wreszcie zobaczyłem jak się to powinno robić", co chyba można uznać za spełniony cel prezentacji:), plus
  • "Wybrane elementy innowacji w Microsoft i Microsoft Research" Mariusz Jarzębowski, Patryk Góralowski - podobno bardzo ciekawe nowe rozwiązania zaprezentowane w fajny sposób, plus
  • "Efektywne zarządzanie ryzykiem bez/z Team Foundation Server 2008" Tadeusz Golonka - nazwisko mówi samo za siebie, a do tego podobno sesja na zwykłym dla prelegenta, bardzo wysokim poziomie, plus
  • "Praktyka Silverlight" Tomasz Rakoczy - sesja na MTS kończąca się po 20 minutach? filmik z aplikacji działającej publicznie w necie i do domu? dzień dobry/play/stop/do widzenia? no bez jaj... MINUS
  • "Integrating Windows Presentation Foundation and Windows Communication Foundation into Your Office Business Applications" Tim Huckaby - po rekomendacji jaką usłyszałem z pewnością zapoznam się z prezentacja i z niecierpliwością czekam na webcast, plus
  • "Monitorowanie aktywności na SQL Server 2008" Paweł Potasiński, Marek Adamczuk - dla mnie czarna magia, ale znajomy był i powiedział że "chłopaki dali radę", plus

Speaker Idol

Dodatkiem do profesjonalnych sesji był konkurs Speaker Idol - "amatorzy" mogli wysłać swoje prezentacje i przekonać sędziów, że nadają się na prelegentów. Półfinał odbył się pierwszego dnia na korytarzu, słychać było niewiele, żarcie zdominowało tą przerwę. Wrażenia zatem co najwyżej średnie. Finał zamykał natomiast całą konferencję następnego dnia. Cztery najlepsze prace były prezentowane na Sali Kongresowej. Taki początek "prelegenckiej" kariery to jest coś! Poziom 5-minutowych wystąpień oceniam naprawdę wysoko, z pewnością _każde_ z nich było lepsze niż _któraś_ sesja "PRO". A że zwycięstwo i główna nagroda - zapewnione miejsce wśród przyszłorocznych prelegentów - trafiło (w pełni zasłużenie, a jak dla mnie II miejsce to Bartek Szafko) w rency mego ziomka JJałbrzykowskiego, tym lepiej. Gratuluję - za rok w relacji nie zostawię na tobie suchej nitki, więc BEWARE ;).

Podsumowanie

Wiem, że użyłem momentami dość mocnych i bezpośrednich słów, bez owijania w bawełnę. Mam spore doświadczenie w "byciu krytykowanym" i jak najrzadziej staram się krytykować innych. Ale... hola hola! MTS nie jest za darmo! To nie HHH czy C2C, gdzie jedyny koszt poniesiony przez uczestników to trochę swojego czasu. Przygotowanie prezentacji to jest kwestia odpowiedzialności WYŁĄCZNIE prelegenta, nie ma na kogo zwalić winy. Wybierając się tam w roli wykładowcy TRZEBA było sobie zdawać sprawę, że to jedyna konferencja w Polsce o takim rozmachu i renomie. I że - najzwyczajniej w świecie - trzeba wstydu nie mieć, żeby odwalić tam chałę, ponieważ wygórowane oczekiwania uczestników są jak najbardziej uzasadnione. Poza tym wszyscy prosili o oceny, więc oto one.

Jak zatem zapamiętam MTS w wydaniu 2008? Z jednej strony - na pewno pewien niedosyt pozostał. Nie chodzi o organizację samej imprezy, chociaż tu na pewno w przyszłym roku znajdzie się pole do poprawy. Może warto wprowadzić dokładniejszą analizę przygotowanych sesji? Weryfikować ich zgodność z deklarowanym tematem i poziomem ZANIM znajdą się na scenie? Z drugiej strony... Obejrzenie prezentacji wartych obejrzenia, spotkanie ludzi którch się na co dzień nie widuje, klimat wielkiej imprezy - tego nic nie zepsuje. Czy zatem warto było poświęcić dwa dni życia na wycieczki do PKiN? Zdecydowanie tak, choć mogło być lepiej.
Moja subiektywna i uzasadniona powyższymi wypocinami ocena całej konferencji: 7.

opublikowano 10 października 08 11:13 przez Procent | 25 komentarzy   
Zarejestrowano w kategorii: ,
Autoryzacja w Web Client Software Factory z wykorzystaniem wyrażeń regularnych

Korzystając z Web Client Software Factory mamy możliwość zdefiniowania reguł bezpieczeństwa, które kontrolują dostęp użytkowników do zasobów. Uzytkownik należy do ról, role mają (bądź nie) uprawnienia wykonywania reguł, natomiast reguły przypisane są do konkretnych adresów URL. Proste. Przykładowy wpis w web.config (z modułu Customers w Order Management Reference Implementation) wygląda tak:

<authorization>
  <rule Url="~/Customers/Default.aspx" Rule="AllowSearchCustomers" />
  <rule Url="~/Customers/SearchCustomers.aspx" Rule="AllowSearchCustomers" />
  <rule Url="~/Customers/CustomerAutoCompleteService.asmx/GetCustomersName" Rule="AllowAutocomplete" />
</authorization>

Co w przypadku, gdybyśmy chcieli jakikolwiek dostęp do wszystkich stron w module Customers ograniczyć do ról posiadających prawa do wykonania reguły "AllowUseCustomers"? Prawdopodobnie należałoby w podobny sposób wylistować wszystkie strony z owego modułu... Ohyda.

Na szczęście architekturę WCSF, podobnie jak wszystkiego ze stajni zespołu Patterns & Practices, przemyślano tak, aby można było właściwie w każde newralgiczne miejsce wprząc własną logikę. Zobaczmy zatem jak poradzić sobie z powyższym problemem. Efekt, który chcemy uzyskać, to plik konfiguracyjny posiadający sekcję authorization wyglądającą następująco:

<authorization>
  <rule Url="~/Customers/.*" Rule="AllowUseCustomers" />
</authorization>

Na początek trzeba znaleźć kod odpowiedzialny za autoryzację. Po kilkunastowym flircie z Reflectorem wszystko staje się jasne: tą częścią systemu zajmuje się implementacja interfejsu Microsoft.Practices.CompositeWeb.Interfaces.IAuthorizationRulesService. Napiszmy w takim razie własną:

  1:  public class RegexAuthorizationRulesService : IAuthorizationRulesService
  2:  {
  3:  	// each url can have multiplerules assigned
  4:  	Dictionary<string, List<string>> _rules = new Dictionary<string, List<string>>();
  5:  
  6:  	/// <summary>
  7:  	/// Assigns a new rule name for a given regex-based url.
  8:  	/// </summary>
  9:  	public void RegisterAuthorizationRule(string urlPath, string rule)
 10:  	{
 11:  		// create a new list of rules if a given url has not yet been been registered
 12:  		if (_rules.ContainsKey(urlPath) == false)
 13:  			_rules.Add(urlPath, new List<string>());
 14:  
 15:  		_rules[urlPath].Add(rule);
 16:  	}
 17:  
 18:  	/// <summary>
 19:  	/// Retrieves all rules that were assigned to regexes that match a given url path.
 20:  	/// </summary>
 21:  	public string[] GetAuthorizationRules(string urlPath)
 22:  	{
 23:  		var rulesList = from entry in _rules
 24:  						where Regex.IsMatch(urlPath, entry.Key, RegexOptions.IgnoreCase)
 25:  						select entry.Value;
 26:  
 27:  		// "flatten" the enumerable of List<string> to a one-dimensional array of strings
 28:  		var allRules = rulesList.SelectMany(list => list)
 29:  			.ToArray();
 30:  
 31:  		return allRules;
 32:  	}
 33:  }
 34:  

Ślicznie - mamy już komponent gotowy do "wstrzyknięcia". Tylko gdzie? Po kolejnych kilku minutach analizy WCSF znamy odpowiedź: standardowo wykorzystywana jest Microsoft.Practices.CompositeWeb.Authorization.AuthorizationRulesService . Fabryka rejestruje ją podczas startu aplikacji w swojej klasie Microsoft.Practices.CompositeWeb.WebClientApplication . A dokładniej: w metodzie AddRequiredServices wywoływanej z Application_Start. Musimy zmienić to zachowanie. Najprościej będzie odziedziczyć z klasy aplikacji i nadpisać standardową metodę, co wygląda tak:

  1:  public class CustomWebApplication : WebClientApplication
  2:  {
  3:  	protected override void AddRequiredServices()
  4:  	{
  5:  		this.RootContainer.Services.AddNew<RegexAuthorizationRulesService, IAuthorizationRulesService>();
  6:  
  7:  		base.AddRequiredServices();
  8:  	}
  9:  }

Tym sposobem zarejestrujemy własny serwis przed rejestracją swoich usług przez WCSF - i dokładnie o to nam chodzi.

Na koniec zostało jedynie poinstruowanie systemu, że od teraz należy wykorzystywać właśnie stworzoną klasę aplikacji. W tym celu otwieramy plik Global.asax i podmieniamy wymienioną tam klasę na własną:

<%@ Application Language="C#" Inherits="CustomNamespace.CustomWebApplication, CustomAssembly" %>

I to by było na tyle - od teraz możemy dowolnie przypisywać reguły adresom URL przy pomocy wyrażeń regularnych.

opublikowano 04 października 08 02:27 przez Procent | 0 komentarzy   
Zarejestrowano w kategorii: , , , ,
FullHD na VPC przez RDP

Co robi programista po powrocie z pracy? Powszechnie wiadomo - siada do pracy. O ile na warunki w miejscu zatrudnienia czasami ma się wpływ minimalny, o tyle domowe środowisko to zupełnie inna para kaloszy. Ostatnio postanowiłem jeszcze bardziej "uidealnić" swoje programistyczne gniazdo w domowym zaciszu i nabyłem kolejną parę oczu na świat - 24 calowe monstrum Hyundai W241D (wierność marce, a co:) ). W połączeniu z 19" Benq FP93GP ma mi zapewnić komfort pracy o jakim wcześniej mogłem jedynie pomarzyć. Już widziałem te setki linii kodu w trybie PIVOT, już myślałem jak to ślicznie zorganizuje moją pracę z maszynami wirtualnymi, jednym określeniem: juz witałem się z gąską.

No i przyszło rozczarowanie: jak się okazało, twórcy Virtual PC nie przewidzieli możliwości pracy w rozdzielczości większej niż 1600x1200. Niby to też bardzo dużo, ale nastawiałem się na full-screen w natywnej rozdzielczosci 1920x1200. Niestety, emulowana karta graficzna w VPC posiada jedynie 8MB pamięci i nie ma możliwości przeskoczenia tej bariery. "There is no f*** way!! Or is there...?"

Na szczęście są na tym świecie mądrzy ludzie! Potrzeba było kilku minut, aby znaleźć w internecie "workaround". Rozwiązanie: włączamy na wirtualce połączenia RemoteDesktop -> łączymy się za pomocą RDP z systemu gospodarza -> ustawiamy tryb FullScreen i... cieszymy się! Łiii...

Linki:

P.S. W celu podłączenia się do VPC do sesji "console" należy użyć polecenia mstsc ze switchem "/console". ALE! Może nie zadziałać. I jeśli nie zadziała to można albo zastanawiać się dlaczego a następnie zapytać jakiegoś guru, albo od razu użyć switcha "/admin". Ja byłem skazany na pierwszą drogę - dzięki, Karol :).

opublikowano 28 września 08 11:54 przez Procent | 4 komentarzy   
Zarejestrowano w kategorii: ,
Virtualny Tip z Marry Softer

Tym razem nowa konwencja. Prawdopodobnie jedyny taki wyskok. Niezainteresowanych moim wcieleniem się w autorkę Harry'ego Pottera zapraszam do pominięcia literackiego wstępu i przeczytania ostatniej, jedynej "wartościowej technicznie" części. Klik.

Wstęp

Był to jeden z tych lekkich, letnich dni w magicznej szkole Softwartu. Leniwie rozpoczynał się piątkowy wieczór.
"Czas na zmiany! " - pomyślała Marry Softer zdejmując czarodziejski kapelusz i rzucając w kąt sfatygowaną różdżkę. "Ile można bawić się z kolegami w lśniące pałki i tajemnicze sakiewki? W ten weekend zrobię coś pożytecznego."
Wyczarowanie dziurawego czajnika albo liniejącej łasicy jest niczym w porównaniu ze stworzeniem niezawodnego, poprawnie działającego i ślicznego programu. To był cel Marry - poznać inny, nowy rodzaj magii. Zawsze była ambitna.
Odrzuciła na bok książki zawierające bezużyteczny bełkot do wykrzykiwania podczas nagich pląsów w dzień sabatu. Siadła przed komputerem, lecz zamiast codziennego rytuału uruchamiania komunikatora Czaru-Maru i odwiedzania stron www.ezotv.pl oraz love.mag, podążyła w zupełnie innym kierunku...

Rozdział I

Jak każda magicznie naznaczona istota, Marry miała niesamowitą zdolność absorpcji wszelkich informacji. Wirujące gałki oczne poświadczały przetwarzanie, rozumienie i zapamiętywanie instrukcji związanych z zakresem The Magic of Software Development. "To jest autentycznie bardziej pasjonujące niż machanie kawałkiem drewna..." - wysapała bezwiednie, zaśliniona ze skupienia. Odgarnęła z czoła niesforny kosmyk włosów, gładząc przy tym tajemniczą bliznę, której pochodzenia mogła się tylko domyślać. Zdaniem nauczycieli z Softwartu kształt owej blizny nie mógł być przypadkowy. Gdy się bliżej przyjrzeć, można było dostrzec dwa nałożone na siebie krzyże. Złowrogi symbol krwi, bólu i cierpienia. Przypadek?
Marry oderwała się na chwilę od monitora i popadła w głębokie zamyślenie. "Dwa krzyże... Dlaczego ciągle widzę ten symbol?" Przez strony poświęcone poznawanej właśnie materii nieustannie przewijał się ten tajemniczy znak... Cóż to może znaczyć? Jaką niezgłębioną tajemnicę w sobie skrywa?
"Dokąd zmierzasz, cudowna dziewczyno? Czego pragniesz? Twoje przenaczenie czeka..." - niezidentyfikowany szept wyrwał ją z zadumy. Wystraszona wyłączyła komputer i postanowiła pozwolić umysłowi przyswoić nową wiedzę podczas snu.
Nie spała jednak spokojnie. Przez całą noc męczyły ją dziwne zjawy, jedne przynoszące przerażenie i ból, inne przygotowujące na ekstazę i uniesienie. Miały jedną wspólną cechę - w tle wszystkimi zmysłami dało się zawsze wyczuć ten niepokojący znak. #.

Rozdział II

Następnego ranka Marry obudziła się z nowym zapałem. Bez chwili zwłoki zaczęła odkrywać coraz to nowe zakamarki tajników programowania. W swej podróży natknęła się na cykl publikacji o praktyce niesamowicie wspomagającej tą piękną czynność. Po pochłonięciu całej zawartości "Wstępu do wirtualizacji" poczuła, że jest gotowa na zmierzenie się z prawdziwym wyzwaniem. Samo określenie "wirtualny" wydało jej się kuszące. Bez chwili zwłoki zabrała się do roboty i już po południu miała środowisko gotowe do przyjęcia całej nowej wiedzy i nieposkromionego zapału TWORZENIA. Rzuciła się na klawiaturę niczym wygłodniała gazela. I pisała, pisała...

Rozdział III

Blady świt zastał Marry śpiącą z głową opartą o biurko. Migoczący ekran musiał sam przejść w tryb oszczędzania energii. Jedyne co na nim widniało to znany już dobrze, pływający symbol #.
Marry otworzyła głaskane promieniami porannego słońca oczy. Uniosła głowę, zerknęła na monitor, i uśmiechnęła się do znaku. Przeciągnęła się, wstała i podeszła do lustra. Spojrzała na bliznę i pogładziła ją czule. "Już wiem co oznaczasz... świat wcale nie potrzebuje kolejnej wiedźmy" - wyszeptała. - "Nie zawiodę go..."
Z fascynacją i świeżymi siłami wróciła do komputera. Jeszcze cały dzień wolnego, cały dzień na programowanie, projektowanie, rozwiązywanie problemów i obchodzenie przeszkód!
W pokoju rozległo się miarowe stukanie klawiszy. Nic nie mogło jej przeszkodzić. Nic nie mogło zmniejszyć dziewczęcej determinacji do osiągnięcia wymarzonego celu.

Rozdział IV

Niedzielny wieczór nadszedł niepostrzeżenie. "To już cały dzień? Tak szybko?" Marry zrobiło się żal, jednak była z siebie dumna. Skończone! W ciągu zaledwie jednego weekendu nauczyła się więcej, niż przez cały miesiąc w Softwarcie. A efekt przerósł jej najśmielsze oczekiwania. Była świadoma, że przed nią nieskończone morze nauki, jednak... O dziwo, nie mogła się doczekać systematycznego posiadania nowej wiedzy. Było to dla niej nowe uczucie. Zwykle wyłącznie perspektywa wieczornych szaleństw pozwalała jej zmobilizować się do pracy. Było to nowe i... podobało jej się!
Z satysfakcją zapisała na wirtualnym dysku wszystkie zmiany. Zmniejszyła ekran, wcisnęła krzyżyk wyłączający system gościa. Wirtualna maszyna zapytała o sposób wyłączenia, a Marry bez wahania wybrała z listy Save State. Zapis stanu się rozpoczął...

Rozdział V

Wszystko stało się tak szybko... Trwało zaledwie kilka sekund, a mimo to w umyśle Marry chwile te zostaną na zawsze wyryte niczym niekończące się godziny. Proces zapisu stanu maszyny zawierającej całą jej piękną pracę doszedł do 3%, gdy drzwi z hukiem wpadły do środka. W przejściu stanęła mroczna postać. "HA!" - zakrzyknęła złowrogo - "mam cię, M.S.! Jam jest Lord GoogleMort! Przez lata próbowałem do ciebie dotrzeć, zniszczyć cię, zmiażdżyć!" Marry w ułamku sekundy przypomniała sobie wszystkie straszne opowieści, które z takim trudem wyparła ze świadomości. Powróciły wspomnienia z dzieciństwa, niewyjaśniona śmierć rodziców, strach przed jutrem, niepewność nadchodzących lat... To, z czym jej umysł uporał się z tak wielkim trudem, stało przed nią... Twarz nieznajomego wykrzywiła się okrutnie. "Pracowałem nad nowym zaklęciem, któremu na pewno się nie oprzesz! Już nigdy mnie nie poniżysz, nigdy ze mną nie zwyciężysz!" Uniosł nad głowę czarną różdżkę. Wydobywające się z niej ciemne iskry spadały na podłogę wydając przerażający syk, przynoszący na myśl najgłębsze otchłanie rozpaczy.
Marry oniemiała. Jej rozbiegany wzrok szukał ratunku, jednak jedyna możliwa broń była za daleko. Rzucona niedbale różdżka potoczyła się pod łóżko i leżała tam przez ostatnie dni. Wzrok zatrzymał się na chwilę na monitorze. Pasek zapisu maszyny wirtualnej sięgał 90%. "Akurat teraz, gdy moje życie zaczęło nabierać sensu..." pomyślała i w jej oku po raz pierwszy od lat zalśniła łza. Bezradnie zdała się na łaskę losu.
Lord GoogleMort zakończył wykonywać sekwencję ruchów wywołujących nowe, przerażające zaklęcie. Wycelował różdżkę w Marry, otworzył usta. Napięcie w pokoju sięgnęło zenitu. Oboje wiedzieli, że słowo rozpoczynające właśnie drogę przez przeponę Lorda oznacza koniec. Nieodwracalny koniec.
"CHROOOOME !!!" - echo niosło się daleko, daleko... W pomieszczeniu zapanowała smolista ciemność.

Rozdział VI

Marry wstała z podłogi. Stopniowo odzyskiwała wzrok. Po chwili mogła rozpoznać kształt wyrwanych drzwi, zarys okna przez które wpadały resztki światła niedzielnego wieczora. Gdy szok powoli mijał, do jej świadomości pulsującymi podrygami zaczął płynąć ból. Nie do zniesienia. Uniosła dłoń do czoła, pogładziła bliznę. Krzyknęła i natychmiast cofnęła rękę.
Marry spojrzała na palce - lepka czerwień nie pozostawiała wątpliwości. To blizna! To ona otrzymała cios straszliwym zaklęciem Chrome!
Rozejrzała się, jednak po Lordzie GoogleMorcie nie było ani śladu. Wtedy do niej dotarło i natychmiast zapomniała o bólu. Jej dzieło! Jej dziecko! Jej pierwszy program! Zaklęcie było tak silne, że spowodowane przez nie napięcie wyłączyło wszystkie urządzenia. A przeciez zapis stanu maszyny wirtualnej się nie zakończył!
Włączyła ponownie komputer, z zaciśniętymi wargami spróbowała uruchomić swoje wirtualnie środowisko... Niestety... "The virtual image could not be restored because the saved state was either corrupt or incompatible with this version of Virtual PC."

Epilog

Zrozpaczona Marry nie mogła uwierzyć. Tyle pracy stracone? Trzy dni na marne?
Wtedy jej wzrok przykuło coś dziwnego. W katalogu, w którym powinny znajdować się dwa pliki, widniały trzy! VMC - opcje maszyny, VHD - dysk maszyny, to oczywiste. A trzeci? VSV... "Nigdy czegoś takiego nie widziałam... Trudno, gorzej i tak być nie może" - pomyślała i usunęła nieznany twór. Chwila niepewności, dwuklik na VMC... Działa! I wszystkie dane są tam gdzie być powinny!
Na twarzy Marry zagościł uśmiech. Wszystkiego się już domyśliła. W katalogu maszyny wirtualnej VHD zawiera dane, podczas gdy VSV to tylko aktualny zatrzymany stan fizyczny komputera! Jego usunięcie działa po prostu jak wyciągnięcie wtyczki! Dlatego też jeśli podczas zapisywania stanu maszyny stanie się coś niedobrego, to pozbycie się go może być rozwiązaniem!
Ufff... odetchnęła z ulgą. "Teraz mogę zacząć myśleć o Lordzie GoogleMorcie..."

opublikowano 09 września 08 08:16 przez Procent | 7 komentarzy   
Zarejestrowano w kategorii: ,
Relacja z ZineDay 2008

O ZineDay słychać było już od jakiegoś czasu. Założyciel Zine'a, Michał Grzegorzewski, zorganizował (pewnie przy pomocy wielu osób) konferencję dla twórców, bloggerów i czytelników tego portalu. Wszystko odbyło się 6 września 2008 w siedzibie Microsoft w Warszawie.

Spotkanie nie miało rangi DevDays, HHH, C2C czy MTS. Ot, zlot kilkudziesięciu osób połączonych jednym portalem, bez wielkich akcji marketingowych i zaplecza "logistycznego". Jednak zarówno na organizację, jak i przebieg oraz menu prezentacyjne raczej nikt nie mógł narzekać. Liczba osób także nie była mała - około 50.
Cały dzień podzielony został na dwie części: "konferencyjne" prezentacje oraz konkurs. One by one:

Gael Fraiteur - "Addressing non-functional requirements with aspects"

Jako pierwszy wystąpił autor PostSharpa - darmowej biblioteki "przynoszącej Aspect-Oriented Programming do .NET". Sesja ta jednak wbrew pozorom wcale nie miała na celu zareklamowania produktu Gaela. Zamiast tego zostaliśmy zaproszeni na wycieczkę po świecie aspektów - co to jest, po co zostały wymyślone, jakie korzyści płyną z ich zastosowania, kiedy i dlaczego należy się tym zainteresować. Odpowiedzi? Zainteresować się należy JAK NAJSZYBCIEJ. Dlaczego? Odsyłam do wujka Google (lub materiału wideo który ma się ukazać na Zine), ponieważ temat jest na teraz za długi i za szeroki.
Tak czy siak, podczas wystąpienia Gael nie ograniczył się do prezentacji jedynie swojego rozwiązania. Wraz z PostSharpem liznęliśmy Policy Injection Application Block z Microsoftowej Enterprise Library, Spring.NET oraz Castle Project. Każdy z przedstawionych frameworków został pobieżnie omówiony i zaprezentowany w praktyce. Jakie są różnice w implementacji, jakie mają możliwości, jakie wady i jakie zalety? Było to bardziej odsłonięcie czubka prawdziwej góry lodowej. Myślę, że zarówno programista AOP jak i nowicjusz (do których głównie kierowany był występ) wyniósł z sali nowe informacje.
Oprócz praktyki wykorzystania gotowych bibliotek dowiedzieliśmy sie też jak one powstają - niektóre modyfikują gotowy kod MSIL (jak Post#), inne korzystają z remotingowych Proxy (PIAB), jeszcze inne tworzą własne klasy pośrednie (Spring i Castle).

Andras Belokosztolszki - "Managing change in the database world"

Myślałem, że ta sesja będzie nudną przerwą w tym aspektowym dniu. Na szczęście - jakże się myliłem! Prowadzący z firmy RedGate znakomitą angielszczyzną omówił kluczowe zagadnienia w wersjonowaniu baz danych. Przedstawił problemy wynikające z modyfikacji baz "w produkcji" (dowiedzieliśmy się np o problemach z zastosowaniem procedury sp_rename mogących przyprawić o zawrót głowy!). Pokazał na żywych przykładach przed jak wielkim wyzwaniem stoją autorzy narzędzi mających ten proces uprościć. Ujawnione zmiany pomiędzy mechanizmami przechowywania metadanych w SQL Server 2000 i 2005 są doprawdy zadziwiające - i wcale nie w pozytywnym tego słowa znaczeniu. Olaboga! Bez fałszywego marketingu, zero ściemy. Wydobywanie metadanych z różnych baz a następnie porównanie ich wbrew pozorom nie ogranicza się do kilku SELECTów - wzbudza szacunek.
O ile wątpię, czy administratorzy baz danych bądź programiści spędzający większość czasu "po tamtej stronie serwera" dowiedzieli się czegoś nowego, o tyle za dobór tematu sesji na typowy zlot .NETowców należą się brawa.

Gael Fraiteur & Jakub Binkowski - "More complex aspects using PostSharp"

Programowania aspektowego ciąg dalszy. Tym razem do Gaela dołączył na scenie zine'owy ziomek JBinkowski. Celem było zaprezentowanie oraz dokładniejsze omówienie bardziej zaawansowanych możliwości samego PostSharpa. W konwencji Mango Gdynia;) - Kuba jako biedny developer, Gael jako wszechwiedzący "problem-solver". Jednak mimo takiego porównania całość oglądało się bardzo przyjemnie, z pewnością było to bardziej interesujące niż jednoosobowe przedstawienie kilkudziesięciu linijek kodu.
Rozpoczęto od zaprezentowania banalnej aplikacji "książka kontaktów" oraz problemów jakie mają z nią końcowi użytkownicy (albo "THOSE UNGRATEFUL SHAMELESS BASTARDS THAT DARE TO COMPLAIN!", jak ich bez owijania w bawełnę określił Jakub:) ). Kłopoty najróżniejsze - od wolnej odpowiedzi na akcje użytkownika, przez niewyłapane wyjątki aż po wielowątkowość. Post# lekiem na całe zło:). Najbardziej zaawansowany scenariusz musiał zrobić wrażenie na wszystkich obecnych - Gael zademonstrował domiplementowanie interfejsu INofityPropertyChange do własnych klas poprzez jeden atrybut! Za magię pod owym atrybutem odpowiadało kilka PostSharpowych aspektów, których implementacja, choć bardzo interesująca, była moim zdaniem zbyt skomplikowana do przedstawienia na takim spotkaniu. Za mało czasu, za dużo kodu. Ale z niecierpliwością czekam na udostępnienie slajdów z prezentacji aby własnoocznie zobaczyć co i jak.

Konkurs na projekt Open Source

Konkurs na projekt Open Source został ogłoszony kilka miesięcy temu na blogu Michała. Do "finału" (czyli prezentacji na ZineDay) dotarło 6 projektów. Trzy najlepsze zasłużyły na nagrody główne - roczną subskrypcję MSDN Premium, trzy kolejne - na Vistę. Wszystkie prezentacje trzymały odpowiedni poziom, widać było zaangażowanie i przygotowanie autorów do prezentacji. Nie ma się co dziwić - było o co walczyć. Całość przypominała mi trochę Imagine Cup z tą różnicą, że zamiast stresować się "na scenie" mogłem po prostu oddać swój głos na obradach jury:). Gratulacje dla twórców wszystkich projektów i dzięki za interesujące ich przedstawienie.

Podsumowanie

Dzień zaliczam do bardzo udanych. Masa informacji o coraz popularniejszym w świecie .NET "paradygmacie" tworzenia oprowamowania + interesujące i bardzo przydatne porady "czego nie robić w SQL Server" + fajne prezentacje zgłoszonych projektów = event, na którym naprawdę warto być! Dzięki i czekamy na następne?

opublikowano 08 września 08 11:47 przez Procent | 0 komentarzy   
Zarejestrowano w kategorii: ,
Własna implementacja formatowania kodu C# -> HTML

ToBeDone

Każdy prowadzący technicznego bloga wcześniej czy później napotyka problem: jak przedstawić swój kod na stronie? Do wyboru mamy teoretycznie wiele możliwości. Jest popularny formatter Manoli, jest Actipro CodeHighlighter, o jeszcze innym rozwiązaniu pisał ostatnio Jacek Ciereszko. Gdy jednak rozpoczynalem swoją przygodę z blogowaniem ponad pół roku temu, nie mogłem znaleźć rozwiązania satysfakcjonującego mnie w 100%. Czego oczekiwałem? Pełnej kontroli nad otrzymanym kodem, łatwości dostosowania do własnych potrzeb oraz... możliwości momentalnego wprowadzenia poprawek, gdyby okazało się że coś nie jest tak jak powinno. I tak powstał Procent.Samples.CodeFormatter:). Chwilę po założeniu bloga powstała wersje "pre-alfa"(?) służąca mi aż do niedawna. Ostatnio postanowiłem doprowadzić ją do ładniejszego stanu i zaprezentować tutaj (po zakończeniu tych czynności kod robi więcej niż robił, a jest go 2x mniej! refactoring rulz). Zanim jednak przejdziemy do technicznych rozważań - ONLINE DEMO prezentujące główną funkcjonalność (czyli "paste -> format -> use") znajduje się pod adresem http://www.maciejaniserowicz.com/samples/CodeFormatter.aspx. CzkItOłt.

Rzut oka z lotu ptoka - UML

Na początek przedstawienie koncepcji - jak widzę problem od strony "techniczno-obiektowej". Całość procesu to nic innego jak odpowiednie przetwarzanie otrzymanego z zewnątrz tekstu: krok po kroku, reguła po regule. Każdy z tych kroków da się logicznie wyodrębnić i opisać, a co za tym idzie - opakować w osobną klasę. Separation of concerns, baby. Kolorowanie słów kluczowych nie powinno teoretycznie mieć wpływu na numerowanie linii, co z kolei ma się nijak do doklejenia notki od autora narzędzia, prawda?

Takie założenie pozwoliło mi traktować modyfikacje przekazanego tekstu jako łańcuch następujących po sobie czynności. Aż pozwolę sobie podkreślić najważniejsze słowo: łańcuch. Co za tym idzie - każda pojedyncza modyfikacja to ogniwo tej struktury mająca za zadanie wykonać robotę i przekazać efekt swojej pracy dalej. Tak oto powstała ChainElement. Banalne - w sam raz na pierwszy na tym blogu diagram klas(y) (sic!)!

Myślimy dalej i wymyślamy: tak naprawdę można rozdzielić wszystkie możliwe czynności na dwie logiczne grupy. Elementy łańcucha z pierwszej z nich operują na tekście jako całości (np. wspomniane doklejenie notki "Generated by..."), a z drugiej grzebią się w zawartości i zdobią odpowiednie fragmenty tekstu kodem CSS (np. "ozdabiacze" słów kluczowych czy komentarzy). O ile nie możemy przewidzieć co mogą robić ogniwa przynależące do pierwszej grupy, o tyle można domniemywać, że cała druga grupa ogranicza się do zdefiniowana odpowiedniego wyrażenia regularnego i tekstu mającego zastąpić wyszukaną wartość. Tak scharakteryzowana funkcjonalność da się zaimplementować w klasie bazowej zawierąjacej całą potrzebną logikę. A więc przedstawiamy CssDecoratingElement na diagramie numer dwa:

Nowa klasa implementuje abstrakcyjną ProcessString, ponieważ wie co ma zrobić z otrzymanym tekstem. Właściwość CssClass pozwala na skonfigurowanie stylu css wykorzystanego przez dany element, a abstrakcyjna właściwość _regexPattern wymusza na klasach dziedziczących zdefiniowanie kryteriów wyszukiwania napisu do zastąpienia.
Po takich przemyśleniach przychodzi czas na zdefiniowanie kolejnych stacji, na których musi się zatrzymać czysty tekst aby wyjechać "w chmurę" jako śliczny, kolorowy HTML. Nazwy klas mówią same za siebie, zatem kolejny diagram (ale dziś ze mnie sztywniak) powinien być wystarczający:

Po zaimplementowaniu takiej struktury można pokusić się o dołożenie kilku bonusów. Jeden z nich to możliwość konfiguracji sposobu, w jaki CSS zostaje umieszczony w wynikowym tekście. Na moje potrzeby całkowicie wystarcza generacja atrybutu "class" z odpowiednią nazwą, resztę i tak mam podefiniowaną w zewnętrznych plikach. Wychodząc do ludzi wypada jednak zaoferować możliwość kolorowania składni "inline", aby otrzymany wynik był gotów do natychmiastowego użycia. Do tego celu utworzyłem minihierarchię "Inline style providers" wraz z dwoma przykładowymi implementacjami. Pierwsza z nich (CSharpStyleProvider) pobiera na sztywno zdefiniowane style prosto z zasobów aplikacji, a druga (CustomStyleProvider) poprzez dziedziczenie z Dictionary<string, string> pozwala na własne dowolne definicje:

Zauważmy jedną rzecz: taka architektura sprawiła, że mamy omówione prawie całe zagadnienie, a nigdzie nie pojawiła się jeszcze nazwa CSharpCodeFormatter! Przy przedstawionych założeniach każdy konkretny CodeFormatter to nic innego jak zbiór odpowiednich klocków - wybierz czynności jakie chcesz wykonać, zbuduj z nich łańcuch i voilà!

Dodatkowo wprowadziłem jeszcze jeden podział w zaimplementowanych elementach łańcucha. Większość z nich jest niezależna od składni C#, więc warto było zaznaczyć możliwość ich bezpośredniego wykorzystania przy implementacji kolejnych języków:

C# diving

Po takim zarysowaniu zagadnienia czas na kilka rzutów oczami prosto w najbardziej interesujące miejsca w kodzie.

Inicjalizacja łańcucha

Krótko: wybieramy elementy, ustawiamy w odpowiedniej kolejności i:

  1:  protected override void InitializeChain()
  2:  {
  3:  	Chain = new HtmlEncoder();
  4:  	Chain.Attach(new DocumentationFormatter())
  5:  		.Attach(new SingleLineCommentsFormatter())
  6:  		.Attach(new MultiLineCommentsFormatter())
  7:  		.Attach(new DirectivesFormatter())
  8:  		.Attach(new StringsFormatter())
  9:  		.Attach(new KeywordsFormatter(_keywords))
 10:  		.Attach(new LinesCounter())
 11:  		.Attach(new Wrapper())
 12:  		.Attach(new CopyrightWriter());

Inline CSS vs CSS class

Decyzję o tym jaki kod generować można podjąć na dwóch poziomach: całego formattera oraz poszczególnych elementów łańcucha. Faktyczne wprowadzenie tej decyzji w życie odbywa się w CssDecoratingElement i wygląda tak:

  1:  protected string GetStyleFragment()
  2:  {
  3:  	if (InjectInlineCss)
  4:  		return string.Format("style=\"{0}\"", InlineStyleProvider.GetStyle(CssClass));
  5:  
  6:  	return string.Format("class=\"{0}\"", CssClass);
  7:  }
  8:  

Przed wykorzystaniem elementy muszą zostać odpowiednio skonfigurowane, CSharpFormatter robi to tak:

  1:  private void PrepareChainForStyleInlining()
  2:  {
  3:  	foreach (var element in Chain.AsEnumerable().OfType<CssDecoratingElement>())
  4:  	{
  5:  		element.InjectInlineCss = true;
  6:  		element.InlineStyleProvider = this.InlineStyleProvider;
  7:  	}
  8:  }

ChainElement.AsEnumerable

Na strukturach takich jak omawiany łańcuch chce się czasem poszaleć przy użyciu LINQ. Poniższa metoda umożliwia to zwracając wszystkie elementy łańcucha od obecnego w głąb:

  1:  public IEnumerable<ChainElement> AsEnumerable()
  2:  {
  3:  	yield return this;
  4:  	if (_next == null)
  5:  		yield break;
  6:  
  7:  	foreach (var element in _next.AsEnumerable())
  8:  		yield return element;
  9:  }

Embedded resources

Domyślne style "inline" oraz słowa kluczowe C# (ściągnięte stąd) zapisane są w plikach tekstowych dołączonych do projektu jako "embedded resource". Dzięki temu podczas pisania aplikacji możemy łatwo edytować ich zawartość, a po kompilacji nic nam nie zaśmieca folderu wynikowego. Oznaczenie pliku jako wewnętrzne zasoby odbywa się w VS następująco:

, natomiast wykorzystanie takiego pliku w kodzie demonstruje poniższy wycinek inicjalizujący kolekcję słów kluczowych w programie:

  1:  private static IEnumerable<string> InitializeKeywords()
  2:  {
  3:  	using (Stream resourceStream = Assembly.GetExecutingAssembly()
  4:  		.GetManifestResourceStream(("Procent.Samples.CodeFormatter.Resources.CSharpKeywords.txt")))
  5:  	{
  6:  		using (StreamReader reader = new StreamReader(resourceStream))
  7:  		{
  8:  			// reading a stream...
  9:  

Najciekawszy Regex

Manipulacje tekstem odbywają się przy użyciu wyrażeń regularnych. Nie ma sensu wypisywania tutaj wszystkich, z których skorzystałem, jednak jedno jest warte osobnego przedstawienia. Proces formatowania kodu odbywa się krok po kroku, co oznacza że element formatujący słowa kluczowe otrzyma tekst już częściowo sformatowany, a co za tym idzie - usiany tagami <span>, których nie powinien ruszać. Dodatkowo przyjąłem założenie, że każdy fragment tekstu nie może zostać sformatowany więcej niż raz. Dzięki temu przykładowo "int" będące częścią wcześniej pokolorowanego literału napisowego (bo StringsFormatter jest dołączony do łancucha przed KeywordsFormatter) nie zostanie dodatkowo oznaczone klasą słów kluczowych - i dobrze. Za takie sztuczki odpowiedzialne jest raptem kilka znaków pilnujących, aby odnaleziony tekst nie znajdował się wewnątrz taga XML bądź nie był jego częścią. Efekt ten osiągam doklejając je z przodu właściwego wyrażenia odpowiedzialnego za odnalezienie innych fragmentów tekstu. Szczegółowe zapoznanie się i rozgryzienie tego wyrażenia pozostawiam zainteresowanym jako pracę domową:

  1:  const string _outsideTagPatternStart = "(?<!<.*?(>.*)?)";

Najciekawszy CSS

Mistrzem CSS nie jestem, więc zamiast się wymądrzać odeślę do źródła tajemnej wiedzy o odpowiednim zawijaniu linii omijającym luki w poszczególnych przeglądarkach. Nie jestem w 100% pewny czy to zawsze działa, ale mimo to link: "Making preformated <pre> text wrap in CSS3, Mozilla, Opera and IE".

Przykładowy element łańcucha

I na koniec przykład jednego z "kroków" mielenia tekstu: klasa odpowiedzialna za formatowanie dyrektyw kompilatora (czyli linii w których pierwszym "niebiałym" znakiem jest #):

  1:  public class DirectivesFormatter : CssDecoratingElement
  2:  {
  3:  	protected override string _defaultCssClass
  4:  	{
  5:  		get { return "csDirective"; }
  6:  	}
  7:  
  8:  	protected override string _regexPattern
  9:  	{
 10:  		get { return @"^\s*#.*\n"; }
 11:  	}
 12:  }

Proste, łatwe i przyjemne - wszystko mamy wyciągnięte do odpowiednich klas bazowych.


To tyle przykładów z kodu. Zachęcam do ściągnięcia źródeł, zapoznania się z nimi "sam na sam" i wyrażenia swojej opinii. Co można zrobić lepiej/inaczej/wydajniej/bardziej interesująco?

Samary

Mechanizmy .NET wykorzystane w praktyce:

  • regular expressions
  • embedded resources
  • słówko kluczowe yield

Możliwości rozwoju:

  • implementacja kolejnych języków
  • implementacja innego zdobienia nieparzystych linii
  • więcej możliwości konfiguracyjnych (np. możliwe do wyłączenia dodawanie numerów linii czy konfigurowanie generowanych nazw klas, tak jak teraz możliwe jest definiowanie własnych styli inline)
  • parser CSS dla CSharpStyleProvider - aktualnie style przechowywane w wewnętrznym pliku tekstowym mają postać "nazwaKlasy|wartości", a można by się pokusić o odczytywanie "full-blown" CSS
  • implementacja osobnego kolorowania nieparzystych linii
  • i wreszcie, co by było chyba rzeczą najfajniejszą z fajnych - implementacja wtyczki do VS która robi to wszystko sama!

Kod źródłowy...

...zawierający bibliotekę oraz demko WinForms tak jak poprzednimi razy dostępny do ściągnięcia na stronie SAMPLES. Z ciekawości można również zajrzeć do kodu źródłowego wspomnianego wcześniej Manoli formatter. Cel i efekt te same, mimo że już na etapie koncepcyjnych rozważań obraliśmy inne drogi.

opublikowano 02 września 08 08:24 przez Procent | 4 komentarzy   
Zarejestrowano w kategorii: ,
C# Power ponownie - Control.AllChildControls

Podczas przygotowywania kolejnego posta z serii "Samples" zaimplementowało mi się coś bardzo fajnego, co chyba zasługuje na osobną notkę. Oto zatem kolejna krótka demonstracja potęgi połączonych mechanizmów C# (v. 2 i 3).
Scenariusz: mamy formatkę wypełnioną panelami, groupboxami, layoutami i wszystkimi innymi kontenerami jakie tam jeszcze Bozia z Redmond na toolbox wrzuciła. Nachodzi nas chętka na wykonanie pewnej operacji na WSZYSTKICH kontrolkach zawartych w oknie, niezależnie od tego gdzie są zagnieżdżone. Jak się do nich dobrać? Here comes the beauty of YIELD:

  1:  public static IEnumerable<Control> AllChildControls(this Control instance)
  2:  {
  3:  	foreach (Control control in instance.Controls)
  4:  	{
  5:  		yield return control;
  6:  		foreach (Control childControl in control.AllChildControls())
  7:  			yield return childControl;
  8:  	}
  9:  }

Wykorzystajmy to w jakimś interesującym przypadku... na przykład pod każdy TextBox podepnijmy ToolTipa pokazującego aktualną wartość właściwości Tag. Warunki z tego wynikające są dwa: kontrolka-dziecko musi być TextBoxem i jej Tag nie może być null. Na potęgę posępnego czerepu, LINQ przybywaj!!!

  1:  this.AllChildControls().OfType<TextBox>()
  2:  	.Where(tb => tb.Tag != null).ToList()
  3:  	.ForEach(tb => toolTip.SetToolTip(tb, tb.Tag.ToString()));

Może to jakieś zaćmienie, może za dużo kodowania bez przerwy, może nie widzę innego równie wyśmienitego rozwiązania, ale... jestem pod wrażeniem. Jak wyglądałby kod robiący to samo jeszcze kilkanaście miesięcy temu? Pewnie jakoś tak. Nie uzależniajmy się od technologii, ale wykorzystujmy w pełni to co nam oferuje!

opublikowano 30 sierpnia 08 10:22 przez Procent | 7 komentarzy   
Zarejestrowano w kategorii: ,
Partial classes & partial methods - explained

...far far away...

Bohaterami dzisiejszego spotkania są dwa współpracujące ze sobą twory (Bolki?), różniące się znacząco wiekiem. Partial classes (klasy częściowe...) zostały wprowadzone do .NET za czasów wersji 2.0 zarówno platformy .NET jak i języka C#. Partial methods z kolei to "najnowsza nowość", bowiem przyjście na świat tej konstrukcji miało miejsce zaledwie kilka miesięcy temu, wraz z .NET 3.5, C# 3.0, LINQ, lamda, extensions itpm (i tym podobną magią). O ile jednak całe jej "rodzeństwo" w postaci wymienionych mechanizmów zostało należycie przedstawione developerskiemu światu, na ich cześć odbywały się imprezy i pokazy, o tyle o "metodach częściowych" słyszy się raczej niewiele. Usłyszmy więc teraz.

RU interested?

Odpowiedź na jakże szpanersko zadane pytanie wcale nie musi być jasna i oczywista. Zanim przejdę do meritum, nakreślę tło do mającej nastąpić za chwilę operacji na żywej tkance. A więc: co to są te tzw. "partiale"? Jedyny cel ich powstania to rozbicie JEDNEJ klasy na WIELE plików *.cs. Część klasy w Person.cs, reszta w Person.Part2.cs. Do czego to prowadzi? Nie owijając w bawełnę: do płaczu i zębów zgrzytania. Jeżeli klasa jest AŻ TAK rozbudowana, że musimy dzielić ją na kilka plików, to oznacza to tylko jedno: nakazujemy jej zajmować się zbyt wieloma rzeczami! Zrobiliśmy z niej wór na śmieci, złamaliśmy zasadę "high cohesion", jesteśmy be i generalnie powinniśmy ją skasować i rozbić na wiele mniejszych. Klas, nie plików.
PO CO więc wprowadzono do .NET mechanizm tak jawnie promujący zły design, pozwalający na radosne tworzenie programistycznego błota? Zły, zły Microsoft? A no właśnie nie. Jest jeden scenariusz, gdy omawiane konstrukcje są, jakkolwiek to zabrzmi, "zbawcze". Scenariusz ów to GENERACJA KODU. Dlaczego? Faktem oraz "oczywistą oczywistością" jest, że sens generowania kodu kończy się w momencie konieczności ręcznej jego edycji. Częściowe klasy i metody to miły sposób na ułatwienie sobie eliminacji tej czynności. Pozwólże zatem Czytelniku, że odpowiem za Ciebie na pytanie postawione tytule tego paragrafu. Jesteś zainteresowany bohaterami tego wpisu "wtedy i tylko wtedy", gdy masz do czynienia z generacją kodu. Jeżeli nie masz - to zapomnij że istnieją i, na Mahometa, nie używaj ich w swoich projektach. Następne pokolenia programistów utrzymujących w przyszłości twój kod będą wdzięczne.

Partial classes

Na pierwszy ogień pójdą klasy, bowiem bez nich nie ma metod. (czy ktoś gdzieś za tak genialne stwierdzenia rozdaje nagrody?) Założenie jak i wykonanie jest banalne: w dwóch lub więcej plikach implementujemy klasę o tej samej nazwie. Jedyna różnica w stosunku do standardowego sposobu to dodanie słowa kluczowego 'partial' do modyfikatorów typu. Przykład praktycznego zastosowania tej sztuczki można zaobserwować chociażby tworząc najprostszy projekt Windows Forms w VS: wygenerowany kod odpowiedzialny za tworzenie kontrolek ląduje w Form1.designer.cs. Sami możemy zrobić coś takiego:

Jak widać - nazwy plików nie mają żadnego znaczenia. Kompilator C# zadba o to, aby wszystkie części zostały ze sobą odpowiednio sklejone. W dowód screen skompilowanego kodu - na tym etapie pojęcie "partial class" nie istnieje:

Co za tym idzie, obowiązują nas pewne ograniczenia. Nie można w kilku plikach zdefiniować sprzecznej hierarchii dziedziczenia, nie można jednej części oznaczyć jako 'public' a innej 'internal', nie można rozbijać