25/05/2009

Konkurs Code Camp 2009 - podsumowanie

Home

Na podsumowanie konferencji Code Camp 2009 w Warszawie z mojej perspektywy nadejdzie jeszcze czas. Najpierw chciałbym napisać o konkursie, który udało mi się zorganizować przy tej okazji. W skrócie konkurs składał się z dwóch etapów. Pierwszy etap (tzw. konkurs skojarzeniowy) odbył się w tygodniu poprzedzającym konferencję i polegał na odgadnięciu nazwy miejsca (kraju, miasta, wyspy itd.) na podstawie zdjęć, obrazków czy też opisu słownego. Wszystkie te miejsca miały tą wspólną cechę, że ich nazwy zostały użyte jako nazwy kodowe różnych produktów firmy Microsoft. Drugi etap, konkurs kartkowy, odbył się w czasie konferencji i polegał na odpowiedzeniu na 5 testowych pytań. Odpowiadając na pytanie nie można było korzystać z komputera, Internetu czyli trzeba było liczyć tylko na własną głowę.

Jak wyszło? Mówiąc szczerze nie jest do końca zadowolony. Frekwencja co tu dużo mówić nie dopisała. W konkursie wzięło udział tylko 6 osób. Chociaż z tego co dowiedziałem się od bardziej doświadczonych kolegów to i tak całkiem dobry wynik :)

Jeśli chodzi o konkurs skojarzeniowy to okazał się on dość łatwy i generalnie uczestnicy nie mieli problemów z odpowiedzeniem na pytania. Z konkursem kartkowym było już gorzej, poprawnych odpowiedzi było zdecydowanie mniej. Wydaje mi się, że było to spowodowane dwoma czynnikami. Po pierwsze pytania mogły być zbyt szczegółowe ale ja nie jestem tutaj obiektywny. Po drugie, konkurs był przewidziany na raptem 10 - 15 minut. Najwyraźniej nie udało mi się dostosować poziomu pytań do tak krótkiego czasu. Muszę o tym pamiętać i następnym razem przetestować pytania na znacznie większej grupie ludzi niż to uczyniłem.

Poniżej zamieszczam pytania i odpowiedzi do obu konkursów:

Konkurs skojarzeniowy


Odpowiedzi

  1. Dublin - Opis
  2. Hawaii - Visual Studio
  3. Astoria - ADO.NET Data Services
  4. Kilimanjaro - Sql Server 2010/Dynamics CRM 4.0
  5. Orleans - Opis
  6. Geneva - Opis
  7. Paris - Opis
  8. Ibiza - Sync Framework
  9. Oslo - Opis
  10. Quebec - Windows Embeded 2010
Do trzeciego pytani wkradł się błąd. Pytałem w nim o miasto na wschodnim wybrzeżu podczas gdy chodziło o zachodni brzeg USA. Z tego powodu zaliczałem również inne odpowiedzi na przykład Boston czyli Visual Studio 97.

Konkurs kartkowy

1. Mamy definicje dwóch klas jak poniżej:
class Base
{
   public virtual void Fun(int x)
   {
      Console.WriteLine("Base.Fun(int x)");
   }
}

class Derived : Base
{
   public override void Fun(int x)
   {
      Console.WriteLine("Derived.Fun(int x)");
   }

   public void Fun(object o)
   {
      Console.WriteLine("Derived.Fun(object o)");
   }
}
Co wypisze na ekran podany kod:
Derived d = new Derived();
d.Fun(1);
  1. Base.Fun(int x)
  2. Derived.Fun(int x)
  3. Derived.Fun(object o)
  4. Wywołanie metody spowoduje wyjątek
2.
Nullable<int> nullable = new Nullable<int>();
Type t = nullable.GetType();
Jaki rodzaj wyjątku zostanie rzucony po uruchomieniu tego kodu?
  1. Żaden
  2. InvalidOperationException
  3. NullReferenceExcpetion
  4. IndexOutOfRangeException
  5. ArgumentNullException
3. Załóżmy, że mamy zdefiniowaną zmienną o nazwie variable. Kiedy poniższy kod nie spowoduje rzucenia wyjątku:
variable = null;
variable.ToString();
4. Jaki będzie wynik wykonania poniższego kodu:
string s1 = new String(new char[] { 'a' });
string s2 = new String(new char[] { 'a' });
bool result = Object.ReferenceEquals(s1, s2);
Console.Write(result);

s1 = new String(new char[0]);
s2 = new String(new char[0]);
result = Object.ReferenceEquals(s1, s2);
Console.Write(result);

