Zapytanie LINQ vs metody LINQ

Wszyscy chyba zdają sobie sprawę z tego, jakim dobrodziejstwem jest LINQ, które pojawiło się dosyć dawno, wraz z .NET 3.0 3.5. Jak wiadomo LINQ oferuje trochę nowych słów kluczowych oraz trochę metod – i tu pojawia się pytanie  – czym różni się zapis za pomocą słów kluczowych od zapisu „metodowego”? Szczególnie interesujące zdaje się być to, czy któryś z zapisów powoduje jakiś narzut wydajnościowy.

Nie będę budował napięcia i od razu odpowiem – query syntax w zasadzie nie różni się niczym od zapisu za pomocą extension methods. W praktyce, zapytanie zapisane za pomocą słów kluczowych jest tłumaczone podczas procesu kompilacji na coś, co CLR świetnie rozumie – metody. Microsoft, tak jak wielu programistów, preferuje zapis „zapytaniowy” nad „metodowym” ze względu na czytelność. Moim zdaniem jest to sprawa mocno dyskusyjna, dla mnie często dużo bardziej czytelniejsze jest używanie extension methods. Ponadto, niestety nie wszystko zapisywalne za pomocą extension methods da się zapisać za pomocą słów kluczowych, ale o tym za moment w przykładach.

Przykład 1

int[] numbers = { 5, 10, 8, 3, 6, 12 };

IEnumerable numQuery1 =
    from num in numbers
    where num % 2 == 0
    orderby num
    select num;

Taki kod równoważny jest (i jednocześnie tłumaczony w procesie kompilacji na następujący):

IEnumerable numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n);

Czy ten drugi nie wydaje się Wam czytelniejszy? ;) Nietrudno jednak stworzyć przykład w którym query syntax będzie bardziej wymowne.

Przykład 2

var personQuery1 = from person in people
                   let fullname = person.Name + " " + person.Surname
                   select new { Name = fullname, Age = person.Age };

var personQuery2 = people
                   .Select(person => new { Name = person.Name + " " + person.Surname, Age = person.Age });

W pierwszej linijce widzimy jak przydatne (dla czytelności) jest słowo kluczowe let pozwalające na tymczasową definicję nowej zmiennej (więcej o słówku let tu i tu na blogu Maćka Aniserowicza). Zapis za pomocą extension methods nie jest już taki ładny (choć to też zapewne sprawa gustu). Ostatni przykład zaprezentuje nam, że nie wszystko da się zrobić za pomocą query syntax.

Przykład 3

int[] numbers = { 5, 10, 8, 3, 6, 12 };
var nums = numbers.Skip(3).Take(2).ToList();

Efektu wywołania takich metod nie otrzyma się za pomocą zapytania.

Podsumowanie

Wszystko co da się napisać za pomocą query syntax da się zapisać za pomocą extension methods. Odwrotnie już tak niestety nie jest. Często zapis za pomocą słów kluczowych jest dużo czytelniejszy (szczególnie przy używaniu let, group, join), natomiast metody dają nam szersze możliwości. Wybór więc powinien zależeć od osobistego stylu i zdania na temat tego, co jest bardziej wymownie. Nieważne jednak czy korzystasz z metod, czy z zapytań, powinieneś robić to świadomie, aby nie tracić na wydajności – polecam przeczytać drugi z linków do blogu Maćka powyżej.

Prosty sposób na uaktualnienie GUI za pomocą BackgroundWorkera

Podczas pisania aplikacji okienkowych często zdarza się, że nasz program pobiera duże ilości danych, a następnie wyświetla je użytkownikowi. Niezwykle denerwującą sytuacją jest, gdy całość danych wyświetla się „na raz”. Jeśli nie „zamraża” to interfejsu użytkownika i jeszcze do tego pisze coś w stylu „Praca w toku” to jeszcze pół biedy, gorzej jak użytkownik pozostaje z okienkiem z uroczym dopiskiem „Nie odpowiada”. Wielkie szanse, że zirytowany taką sytuacją wyłączy naszą aplikację i zgłosi nam błąd – że nie działa :) Warto jednak zrobić coś jeszcze lepszego, niż zwykłe ostrzeżenie użytkownika, że troszkę poczeka.

Moim zdaniem najlepiej jest wprowadzić do aplikacji pasek postępu (choć nie zawsze jest to możliwe, bo czasem nie wiadomo ile danych przybędzie) i przede wszystkim – podzielić dane na paczki i prezentować dane progresywnie.