s1 = "Ala ma kota";
s2 = "Ala ma" + " kota";
result = Object.ReferenceEquals(s1, s2);
Console.Write(result);

s1 = "Ala ma kota";
string temp = "ma";
s2 = "Ala " + temp  + " kota";
result = Object.ReferenceEquals(s1, s2);
Console.Write(result);
  1. True, False, True, Talse
  2. False, False, True, False
  3. False, True, True, False
  4. False, False, False, False
  5. True, True, True, False
5. Jaki będzie wynik wykonania poniższego kodu:
delegate void Printer();
...
List printers = new List();
for (int i = 0; i < 4; i++)
{
  if (i % 2 == 0)
  {
      printers.Add(delegate { Console.Write(i); });
  }
  else
  {
     int j = i;
     printers.Add(delegate { Console.Write(j); });
  }
}

foreach (Printer printer in printers)
   printer();
  1. 0, 1, 2, 3
  2. 4, 4, 4, 4
  3. 4, 1, 4, 3
  4. 3, 2, 1, 0
  5. Inny

Odpowiedzi

  1. C - Derived.Fun(object o);

    W przypadku wywołania derived.Fun(1) zostanie wywołana metoda Derived.Foo(object). Metody zdefiniowane bezpośrednio na poziomie klasy wywołującej mają zawsze priorytet nad metodami zdefiniowanymi na poziomie klasy bazowej nawet jeżeli zostały przedefiniowane w klasie pochodnej. Jest tak ponieważ przy szukaniu metody najlepiej pasującej do wywołaniu, spośród wszystkich metod kandydujących odrzucane są metody zdefiniowane poza typem najbardziej wydziedziczonym. W wyniku tego kroku ze zbioru mogą zostać usunięte metody wirtualne.

  2. C - NullReferenceException

    Uruchomienie tego kod zakończy się rzuceniem wyjątku NullReferenceException w linijce z wywołaniem GetType. Typ Nullable<T> dostarcza własną implementacja ToString oraz GetHashCode ale nie GetType. Wywołanie GetType prowadzi więc do przekształcenia wartości Nullable<int> w referencje do obiektu (opakowywanie), a ponieważ w tym przypadku Nullable.HasValue jest równe false na stos odkładany jest null.

  3. Jeśli variable jest typem Nullable<T>

  4. C - False, True – bug?, True – optymalizacja kompilatora, False

  5. C - Domknięcie - Jak to działa?

19/05/2009

Name mangling, UniqueID, ClientID oraz ID

Home

Name mangling, po polsku maglowanie nazw, to w kontekście stron wzorcowych (ang. master pages) proces podmieniania identyfikatorów kontrolek przy generowaniu strony wynikowej (ze strony wzorcowej i strony z właściwą zawartością), a celem tej operacji jest zapewnianie, że identyfikatory będą na pewno unikalne w obrębie strony. Technicznie operacja ta sprowadza się do połączenia identyfikatora kontrolki z identyfikatorem kontenera w jakiej kontrolka została umieszczona, a dokładniej jego UniqueID. Operacja ta jest potrzebna ale stwarza też problemy i prowadzi niestety do błędów. Zacznę od opisu scenariusza:
  • Utworzyłem stronę wzorcową.
  • Utworzyłem stronę z zawartością.
  • Do strony z zawartością dodałem kontrolki GridView oraz SqlDataSource.
  • Skonfigurowałem połączenie z bazą danych.
  • Uruchomiłem stronę i GridView wyświetlił dane ze wskazanej tablicy.
  • Dodałem do strony kilka pól tekstowych i przycisk.
  • Dodałem metodę obsługującą naciśnięcie przycisku:
    protected void Button_Click(object sender, EventArgs e)
    {
     SqlDataSource.Insert();
    }
    
  • W kodzie strony deklaratywnie zdefiniowałem parametry wejściowe dla zapytania wstawiającego dane do bazy:
      <asp:SqlDataSource ID="SqlDataSource" runat="server" 
        ConnectionString="<%$ ConnectionStrings:Database %>" 
        SelectCommand="SELECT [Kolumna_1], [Kolumna_2], [Kolumna_3] FROM [Tabela]"
        InsertCommand="INSERT INTO users ([Kolumna_1], [Kolumna_2], [Kolumna_3]) VALUES (@Param_1,@Param1_2,@Param_3)">
      <InsertParameters>
        <asp:FormParameter Name="Param_1" FormField="PoleTekstowe_1" />
        ...
      </InsertParameters>
      </asp:SqlDataSource>
    
    W powyższym kodzie PoleTekstowe_1 to identyfikator pola tekstowego będącego źródłem danych dla parametru Param_1.