Jak to zrobić?

Najprostszym i przyjemnym sposobem jest użycie klasy BackgroundWorker, ale zacznijmy od początku. W celach demonstracyjnych stworzymy proste okienko, które będzie zawierało ListBox – do prezentacji wyników, przycisk „Start” oraz ProgressBar. Przejdźmy teraz do kodu:

private BackgroundWorker backgroundWorker = new BackgroundWorker();
private const int Results = 40;
private const int MaxPartCount = 5;

public PartialUpdateWindow()
{
    InitializeComponent();

    //initializing backgroundWorker
    backgroundWorker.DoWork += backgroundWorker_DoWork;
    backgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;
    backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
    backgroundWorker.WorkerReportsProgress = true;
}

Kod chyba jest bardzo wymowny. Tworzymy nową instancję BackgroundWorkera, dla prostoty przykładu ustalamy ile będzie wyników i ile ma liczyć maksymalna paczka danych do wyświetlenia. Następnie przypisujemy odpowiednie zdarzenia – DoWork – czyli to co ma zostać wykonane, ProgressChanged – zdarzenie odpalane w wątku GUI, które wyświetla wyniki, RunWorkerCompleted – odpalane po zakończeniu DoWork. Ostatnia linijka jest istotna, bo domyślnie ustawiona jest na false i wywołanie ProgressChanged skończy się wyjątkiem. Przejdźmy teraz do implementacji poszczególnych metod.

private void startButton_Click(object sender, RoutedEventArgs e)
{
    resultsListBox.Items.Clear();
    startButton.IsEnabled = false;
    backgroundWorker.RunWorkerAsync(Results);
}

Na początek funkcja podpięta pod przycisk która odpali naszego BackgroundWorkera. Jak widzimy do metody RunWorkerAsync, która uruchamia wątek możemy przekazać opcjonalnie argument. Może być on dowolnego typu i może być tylko jeden. W razie potrzeby, można zawsze przesłać tablicę lub inny kontener.

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    int percentageComplete;
    List tempResults = new List();
    int partsCount;

    var random = new Random();

    for (var i = 1; i <= Math.Ceiling((int)e.Argument / (double)MaxPartCount); i++)
    {
        Thread.Sleep(random.Next(500, 1000)); //simulating data fetching

        if (i * MaxPartCount <= (int)e.Argument)
            partsCount = MaxPartCount; //send maximum
        else
            partsCount = (int)e.Argument - i * MaxPartCount; //send remaining

        for (var j = 0; j < partsCount; j++)
            tempResults.Add(random.Next());

        percentageComplete = (int)(((double)(i * MaxPartCount) / (int)e.Argument) * 100);

        backgroundWorker.ReportProgress(percentageComplete, tempResults);
    }
}

Teraz główna część naszego przykładu, czyli metoda podpięta pod DoWork. W środku tej metody tworzymy pętlę, która przebiega odpowiednią ilość razy (sufit ze wszystkich wyników podzielonych na maksymalna ilość części). Jak widzimy możemy się odwołać do przesłanego argumentu poprzez e.Argument. Musimy jednak stosować rzutowanie, gdyż e.Argument jest typu object (to dosyć oczywiste). W dalszych linijkach generujemy w losowym odstępie czasu po partsCount (równa MaxPartCount albo to co nie zostało jeszcze wysłane) liczb losowych, a także obliczamy procent wykonanej roboty. Kluczową częścią metody jest jej ostatnia linijka, która wywołuje w wątku GUI metodę podpiętą pod ProgressChanged. Do metody tej przekazujemy procent wykonanej pracy oraz znowu mamy opcjonalnie do przekazania jeden argument (ponownie typu object). To umożliwia nam sprytne użycie pozyskanych częściowych wyników - wysłanie ich do GUI. Dalsza część to już oczywistość:

private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    completeProgressBar.Value = e.ProgressPercentage;
    foreach (var item in (List)e.UserState)
        resultsListBox.Items.Add(item);
}

private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    startButton.IsEnabled = true;
}