Mając gotową stronę uruchomiłem aplikację, wypełniłem pola tekstowe, nacisnąłem przycisk i otrzymałem wyjątek z komunikatem: Cannot insert the value NULL into column 'Kolumna_1'. Sprawdzam czy nie zrobiłem jakiejś literówki ale wszystko wygląda prawidłowo. Chwila zastanowienia i przypominam sobie, że przecież używałem już podobnego kodu i nie miałem problemów. Główkują dalej i zaczynam patrzeć podejrzliwie na użycie stron wzorcowych. Przenoszę więc cały kod do 'zwykłej' strony, odpalam i wszystko działa. W tym momencie przypominam sobie o Name mangling ale przecież nie zrezygnuję z tego powodu ze wszystkiego co dają strony tego typu.

Żeby nie przeciągać problem rozwiązałem rezygnując z deklaratywnego definiowana parametrów dla źródła danych na poziomie strony na rzecz zdefiniowania ich w kodzie. Oczywiście to nie wszystko. Sztuczka polega na tym, żeby przy podawaniu identyfikatora kontrolki, która będzie źródłem danych dla parametru należy użyć właściwości Control.UniqueID:
protected void Page_Load(object sender, EventArgs e)
{
   this.SqlDataSource.InsertParameters.Add(new FormParameter("Param_1", this.PoleTekstowe_1.UniqueID));
   this.SqlDataSource.InsertParameters.Add(new FormParameter("Param_2", this.PoleTekstowe_2.UniqueID));
   this.SqlDataSource.InsertParameters.Add(new FormParameter("Param_3", this.PoleTekstowe_3.UniqueID));
}
Control.UniqueID zawiera już przemaglowany identyfikator (globalnie unikalny w obrębie strony) i w związku z tym źródło danych nie ma problemu ze znalezieniem odpowiedniej kontrolki.

Dociekliwi mogą powiedzieć, że jest jeszcze właściwość Control.ClientID. Od razu mówię, że jeśli użyjemy tej właściwości to błąd również wystąpi. Na pierwszy rzut oka może wydawać się to dziwne ponieważ ClientID zawiera już zmieniony identyfikator. Różnica polega na tym, że do oddzielenie poszczególnych składowych identyfikatora ClientID używany jest inny separator niż przy UniqueID. Poniżej przykład dwóch identyfikatorów dla tej samej kontrolki:

UniqueID: ctl00$ContentPlaceHolder1$Nazwa
ClientID: ctl00_ContentPlaceHolder1_Nazwa

Dlaczego jednak użyto innych separatorów. Zacznijmy od tego, że aby proces podmieniania nazw był odwracalny ASP.NET musi umieć wydzielić z wygenerowanego identyfikatora jego składowe czyli identyfikatory kolejnych kontenerów i na końcu kontrolki. To jest przyczyna, dla której wprowadzono separatory. Separatorem powinien być oczywiście znak, który nie może wystąpić w bazowym identyfikatorze, w tym przypadku '$' ale można to zmienić.

Tutaj dochodzimy do momentu, w którym potrzebujemy z jakiegoś powodu odwołać się do wyrenderowanej kontrolki z poziomu JavaScript'u. Oczywiście potrzebujemy jakiś identyfikator i tu pojawiaja się problem. Otóż co zrobić jeśli jako separator użytu znaku niedozwolonego w identyfikatorach przez JavaScript? Problem ten postanowiono obejść wprowadzając ClientID i używając innego dozwolonego separatora czyli podkreślnika '_'. Reasumując UniqueID (renderuje się do atrybutu name tagu HTML) identyfikuje globalnie kontrolkę na potrzeby silnika ASP.NET, a ClientID (renderuje się do atrybutu id tagu HTML) na potrzeby JavaScript'u

11/05/2009

Visual Studio 2010

Home

Kilka dni temu, 6 maja, byłem na forum architektów, na którym między innymi pokazano wersję pre-beta Visual Studio 2010. Mówiono również o innych rzeczach ale część dotycząca nowej wersji tego środowiska była, przynajmniej dla mnie, zdecydowanie najciekawsza. Być może ta zasługa, jak zawsze rewelacyjnego Tomasza Kopacza ale nowe funkcjonalności wyglądały naprawdę bardzo obiecująco. Pozwolę sobie wymienić niektóre z nich:
  • UI oparte w całości o WPF
  • Dodano nowy sposób wyszukiwania w IntelliSense. W obecnej chwili po wpisaniu na przykład frazy Add IntelliSense poda wszystkie typy, metody itd. zaczynające się od tej frazy. W VS 2010 poda wszystkie typy, metody itd. zawierające podaną frazę czyli Add, AddTo ale również TestAdd, SuperAddTo.
  • Podgląd hierarchii wywołań pokazujący co wywołuje dana metoda i dalej co wywołują te metody itd.
  • Dynamiczne generowane diagramy sekwencji na podstawie kodu.
  • Generowanie szablonów klas. Na przykład piszemy:

    MyClass c = new MyClass();
    
    Załóżmy, że MyClass nie istnieje. W VS 2010 będziemy mogli wygenerować szablon dla tej klas. Podobny mechanizm będzie dostępny dla metod.
  • Transformacje konfiguracji. Tworzymy szablon konfiguracji i definiujemy przy pomocy specjalnego języka jak ten szablon ma zostać podczas kompilacji przekształcony w zależności od jakichś parametrów.
  • Dużo narzędzi do modelowania: integracja z Visio, powiązanie modelu z kodem na przykład po to aby kontrolować jak przebiegają prace - jakie komponenty zostały już zaimplementowane. Dalej kontrola poprawności kodu na podstawie modelu np.: czy nie ma zależności pomiędzy warstwami prezentacji i danych.
  • Lepsze narzędzia do pracy z aplikacjami wielowątkowymi. Profiler pokazujący jak działa nasza aplikacja wielowątkowa, który wątek generuje największe obciążenie, jak rozkłada się obciążenie na rdzenie/procesory. Narzędzia do radzenia sobie z zakleszczeniami.
  • Impact Analysis - Powiązanie testów z metodami, których dotyczą. Po modyfikacji metody wiemy, które testy należy powtórzyć.
  • Narywanie testów UI aplikacji okienkowych (WPF, Win Forms) - narzędzie oparte o Microsoft UI Automation. Testy takie można było pisać do tej pory tylko ręcznie.
Na koniec zostawiłem sobie dwa hity:

Historyczny debugger!!! Podczas debugowania będzie można podejrzeć jak zmieniał się stan aplikacji w różnych chwilach czasowych.

Nagrywanie stanu aplikacji!!! Przy pomocy odpowiedniego narzędzia będzie można zrzucić stan aplikacji (u klienta) do pliku i potem wczytać go do VS 2010 i rozpocząć debugowanie (potrzebny .NET 4.0).

Zaznaczam, że nie wiem jak te i inne rzeczy będą finalnie zapakowane w pudełka i sprzedawane. Z ciekawostek dodam, że Microsoft używa VS 2010 od początki roku 2008, a prace nad VS 2012 trwają już od roku :). Niby to nic dziwnego bo jak lepiej przetestować środowisko niż korzystając z niego, a prace nad tak złożonym programem muszą trwać. Ale jak sobie pomyślę, że ludzie z Microsoftu pracują teraz z/nad zabawkami, które poznam za parę lat, a zacznę z nimi pracować pewnie jeszcze później to co tu dużo mówić, ja też tak chcę!!!.

07/05/2009

"Autentykacja" - Czy takie słowo istnieje?

Home

Nie jestem purystą językowym ale niektóre rzeczy mi przeszkadzają i uważam, że powinno się mówić, a szczególnie pisać po polsku, a nie po "polskiemu". Właśnie jestem po lekturze kilku dokumentów dotyczących bezpieczeństwa, zarządzania użytkownikami oraz uprawnieniami, w których nagminnie używano słowa autentykacja. Niby wiadomo, że chodzi o proces uwierzytelniania (ang. authentication) ale takiego słowa nie ma po prostu w języku polskim. Jeśli ktoś nie wierzy to zapraszam do słownika języka polskiego, dostępny również on-line. Pół biedy kiedy używamy tego sformułowania w luźnej rozmowie ale słowo pisane jest bardziej wrażliwe na takie neologizmy, dziwne sformułowania itd.

06/05/2009

Dopowiedzenie

Home

Mam niewielką uwagę w kontekście postów Czemu zdarzenia nie działają??? oraz Czemu zdarzenia nie działają??? (część 2). Główne ich przesłanie:

W przypadku dynamicznego tworzenia kontrolek, czy to bezpośrednio czy to przy okazji użycia kontrolek data bound zawsze należy pamiętać aby dynamiczne kontrolki były tworzone nie tylko przy inicjalnym odwołaniu do strony ale również przy kolejnych.

Jest cały czas aktualne przy czym chciałbym dodać jedną rzecz. Otóż zapomniałem napisać, że w przypadku dowiązywania kontrolek do źródeł danych (na przykład do ObjectDataSource) nie trzeba się tym przejmować. Jest tak ponieważ źródła danych same dbają o to aby kontrolka została zasilona danymi w odpowiednim momencie. W szczególności nie trzeba jawnie wołać metody DataBind.