W backgroundWorker_ProgressChanged uaktualniamy stan ProgressBara oraz dodajemy pozyskane elementu do ListBoksa. Jest to możliwe gdyż, jak już wspomniałem, metoda ta wywoływana jest w tym samym wątku co GUI. Warto zwrócić uwagę na przekazany argument dostępny pod e.UserState - znów konieczne jest rzutowanie. Po skończonej pracy odblokowywujemy przycisk start i to tyle.

Podsumowanie

Widzimy, że rozwiązanie problemu częściowego uaktualniania interfejsu za pomocą BackgroundWorkera jest bardzo łatwe. To jest niewątpliwy plus. Ten sposób ma też (jak chyba wszystko ;)) jednak swoje wady. Po pierwsze, widać w kodzie, że w wielu miejscach musimy stosować rzutowanie z typu object na inny typ. Nie jest to operacja bezpieczna i przy jakichkolwiek zmianach w kodzie należy pamiętać aby pozmieniać też rzutowania w innych miejscach. Innym minusem jest utrudnione oddzielnie widoku od logiki, gdyż klasa BackgroundWorker pozostaje mocno powiązana z GUI.

Konicząc mój wywód - jeśli tworzysz małą aplikację lub pogodzenie się z minusami BackgroundWorkera nie jest szkodliwe dla Ciebie, ani dla tworzonego kodu - jak najbardziej polecam to rozwiązanie, bo po co pisać kod, który stworzył już ktoś wcześniej?

Producent i konsument – przykład użycia słowa kluczowego lock

Niejednokrotnie podczas pisania aplikacji napotyka się na sytuację gdy jedna metoda produkuje pewne dane, inna natomiast w pewien sposób je konsumuje. Czasem dobrym pomysłem jest, w przypadku gdy produkowane dane są w pewien sposób podzielne na części, wykonywać produkcję i konsumpcję w równoległych wątkach. Tutaj pojawia się istotny problem z zagadnienia wielowątkowości – synchronizacja. Oba (wszystkie) wątki współdzielące dany zasób muszą z niego korzystać w pewien ustalony sposób, tak aby w danej chwili korzystał z niego tylko jeden z wątków. W uproszczeniu, zapewnienie tego stanu nazywamy synchronizacją. Problem ten jest na tyle niebanalny i powszechny, że platforma .NET wspomaga synchronizację za pomocą wbudowanych mechanizmów. Jednym z nich jest słowo kluczowe lock. Użycie słowa kluczowego lock wygląda tak:

 lock(somethingSharedToLock)
{
     // operations on the locked object
}

Jak widać składnia jest bardzo prosta, ale co tak właściwie daje nam lock? Użycie słowa kluczowego lock gwarantuje nam, iż żaden inny wątek nie będzie ingerował w zablokowany obiekt podczas wykonywania instrukcji z nawiasu klamrowego. Natomiast jeśli obiekt jest zablokowany przez inny wątek, to kolejny lock będzie cierpliwie czekał na zwolnienie obiektu i dopiero wtedy go zablokuje. Pięknie, prawda? :) Oczywiście lock, jak wszystko – ma swoje wady. Częste i nierozważne lockowanie może doprowadzić do tzw. zakleszczenia (ang. deadlock). Starczy tej teorii, przejdźmy do przykładu (przykład z całą pewnością nie pokazuje best practices tworzenia kodu, ale chodziło mi o maksymalne uproszczenie przykładu).

Stwórzmy sobie prostą klasę producenta:

class Producer
{
public bool IsFinished
{
    get;
    set;
}
public List List
{
    get;
    set;
}
public Producer()
{
    List = new List();
    IsFinished = false;
}
public void Produce()
{
    Random random = new Random();

    for (int i = 0; i < 20; i++)
    {
        List.Add(random.Next(0, 20));
        Console.WriteLine("Producer[{0}]={1}", i, List[i]);
        Thread.Sleep(500);
    }
    IsFinished = true;
    Console.WriteLine("Producer has finished his work");
}
}

Klasa ta, jak widać, w konstruktorze przyjmuję listę, a następnie po wywołaniu Produce() wpisuje do tej listy losowe liczby całkowite z przedziału <0,20) wypisując je przy okazji. Klasa posiada pole które poinformuje nas, że praca została zakończona. Usypianie w metodzie produkującej umożliwi nam zaobserwowanie pewnej ciekawej rzeczy, ale o tym dalej.

Klasa konsumenta:

class Consument
{
    private Producer producer;
    public Consument(Producer producer)
    {
        this.producer = producer;
    }
    public void Consume()
    {
        int currentElement = 0;
        int elementCount = 0;

        while (true)
        {
              elementCount = producer.List.Count;

              if (producer.List.Count > currentElement)
              {
                   producer.List[currentElement] += 2;
                   Console.WriteLine("Consument[{0}]={1}", currentElement, producer.List[currentElement]);
                   currentElement++;
              }
              if (producer.List.Count == currentElement && producer.IsFinished)
                   break;
         }
         Console.WriteLine("Consument has finished his work");
    }
}

Konsument, w konstruktorze przyjmuje producenta, a po wywołaniu Consume(), o ile pojawiło się coś nowego zwiększa wartość każdego elementu o 2, a następnie go wypisuje. Metoda kończy swoje działanie w momencie, gdy Producent da o tym znać i wszystkie elementy zostaną zmienione.

Pozostaje nam odpalić produkcje i konsumpcje w oddzielnych wątkach:

private static void Main(string[] args)
{
     Producer producer = new Producer();
     Consument consument = new Consument(producer);

     Thread producerThread = new Thread(new ThreadStart(producer.Produce));
     Thread consumentThread = new Thread(new ThreadStart(consument.Consume));

     producerThread.Start();
     consumentThread.Start();
     producerThread.Join();
     consumentThread.Join();
}

Wynik działania programu (przykładowy!!):

Producer[0]=0
Consument[0]=2
Producer[1]=4
Consument[1]=4
Producer[2]=17
Consument[2]=17
Producer[3]=8
Consument[3]=8
Producer[4]=0
Consument[4]=2
Producer[5]=16
Consument[5]=16
Producer[6]=6
Consument[6]=6
Producer[7]=13
Consument[7]=13
Producer[8]=17
Consument[8]=19
Producer[9]=9
Consument[9]=11
Producer[10]=15
Consument[10]=17
Producer[11]=14
Consument[11]=14
Producer[12]=11
Consument[12]=13
Producer[13]=3
Consument[13]=5
Producer[14]=15
Consument[14]=15
Producer[15]=13
Consument[15]=13
Producer[16]=16
Consument[16]=18
Producer[17]=5
Consument[17]=7
Producer[18]=2
Consument[18]=2
Producer[19]=14
Consument[19]=16
Producer has finished his work
Consument has finished his work

Ups! Widzimy, że w wielu przypadkach (1, 2, 3, 5, 6, 7, 11, 14, 15, 18 - czyli w połowie wszystkich) wartość producenta nie została zmieniona, tak jakbyśmy chcieli. Czemu się tak stało? Otóż produkcja kolejnych elementów trwa dłużej niż konsumpcja (poprzez wspomniane wcześniej Thread.Sleep(500)) co powoduje iż w pewnych momentach dana jest "jeszcze" tworzona, a próbuje już być skonsumowana, co powoduje iż proces konsumpcji (dodanie do wartości 2) zostaje pominięte. Uniknięcie tej katastrofy jest możliwe dzięki wspomnianemu lockowi. Wystarczy napisać:

lock (((ICollection)List).SyncRoot)
{
    List.Add(random.Next(0, 20));
    Console.WriteLine("Producer[{0}]={1}", i, List[i]);
    Thread.Sleep(500);
}

oraz:

lock (((ICollection)producer.List).SyncRoot)
{
    elementCount = producer.List.Count;

    if (producer.List.Count > currentElement)
    {
        producer.List[currentElement] += 2;
        Console.WriteLine("Consument[{0}]={1}", currentElement, producer.List[currentElement]);
        currentElement++;
    }
    if (producer.List.Count == currentElement && producer.IsFinished)
        break;
}

To zapewni nam prawidłowe działanie kodu (jak nie wierzycie - sprawdźcie sami :)). A co tak właściwie się stało? Kolekcja w momencie produkowania jest na chwilę blokowana, a więc konsumpcja jest wtedy wstrzymana, gdy produkcja się skończy, konsumpcja zabiera kolekcję dla siebie. Dzięki temu działanie jest zgrabnie zsynchronizowane. Dla kolekcji, w celu synchronizacji należy używać właściwości SyncRoot która jest wymagana przez interfejs ICollection. Wszystkie inne obiekty możemy lockować w sposób bezpośredni (lock(someObject)) chyba, że coś (dokumentacja) podpowiada nam inaczej ;)

To tyle w tej kwestii, dla zainteresowanych polecam poczytać Thread Synchronization oraz How to: Synchronize a Producer and a Consumer Thread.

Pełny listing:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;

namespace ProducentConsumerExample
{
    class Example
    {
        private static void Main(string[] args)
        {
            Producer producer = new Producer();
            Consument consument = new Consument(producer);

            Thread producerThread = new Thread(new ThreadStart(producer.Produce));
            Thread consumentThread = new Thread(new ThreadStart(consument.Consume));

            producerThread.Start();
            consumentThread.Start();

            producerThread.Join();
            consumentThread.Join();
        }
    }

    class Producer
    {
        public bool IsFinished
        {
            get;
            set;
        }

        public List List
        {
            get;
            set;
        }

        public Producer()
        {
            List = new List();
            IsFinished = false;
        }

        public void Produce()
        {
            Random random = new Random();

            for (int i = 0; i < 20; i++)
            {
                lock (((ICollection)List).SyncRoot)
                {
                    List.Add(random.Next(0, 20));
                    Console.WriteLine("Producer[{0}]={1}", i, List[i]);
                    Thread.Sleep(500);
                }
            }

            IsFinished = true;

            Console.WriteLine("Producer has finished his work");
        }
    }

    class Consument
    {
        private Producer producer;

        public Consument(Producer producer)
        {
            this.producer = producer;
        }

        public void Consume()
        {
            int currentElement = 0;
            int elementCount = 0;

            while (true)
            {
                lock (((ICollection)producer.List).SyncRoot)
                {
                    elementCount = producer.List.Count;

                    if (producer.List.Count > currentElement)
                    {
                        producer.List[currentElement] += 2;
                        Console.WriteLine("Consument[{0}]={1}", currentElement, producer.List[currentElement]);
                        currentElement++;
                    }
                    if (producer.List.Count == currentElement && producer.IsFinished)
                        break;
                }
            }

            Console.WriteLine("Consument has finished his work");
        }
    }
}

Steve Ballmer – spotkanie ze społecznością / Imagine Cup 2010 w Polsce!

23 kwietnia, o godzinie 10 w hotelu Sheraton w Warszawie odbyło się spotkanie Steve’a Ballmera ze społecznościami IT. Tak się złożyło, że dostąpiłem zaszczytu bycia zaproszonym na owe spotkanie :)

Steve’a Ballmera – prezesa MS nie trzeba chyba specjalnie przedstawiać. Wszyscy zorientowani w świecie Microsoftu kojarzą zapewne ekscentryczne wystąpienia Steve’a na różnych konferencjach. Miałem więc nadzieję, że i tym razem zobaczę coś niezwykłego, ponadto byłem zaciekawiony jego osobą samą w sobie. Jak więc było?

Na początek – nic tak szalonego jak na filmiku wyżej się nie stało, a szkoda ;) Całe spotkanie miało charakter krótkiej prezentacji Steve’a, a pozostała część to Q&A. Nie będę tu przytaczał pytań zadawanych przez publiczność – powiem tylko, że było ciekawie i bardzo zabawnie. Steve oczarował mnie swoją charyzmą i przemyślanymi za każdym razem odpowiedziami na pytania. Szkoda tylko, że spotkanie było tak krótkie.

Przy okazji swojej wizyty w Polsce, Steve ogłosił iż finały kolejnej edycji Imagine Cupa odbędą się w Polsce! Cóż, to doskonała okazja, żeby zabłysnąć w przyszłym roku, bo niestety w tym roku, swoje wystąpienie określiłbym tak ;)

C2C 2009 – relacja

Dokładnie tydzień temu odbyła się konferencja C2C 2009, emocje i kurz opadły.. i szkoda, że to już za nami :) Zapraszam do przeczytania mojej relacji.

Na miejsce dotarłem na parę minut przed rozpoczęciem konferencji, gdyż mimo dokładnych instrukcji, ciężko było mi znaleźć budynek Wydziału Biologii UW, na szczęście – udało się :) W środku był już tłum ludzi, w którym ledwo udało się znaleźć stolik rejestracji, która chwilę później przebiegła bezproblemowo. Wybrana przeze mnie ścieżka, to oczywiście .NET (dostępne były jeszcze SQL i ITPro). Składała się ona z 6 sesji (jak z resztą wszystkie ścieżki):