05/05/2009

Jak rozpoczęła się moja przygoda z Delphi

Home

Los chciał, że od jakiegoś czasu do moich obowiązków dołączyła potrzeba utrzymywania i pielęgnacji komponentu drzewo-listowego (kontrolka pozwalająca na wyświetlanie danych hierarchicznych i listowych z wieloma kolumnami) napisanego w Delphi. Długi broniłem i zapierałem się nogami ale w końcu musiałem się poddać. Dodam, że moja wiedza na temat Delphi była mniej niż skromna. Była bo teraz jest po prostu skromna :).

Plusem całej sytuacji jest to, że kod, który otrzymałem do pielęgnacji został dobrze wytestowany, komponent zachowuje się bardzo stabilnie, jednym słowem zgłoszeń błędów jest mało.

Można zapytań po co utrzymywać stary komponent skoro można napisać nowy albo jeszcze lepiej wybrać i zakupić jeden z istniejących na rynku. Z przepisaniem problem jest taki, że potrzeba by pewnie jednego osobo-roku zdolnego programisty aby to przepisać na .NET (tyle mniej więcej zajęło napisanie starego komponentu) plus dużo czasu na wytestowanie i stabilizację. Ameryki nie odkryję jeśli powiem, że znalezienie takiej ilości zasobów na w gruncie rzeczy niekomercyjny projekt to trudna sprawa.

Jeśli chodzi o zakupienie komercyjnego rozwiązania to pomysł dobry ale zawsze jest jakieś ale. Osobiście zapoznałem się i przebadałem pod względem wydajności, funkcjonalności itd. około dziesięciu rozwiązań dostępnych na rynku. Niektóre komponenty mają naprawdę duże możliwości. Problem polega na tym, że pomimo wszystko nie pokrywają wszystkich cech komponentu stworzonego na wewnętrzne potrzeby firmy, w której pracuję. Nie wchodząc w szczegóły firmowy produkt potrafi naprawdę dużo. Sytuacja bez wyjścia? Tak i nie. Tak, ponieważ z pewnością nie uda się znaleźć rozwiązania w 100% pokrywającego wymagania. Nie, ponieważ w obecnej chwili firma rozwija swoje produkty w .NET, a używanie starego komponentu wymaga użycia ActiveX z czego raz po raz wynikają jakieś problemy. Nie wspominając już o konieczności utrzymywania starego kodu.

Reasumując moja przygoda z Delphi jeszcze potrwa i mam nadzieję, że się czegoś nauczę. Na razie dzięki porównaniu IDE dla Delphi z Visual Studio zdałem sobie sprawę jak duży postęp dokonał się jeśli chodzi o zintegrowane środowiska programistyczne. Z drugiej strony porównanie czasu kompilacji dużego projektu napisanego w Delphi do projektu napisanego w .NET wypada bardzo znacząco na korzyść tej pierwszej technologii. Niestety podobnie jest z szybkością uruchamiania się aplikacji.

04/05/2009

Skrzydła furii

Home

Wiele osób, w tym i ja, spędziło długie godziny swoich młodzieńczych lat grając w takie gry jak Wings of fury. Kilka kolorów na krzyż, idea prosta ja budowa cepa, a grywalności tyle, że można by podzielić pomiędzy kilkadziesiąt współczesnych tytułów i jeszcze by zostało. Kiedy, więc przed weekendem majowym natknąłem się na sequel tej gry stworzony przez polskich programistów - Wings of fury 2 moje serce przyspieszyło.

Na szczęście, po za poprawioną grafiką, dużo się nie zmieniło. Znowu latamy w lewo i w prawo, zrzucam bomby, odpalamy rakiety, startujemy i lądujemy na lotniskowcu itd. Jednym słowem to co tygryski lubią najbardziej.

Jest trochę bugów, które utrudniają grę (problemy ze sterowaniem samolotu, menu gry słabo działa) ale da się z nimi grać. Najgorsze, że pomimo niewielkich wymagań występują problemy z uruchomieniem gry. W moim przypadku gra nie chciała działać na dwóch z trzech testowanych komputerów.

Tytuł jest w pełni darmowy i co dla mnie najciekawsze został napisany w C# na silniku MOGRE. Jest to zarządzana nakładka na silnik OGRE, a jego możliwości wydają się bardzo duże. Zaciekawiło mnie to tyle, że przymierzam się do zrobienia czegoś przy jego pomocy. Co z tego wyjdzie czas pokaże.

Jako podsumowanie mogę powiedzieć, pomimo pewnych zastrzeżeń, brawo dla autorów.