1. Marek Byszewski – Tour de VSTS 2010. W prezentacji tej, jak nie trudno się domyślić, Marek opowiadał o nadchodzącym produkcie – TFS 2010. Temat na pewno ciekawy, jednak problemy techniczne z dostępną wersją skutecznie utrudniały prezentację. Do tego szkoda, że Marek nie opowiedział nic o rzeczach, które wymieniał na początku jako nowości. W związku z tym prezentacja samego TFS-a mogła wydawać się niektórym nudna. Mi szczerze powiedziawszy bardziej podobało się wystąpienie Marka na którymś WG.NET, kiedy opowiadał o aktualnej wersji Team Servera – było więcej, ciekawiej i bez problemów technicznych. Na uwagę zasługuje jednak temat historycznego debuggera, który pokazał Marek, to była zdecydowanie najciekawsza część całego wystąpienia.

Ocena 6/10 (byłoby więcej, ale niestety za mało było tam dla mnie nowości..)

2.Julia Lerman – My Favorite Entity Framework Tips & Tricks. Julie była pierwszą z zagranicznyhch gwiazd tegorocznego C2C. Jako osoba, prelegent Juli jest świetna. Jej prezentacja była dowcipna, ciekawa, a osobowość Julie – wręcz porywająca. Sam temat nie przypadł mi jednak do gustu. Po pierwsze, mało używałem w życiu Entity Framework, a po drugie nie lubię prezentacji typu T&T. Nie przemawiają do mnie tematy, które nie mają wyraźnej struktury – początku i końca. Wolę kompletne podejście do tematu, mimo że przez to czasem nie da się powiedzieć tak dużo.

Ocena 8/10 (głównie za porywający sposób prowadzenia prezentacji, a nie za temat niestety)

3. Piotr Leszczyński – Kolejny kontener Dependency Injection? NIE – dziękuję! Czyli o koncepcji meta-kontenera słów kilka. Piotrek to zwyciezca Speaker Idola na tegoroczny C2C i muszę przyznać, że wywiązał się z obowiązku znakomicie. Prezentacja była bardzo fajnie ułożona – logicznie uporządkowana. Najpierw parę (a w zasadzie trochę więcej) słów o koncepcji Dependency Injection, z czego bardzo się ucieszyłem. Do tego dużo kodu nagranego w postaci screencastów, dzięki czemu nie było efektu usypiania i czekania, aż coś zadziała. Świetnie zrealizowane! Druga część prezentacji dotyczyła już koncepcji meta-kontenera, która jednak mnie nie przekonała. Warto było jednak wysłuchać ciekawego podejścia do tematu.

Ocena 9/10 (za porządek, opanowanie i wiedzę)

4. Ingo Rammer – Hardcore Production Debugging of .NET Applications. Sesja drugiej z zagranicznych gwiazd okazała się prawdziwą rewelacją pod każdym względem. Była to zdecydowanie najlepsza prezentacja, jaką w życiu wysłuchałem. Ingo okazał się świetnym mówcą. Mówił ciekawie i dowcipnie. Nie pozwalał przysnąć nawet na moment. Sesja była bardzo praktyczna i dotyczyła debuggowania aplikacji za pomocą aplikacji z pakietu Debugging Tools for Windows. Nie było więc fajerwerków, a raczej sam command line, a mimo to było porywająco. Wielokrotnie podczas prezentacji bolał mnie brzuch ze śmiechu, a gdy nie było śmiesznie, to było fascynująco :) Geniusz pod każdym względem!

Ocena 11/10 (za wszystko!)

5. Udi Dahan – Avoid a Failed SOA – Business and Autonomous Components to the Rescue. Udiego nie trzeba chyba nikomu przedstawiać. To trzecia i ostatnia postać z zagranicy. Prezentacja Udiego była bardzo ciekawa i ładnie przygotowana. Dotyczyła ona podejścia do projektowania dużych systemów w duchu SOA. Muszę przyznać, że otworzyła mi ona oczy na wiele problemów, a do tego podsunęła efektywne rozwiązania. Szkoda tylko, że podczas prezentacji nie dało się zobaczyć nawet linijki kodu, albo chociaż przełożenia koncepcji PubSub na techniczną część problemu. Wystąpienie Udiego było również bardzo zabawne – Udi w roli mistrza Yody – majstersztyk :)

Ocena 10/10 (za kunszt :))

6. Artur Paluszyński – Interakcyjne sceny 3D w Windows Presentation Foundation. Artur to zwycięzca drugiej rundy Speaker Idola. Przypadła mu prezentacja na koniec – a więc wielkie wyzwanie nie uśpienia zmęczonych uczestników.. i świetnie mu się to udało! Artur pokazał coś, co dla mnie było całkowitym zaskoczeniem i nowością, gdyż nie spodziewałem się, że w WPF można realizować tak zaawansowane sceny 3D. Artur pokazał wiele ciekawych przykładów (button nawinięty na obrotowy walec.. :)), a do tego imponował wiedzą na temat.

Ocena 9/10 (za zainteresowanie mnie tematem)

Dodam jeszcze, że w czasie całej konferencji było masę atrakcji. Poza standardowymi rozmowami w przerwach między sesjami, były konkursy z nagrodami, możliwość pogadania z prelegentami i wiele innych.. Wszystko dopięte na ostatni guzik. Organizatorzy bili się w pierś, iż nie zorganizowali ciepłego posiłku dla uczestników (kryzys?), ale na korytarzu były stoiska z kawą, herbatą i kanapkami, więc żadnego problemu z wyżywieniem nie było.

W tym miejscu chciałbym pogratulować wszystkim organizatorom tej świetnej imprezy. Naprawdę jestem pod wrażeniem, że znalazło się tylu osób chętnych do przygotowania imprezy tak wielkiej skali. Chylę czoła i mam nadzieję, że w przyszłym roku będę mógł uczestniczyć w tym wspaniałym wydarzeniu z numerkiem 2010.

Ocena ogólna konferencji: mistrzostwo!

ASP.NET MVC 1.0 wydane!

W końcu! Na stronach Microsoftu dostępne jest do ściągnięcia ASP.NET MVC 1.0. To doskonała wiadomość dla wszystkich developerów ASP.NET, sam nie mogę się doczekać, aż dobiorę się do świeżutkiego release’a.

W związku z tym, z tego miejsca zapowiadam przepisanie mojego bloga (i udostępnienie źródeł) do ASP.NET MVC 1.0 :) Przy okazji polecam zapoznanie się z fragmentem książki, w którym można znaleźć kompletną instrukcję na temat tego, jak zbudować kompletną aplikację w ASP.NET MVC.

PS. W następnej notce zamieszczę relację z C2C 2009.

Polski serwis agregacyjny dla społeczności .NET!

dotnetomaniak.pl to pierwszy polski serwis agregacyjny przeznaczony dla programistów .NET. Działa on bardzo podobnie do dotnetkicks.com oraz dotnetshoutout.com. Tłumacząc po krótce – użytkownicy portalu dodają ciekawe, ich zdaniem, publikacje na temat platformy programistycznej MS, dzięki temu żadna ciekawa informacja/news nie umykają uwadze Dotnetomaniaków ;)

Źródło tego newsa – blog Pawła Łukasika, jednego z twórców dotnetomaniaka.

PS. Kiedyś miałem identyczny pomysł, jednak zaniechałem realizacji myśląc, że w Polsce się to nie przyjmie. Mam nadzieję jednak, że serwis odniesie wielki sukces :)

38. spotkanie WG.NET

Bez zaskoczenia – było rewelacyjnie :) 38. spotkanie WG.NET było spotkaniem łączonym ze spotkaniem PLSSUG, a ponadto wypakowane po brzegi ciekawymi prelekcjami :)

Pierwsze wystąpienie prowadził Bartosz Pampuch, członek KGD.NET i najlepszy prezenter MTS 2008! Ta jakże zacna persona przedstawiła temat pod tytułem „Skuteczny zespół informatyczny – czynniki sukcesu”. Prezentacja była całkiem „miękka”, a więc nietechniczna, jednakże bardzo ciekawa, upakowana informacjami, interaktywna i bardzo interesująco zrealizowana pod względem graficznym. Mówiąc krótko, miło było posłuchać, popatrzeć. Wystąpienie Bartka skłoniło mnie do bardzo wielu różnych refleksji i bardzo się z tego cieszę :)

Drugą prelekcje poprowadził Cezary Nolewajka (Senior Consultant działu MCS firmy Microsoft) , pt. „Visual Studio 2008 DB + GDR, czyli efektywna praca z projektami baz danych”. Prezentacja była przeznaczona dla bazodanowców, jednak jej przekaz był jasny i klarowny, na czym ja skorzystałem :) Czarek przedstawił bardzo interesujące narzędzie (VS 2008 w wersji DB z dodatkiem GDR) służące całej zabawie z SQL Server. Nie zapowiada się, bym miał kiedyś z tego korzystać, ale nigdy nic nie wiadomo (wiedzy technologicznej – branżowej, nigdy za wiele!). W każdym razie Czarek to bardzo dobry mówca, który bez trudu mnie i resztę publiczności zainteresował tematem.

38. spotkanie WG.NET uważam za bardzo bardzo udane. Na spotkaniu było bardzo dużo ludzi, aż żal że przerwa taka krótka – ale warto było ją poświęcić na tak ciekawe prelekcje. Na koniec dodam jeszcze, że w powietrzu czuć było zapaszek nadchodzącej konferencji C2C 2009.

37. spotkanie WG.NET

Tym razem – działo się :) Wszystko z powodu konferencji C2C 2009, która zbliża się wielkimi krokami (więcej na temat w następnych notkach).

Owym ważnym i ekscytującym wydarzeniem był Speaker Idol – konkurs organizowany przed większymi konferencjami (np. MTS) mający na celu wyłonienie nowych talentów (poprzez krótkie prezentacje), które mają potem szanse zaprezentować pełnowymiarową prelekcje na głównej konferencji. A to lista tego, co można było zobaczyć:

  1. Barbara Fusińska: Wzorce w akcji: Wyraź swoje intencje – doprecyzuj role;
  2. Jacek Ciereszko: Silverlight 2.0 Tips and Tricks;
  3. Andrzej Szczodrak: Nowe modele obiektowości w .NET;
  4. Szymon Pobiega: Service oriented architecture – event driven architecture;
  5. Piotr Leszczyński: Kolejny kontener DependencyInjection? NIE – dziękuję!! Czyli o koncepcji meta-kontenera słów kilka.

Jak widać po tytułach prezentacje były bardzo zróżnicowane i o różnym poziomie zaawansowanie. Moim faworytem był Jacek Ciereszko ze swoim niezawodnym Silverlightem, jednakże zwycięztwo przypadło Piotrowi Leszczyńskiemu.

Ogólnie inicjatywę oceniam bardzo pozytywnie. Prezentacje były ciekawe i bardzo różne, o nudzie nie mogło być mowy :) Szkoda tylko, że zgłoszeń było tak niewiele.. ale kto wie, może następnym razem i ja wezmę udział? ;)

Druga część wieczoru (zaraz po przerwie networkingowej) należała do Pawła Leśnikowskiego, który wystąpił z prezentacją pt. „Working with Legacy Code – PEX”. Paweł przedstawił bardzo ciekawe narzędzie – PEX, które służy do testowania i poznawania legacy code – czyli (w uproszczeniu) naprawdę nieprzyjemnego kodu :) Prezentacja była rzeczowa (ciekawe i rozbudowane dema) i dosyć krótka, ale zdecydowanie nie było to jej wadą. Dodam jeszcze, że narzędzie to bardzo mnie zainteresowało i cieszę się, że znajdzie się domyślnie w Visual Studio 2010.

Sesja zaczyna się za tydzień – jest co robić :) Także wracam do wyznaczników i całek, a w ferię postaram się napisać cokolwiek więcej.

36. spotkanie WG.NET

36. spotkanie było inne niż zwykle. No cóż, w końcu to ostatnie spotkanie przed Wigilią i Sylwestrem.

Tradycyjnie zaczęło się od krótkiego powitania (i rozdania eleganckich identyfikatorów! :) ), a następnie Arek WaśniewskiPaweł Potasiński zrobili krótki wstęp do dyskusji pt. „Rola aplikacji w dostępie do danych (z punktu widzenia .NET/SQL)”… a następnie zaczęło się :) Dyskusja była bardzo ciekawa, ale może głównie z tego powodu, że sporo tam było offtopowania, co moim zdaniem jak najbardziej posłużyło dyskusji. Szczególnie interesujące były fragmenty o SQL Injection oraz o ORM-ach :) Po 1.5 h bardzo luźnej pogadanki przyszła pora na Wigilię grup. Dużo ludzi, dużo jedzenia, świetna atmosfera… :) Gratulacje organizatorom, a w szczególności MS.