Reference Equality – co i jak

Tym wpisem chciałbym rozpocząć serię o trzewiach c# i ILAssembly. Ostatnimi czasy chyba dwa razy słyszałem pytanie, czym się różni operator == od metody Equals. Czy zawsze porównują referencję, czy to jest to samo? W tym wpisie chciałbym pokazać metody porównywania typów referencyjnych, dostępnych w c#. Również spojrzeć troszkę niżej i zobaczyć jak takie metody są zaimplementowane i jaki kod IL generują.

 

Więc na jakie sposoby możemy porównać dwa obiekty. Poniżej przedstawiłem wszystkie znane mi metody:

Jako że klasa Foo nie dostarcza nam, żadnej implementacji operatora == oraz metody Equals, wywoływane są bazowe z obiektu bazowego typu Object.

Operator ==

 

Operator == zawsze będzie porównywać referencję przekazanych obiektów. Na dowód tego, poniżej zamieściłem kod z IlSpy jaki został wygenerowany właśnie dla tego operatora.

Najważniejszym elementem powyższego kodu jest instrukcja ceq. Jak z dokumentacji wynika, ceq porównuje dwie wartości ze stosu, jeżeli są te same zwraca 1, w przeciwnym wypadku zwraca 0. W naszym przypadku wartościami są referencję do instancji klas Foo i dla nich następuje porównanie.

Metoda Equals

Jeżeli metoda Equals nie jest przeciążona, wywoływana jest metoda bazowa z klasy Object, metoda zwróci true w momencie gdy referencje obiektów będą te same. Zobaczmy jak ona jest zaimplementowana:

No jak widać nie za wiele widać. Atrybut MethodImplOptions.InternalCall  informuje nas, że implementacja metody jest w samym CLR. Jeszcze się nie doszukałem tego w kodzie cpp. Jak ktoś znajdzie dajcie znać.

Jeszcze kod w IL:

A więc potwierdzenie, wywołana metoda wirtualna Equals.

W tym linku znajdziemy potwierdzenie tego co napisałem, plus parę wskazówek kiedy i co najlepiej stosować.

Metoda Object.ReferenceEquals

Metoda statyczna klasy Object. Porównuje zawsze referencje. Na dowód tego kodzik źródłowy:

Wywołanie operatora ==. Jako że jest to metoda statyczna więc nie ma możliwości nadpisania jej w żaden sposób. Wywołując tą metodę mamy pewność, że zawsze wykonamy porównanie referencji.

Metoda Object.Equals

W pierwszej kolejności porównywana jest referencja. Następnie sprawdzane jest czy obiekty nie są null. Na końcu wywoływane jest Equals na pierwszej instancji.

Na podstawie powyższych przykładów można wyciągnąć jeden bardzo istotny wniosek.

Dla typów referencyjnych, jeżeli nie dostarczymy jawnych implementacji operatora == lub metody Equals, powyższe wywołania zawsze porównują referencję obiektów.

Dla potwierdzenia powyższego zaimplementujmy np. Equals:

I jeszcze porównanie za pomocą statycznej metody Equals:

Wynikiem tego porównania będzie oczywiście True. Jako, że operator == zwrócił False, oraz żadne z obiektów nie jest null, wykonana została metoda Equals. Jest ona przeciążona w klasie Bar, więc ta implementacja została wywołana.

Podsumowanie

W powyższym wpisie opisałem różne metody porównywania obiektów referencyjnych. Chciałbym nadmienić, że rozpatrywałem wyłącznie nasze implementacje. I zasada którą przytoczyłem dotyczy wyłącznie obiektów nie implementujących operatorów i metod. Należy o tym pamiętać. Zwrócić należny uwagę na np.  klasę string która posiada takie implementacje i niekoniecznie musi się zachowywać w dokładnie taki sam sposób. Omówienie klasy string zachowam sobie na inny wpis.

git log – optymalizacja

Iteruj po liście commitów, dla każdego commita na liście wyszukaj jego rodziców z tej samej listy. Połącz każdego rodzica z obecnym commitem obiektem Link.

Tak brzmi zadanie które musiałem zaimplementować w celu uzyskania pięknych kolorowych linii pomiędzy commitami na grafie.

Proste? Jasne. Szybkie 3 linijki w LINQ i mam! Mój projekt testowy ładuje się 3 ms! Genialnie!

A może podepnę jakieś firmowe repozytorium i zobaczę jaka będzie wydajność dla struktury o większej ilości commitów? Może zamiast 13 commitów, uruchomię to na 2200 commitach? Sure… czekamy…. czekamy. Umarło.

W dzisiejszym wpisie chciałbym przedstawić kilka podejść do implementacji tego zadania. Od najgorszego, po takie w którym rezultaty są zadowalające. Zastrzegam że nie musi być to koniecznie najlepsza implementacja. Po prostu lepszej mi się nie udało zrobić. Jeżeli widzisz jakieś potencjalne miejsca optymalizacji, pisz w komentarzu!

Zadanie zrealizowałem w pięciu różnych konfiguracjach:

  1. Kolekcja typu List, metoda wyszukująca LINQ
  2. Kolekcja typu Array, metoda wyszukująca LINQ
  3. Kolekcja typu Array, metoda wyszukująca Array.Find
  4. Kolekcja typu Array, klasyczne wyszukiwanie poprzez pętle for
  5. Kolekcja typu Dictionary, wyszukiwanie po kluczu słownika

Poniżej jeszcze sam obiekt Commit

Wynika z tego, że zawsze wyszukujemy po kluczu typu string.

Jeszcze w gwoli wstępu. Do pomiaru wydajności z każdych z metod użyłem frameworka benchmarkDotNet, naprawdę polecam. Dodatkowo posiłkowałem się kodem źródłowym c# dostępnym tu.

Podejście pierwsze

Pierwsze podejście najbardziej klasyczne, czyli lista i Linq. Zaletą Linq jest to, że jest wygodne, łatwo dostępne, ładnie wygląda. Wadą, są jego pierwsze dwie zalety. Dlaczego? Czasami wydaje mi się, że zbyt łatwa dostępność tego narzędzia sprawia, że ludzie przestają myśleć o implikacjach jego użycia. Nie zastanawiają się co siedzi pod spodem, dla jakich operacji, zadań jest ono dobre, a dla jakich nie.

Jaki problem może wynikać z tego kawałka kodu.

Rozszerzenie Where oraz metoda Contains. Obie te metody posiadają złożoność O(n), a co to oznacza? Przeszukiwanie liniowe, szukamy elementu, który spełnia nasze kryteria i zwracamy wynik. W przypadku Contains, wynik jest zwracany natychmiastowo po spełnieniu wymagań. W przypadku Where, iterowane są wszystkie elementy i zwrócona kolekcja poprawnych elementów. Można to podejrzeć w kodzie źródłowym c#:

Contains:

Contains to rozszerzenie metody IndexOf – który iteruje po każdym elemencie listy i porównuje go poprzez operator ==. Przypomnę, że operator ten w domyślnej implementacji zachowuje się tak samo jak Equals.

Where to tak naprawdę Extension na IEnumerable, które implementuje List. Poniżej kod źródłowy:

Tak jak w przypadku Contains,iterator przechodzi po każdym elemencie kolekcji sprawdzając predicate czyli warunek przekazany w wyrażeniu lambda. W tym przypadku jest to wynik metody Contains.

Drugie podejście

Jak widać różnicą jest jedynie przekazany typ. Tym razem użyta została tablica commtów. Jako, że tablice typów dziedziczą po typie Array, który jest z kolei klasą abstrakcyjną implementującą IEnumerable, mamy dostęp do Linq. Implementacja Where wygląda następująco:

Wywoływana jest dokładnie ta sama metoda Where rozszerzająca typ IEnumerable. Istotna w tym przypadku jest ta linijka:

A więc sprawdzenie czy typem na którym operujemy jest tablica. Jeżeli tak zwracamy WhereArrayIterator.

Tak jak mogło by się spodziewać w tym przypadku została wykorzystała „natywna” operacja dostępu do elementu poprzez index. I jest to jedyna różnica w implementacji metody MoveNext.

Trzecie podejście

Klasyczne podejście przy operacjach na tablicach. Tak nas uczyli na studiach. Brak Linq i innych „magii”. Nic szczególnego się tu nie dzieje więc przejdę dalej.

Czwarte podejście

Tutaj wykorzystałem dedykowaną metodę z obiektu Array. Można by pomyśleć, że to dobry pomysł. Zobaczmy co siedzi w środku:

Cóż my tu mamy. Na pierwszy rzut oka widać, że wykorzystanie tej metody nie jest najlepszym pomysłem. Zachowuje się jak powyższe przykłady, dodatkowo tymczasowa lista jest ponownie konwertowana na tablicę za pomocą ToArray. Można się spodziewać wyższego zużycia pamięci przy tym podejściu.

Piąte podejście

W ostatnim podejściu zastosowałem Dictionary. Jako, że w zadaniu głównie chodzi o wyszukiwanie commitów po kluczu, można się spodziewać, że ten typ będzie idealny do tego zadania. Jeżeli chodzi o wydajność wyszukiwania. MSDN informuje, że złożoność przy wyszukiwaniu po kluczu zbliżona jest do O(1). Zobaczmy jak to jest zaimplementowane:

Widać wyraźnie dlaczego operacja pobrania wartości na podstawie klucza nie jest ani O(1) ani O(n). Dzięki zastosowaniu hasha naszego klucza, ilość iteracji na kolekcji jest maksymalnie ograniczona.

Wydajność

Tak jak już wcześniej wspomniałem, testy przeprowadziłem za pomocą frameworka benchmarkDotNet. Przeprowadziłem trzy testy na różnej wielkości repozytoriach.

Benchmark – 13 commitów
Benchmark – 514 commitów
Benchmark – 2144 commitów

Chyba nikogo nie zaskoczyły powyższe wyniki. Najwydajniejszym podejściem w tym zadaniu jest zastosowanie Dictionary. Szybki dostęp do zasobu dzięki zastosowaniu hash powoduje, że różnica z podejściami opartymi na liniowym przeszukiwaniu jest kolosalna.

Z pozoru „najbrzydsze”, klasyczne podejście z użyciem pętli for również wychodzi o niebo lepiej niż pozostałe metody. W tym przypadku wyszukiwanie również jest liniowe. Wydaje mi się że na wydajność w tym przypadku ma wpływ przede wszystkim prostota rozwiązania, szybki dostęp do zasobu poprzez Index tablicy i niski współczynnik alokacji pamięci.

No właśnie, a co z pamięcią. Tak jak wspomniałem w punkcie przedstawiającym podejście z Array.FindAll, zużycie pamięci w tym przypadku jest największe. Tak jak w przypadku wydajności, ilość za alokowanej w przypadku Dictionary oraz „klasycznego” podejścia jest najniższa.

Uwaga na koniec – zaalokowana pamięć nie jest tylko wynikiem wyszukiwania i iteracji po kolekcjach. Każde podejście wywoływało metodę CreateLinks która dodawała do listy nowe linki. Metoda była wywoływana tyle samo razy. Więc ilość pamięci za alokowanej w tym przypadku nie jest miarodajną wartością. Należało by w tym przypadku wyskalować te wartości do najwyższej.

Method Alocated Scaled %
Run_LinqApproach 0,08 100
Run_DictionaryApproach 0,03 37,5
Run_ArrayApproach_WithLinq 0,07 87,5
Run_ArrayApproach_WithForLoopSearching 0,03 37,5
Run_ArrayApproach_WithArrayFindAllMethod 0,09 112,5

Przygotowanie danych

Podczas recenzji tego wpisu zwrócono mi uwagę, zadano pytanie. A co z przygotowaniem danych? Przecież takie Dictionary należy wcześniej przygotować. Na szczęście pomiar zajął mi kilka chwil. Poniżej wyniki:

Czas konwersji listy 2144 commitów na odpowiedni typ

Te kolekcje są na tyle małe, że czasy konwersji na odpowiedni typ jest znikomy. Zsumowanie obydwu wartości i tak nie zmienia wyników na tyle aby rozważać jeszcze ten aspekt.

Podsumowanie

Wiele się nauczyłem przy tym prostym zadaniu. Wydaje mi się, że problem jaki dzisiaj poruszyłem jest dość często spotykanym problemem w naszej pracy. Jak dobrać strukturę danych i algorytm aby zadanie było wydajne? Ważne jest aby sprawdzać zaimplementowane rzeczy na większej ilości danych. Żeby nie trzeba było mówić „u mnie działa”. Działa bo lista zawiera 20 elementów albo ilość produktów w DB to 4.

Przede wszystkim musimy też wiedzieć jak coś jest zbudowane. To, że Linq jest łatwo dostępne i łatwe w u życiu nie oznacza, że jest to remedium na wszystkie nasze problemy. Zanim użyjesz, zastanów się, czy przypadkiem nie będzie lepszego rozwiązania. Tak jak w tym przypadku, znalazłem ich 5, a wydaje mi się, że jest ich jeszcze wiele, wiele więcej.

Od momentu gdy .NET wszedł do świata open source, poznawanie wewnętrznej implementacji stało się dużo łatwiejsze. Nie trzeba już nic dekompilować aby poznać szczegóły, wystarczy wejść na https://referencesource.microsoft.com.

gitWeb – branching cz.2

W dzisiejszym wpisie chciałbym omówić kolejne funkcjonalności modułu odpowiedzialnego za branching. W poprzednim wpisie opisałem następujące kwestie:

  • Lista branchy
  • Tworzenie nowego brancha

Dzisiaj skupię się na:

  • Checkout – przełączanie się pomiędzy branchami
  • Pobranie drzewa comitów dla aktualnego brancha
  • Opisanie na drzewie commitów, dostępnych branchy

Checkout

Git

Podstawowa funkcjonalność gita, bez której nie da się działać pracując w środowisku z wieloma branchami. Pozwala na przełączenie się pomiędzy dwoma branchami. W konsoli operacja dostępna pod komendą:

Najważniejsze kwestie jakie należy wziąć pod uwagę korzystając z tej komendy to:

  • Wszystkie zmiany, które posiadamy na aktualnym branchu przeniosą się na nowy branch. Oczywiście, jeżeli wystąpi konflikt to zostaniemy o tym poinformowani.
  • Przełączenie się na nowy branch powoduje, że HEAD repozytorium ustawi się na Tip danego brancha. Innymi słowy, zostanie pobrany stan repozytorium z najnowszego commita na nowym branchu.

Tip w branchu, jest to najnowszy commit zrobiony na danym branchu.

VueJs

Po stronie widoku za wiele się nie dzieje. Wywołane kolejne akcje, które na końcu wywołują API. Jedyną rzeczą, na którą chciałem zwrócić uwagę jest główny plik actions.js w sekcji store.

Generalnie chciałem zmodularyzować Vuex w obrębie głównych komponentów Vue. A więc, miałem moduł Vuex branchArea.js, który odpowiadał komponentowi branch.vue, itd.

Aby była możliwa komunikacja między tymi modułami, wydzieliłem nadrzędne miejsce, w którym akcje będą je spajać.

W tym konkretnym przypadku akcja checkout znajduje się w pliku nadrzędnym actions.js, a sama akcja prezentuje się następująco:

Wywołana sekwencja kolejnych akcji. W pierwszej kolejności wywoływany jest CHECKOUT_BRANCH na wskazanym przez użytkownika branchu. W momencie gdy operacja zakończy się sukcesem wywoływana jest akcja GET_COMMIT_TREE_FROM_HEAD, która pobiera listę commitów, zaczynając od HEAD „nowego” brancha. Na samym końcu wywoływane jest builder odpowiedzialny za kompozycję grafu.

Api

Aby przełączyć branch należy odwołać się do:

Sam kontroler wygląda tak samo jak w poprzednich wpisach, a więc przejdę od razu do właściwej implementacji przy pomocy libgit2sharp:

I pojawia się… Magiczne Commands. Z jakiegoś powodu autorzy biblioteki postanowili, że wydzielą część funkcjonalności do statycznych metod. Oczywiście, to jest OS projekt i rozumiem dlaczego wszystko co miało by trafić do commands, jeszcze tam nie trafiło. Ja mam z tym jeden problem, mianowicie dość ciężko do statycznych metod pisze się testy, trzeba je oklejać jakimiś wrapperami, żeby móc mockować takie wywołania.

Poza tym kawałek kodu dość standardowy, parę sprawdzeń warunków brzegowych, zwrócenie NullObject w momencie gdy branch nie istnieje i translacja do obiektu DTO.

Pobranie drzewa commitów dla aktualnego brancha

Tu sprawa wygląda bardzo prosto. Komenda:

pobiera zawszę listę commitów zaczynając od HEAD aktualnego brancha, na którym się znajdujemy.

Pobieranie listy commitów oraz budowanie z nich branchy opisałem we wpisie dotyczącym komendy git log –graph, serdecznie do niego zapraszam.

Opisanie na drzewie commitów branchy

Na powyższym gifie w prawej stronie widać skromnie wyglądające labele BRANCH. Reprezentują one „status” aktualnego brancha. A więc pokazują się tam wszystkie branche przypisane do commita „widocznego” z poziomu obecnego brancha.

Zadanie do zrealizowania może brzmieć następująco:

Pokaż wszystkie branche których najnowszy commit znajduje się na grafie aktualnego brancha.

Powyższa metoda robi dwie rzeczy. W pierwszej kolejności pobrana jest lista commitów dla aktualnego brancha. Następnie pobrany jest Tip każdego dostępnego brancha. Mając te dwie informacje możemy w prosty sposób zmapować te dwie kolekcje.

Podsumowanie

Komponent zbudowany… ale nie kompletny. Brakuje w nim jeszcze wielu, wielu rzeczy. Między innymi zmiana nazwy, usuwanie, „śledzenie” branchy zdalnych. Operacja Checkout wiąże się również z konfliktami i mergowaniem. Jak widać sporo pracy jeszcze przede mną.

W tych dwóch wpisach opisałem budowę jednego z wielu komponentów, które będą budować moją aplikację. Oprócz samego opisywania kodu, chciałem również wrzucić troszkę teorii dotyczącej samego gita. Chciałbym w dalszym ciągu pisać w takiej konwencji. Dzięki temu mam zamiar wprowadzić trochę urozmaicenia i ciekawej wiedzy we wpisy.

W tym momencie kończę kolejny spory moduł. Jeszcze przed świętami chciałbym opisać część dotyczącą tworzenia commitów i podglądu zmian w plikach.

gitWeb – branching cz.1

W dzisiejszym wpisie opiszę jak zrealizowałem branchowanie w mojej aplikacji.

Na powyższym  gifie widzimy wszystkie funkcjonalności, które udało mi się do tej pory zrealizować. A są to:

  • Lista branchy
  • Stworzenie nowego brancha
  • Przełączenie się na inny branch
  • Pobranie drzewa comitów dla aktualnego brancha
  • Opisanie na drzewie commitów branchy

W tym wpisie opiszę kompletną ścieżkę implementacji od frontendu do wywołania biblioteki libgit2sharp. Podzielę to na 3 sekcje:

  • komenda jaką należy wykonać w konsoli gita
  • moduł VueJs
  • API wraz z implementacją libgit2sharp.

Jako, że każdy z elementów jest obszerny dzisiaj skupie się jedynie na opisie listy branchy i sposobie w jaki udało mi się zaimplementować dodanie nowego brancha.

Lista branchy

Za pomocą tej komendy w konsoli pokażą się wszystkie branche w repozytorium. Zarówno te lokalne jak i „śledzące” zdalne. Dodatkowo dostajemy informację na którym branchu obecnie się znajdujemy.

Komponent VueJs

Lista zaimplementowana została w komponencie o nazwie branch.vue. Nie chcę wklejać tu całego komponentu bo nie będzie to miało sensu. Wkleję jedynie najważniejsze kawałki odpowiedzialne za pobranie listy branych i ich wyświetlenie.

Pobranie danych odbywa się w następujący sposób:

Funkcja beforeMount wywoływana jest przed umieszczeniem komponentu na widoku. Jest to mój punkt wejściowy do aplikacji. Zostanie on nim dopóki nie wymyślę lepszego punktu wejściowego. Funkja jest bardzo prosta wywołuje ona akcję Vuex o nazwie GET_ALL_BRANCHES.

Jak widać akcja jest również prosta. Wywołany zostaje serwis, który odpytuje  WebApi. W przypadku poprawnego pobrania danych przekazywane są one do mutacji SET_ALL_BRANCHES. Ustawia ona stan aplikacji zgodnie z tym, jak powinno się to robić korzystając z Vuex. Tylko mutacje powinny zmieniać stan aplikacji.

Sam serwis do komunikacji wygląda następująco:

 

Jak widać wszystko jest dość przejrzyste i proste. Chciałbym aby cała aplikacja tak wyglądała 😉

API

Po stronie backendu funkcjonalności dotyczące branchy wystawione są za pomocą API w kontrolerze BranchController.cs.

Jeżeli chodzi o samo API wybrałem REST ze względu na to, że jest teraz super fancy i modny. A tak na serio to dzięki tej aplikacji chciałbym poznać to podejście. Jego wady, zalety, ograniczenia.

No więc lista branchy dostępna jest pod:

a sam kontroler jest zaimplementowany maksymalnie prosto:

Jak widać nic szczególnego, wstrzyknięty jedynie odpowiedni provider odpowiedzialny za obsługę branchów. Sam provider wygląda tak:

Ot i pierwsze spotkanie z libgit2Sharp. Jeszcze nie opisywałem tej biblioteki. Do providera wstrzykiwany jest obiekt typu IRepository. Jest to interfejs pochodzący właśnie z tej biblioteki. Stanowi on swoiste serce całego frameworka. Reprezentuje on repozytorium gita. Dzięki temu obiektowi mamy dostęp do prawie wszystkich (opiszę w kolejnych wpisach) operacji i zasobów, które możemy wywołać na repozytorium.

W tym konkretnym  przypadku pobranie listy branchy sprowadza się do zwykłej projekcji w Linq na kolekcji Branches. Klasa Branch jest moją klasą. Chciałem ograniczyć ilość zależności w aplikacji do minimum. Dlatego postanowiłem, że nie będę korzystał z dostępnych w bibliotece typów tylko stworze własne obiekty DTO. Dzięki temu podejściu zależność do libgit2Sharp mam wyłącznie w projekcie gitWeb.Core. Kontrolery nic nie wiedzą jaki provider do gita czy innego typu repozytorium jest wykorzystywany. Otwiera to furtkę do implementacji innych systemów kontroli wersji jak np Mercurial czy SVN bez konieczności większych zmian w aplikacji.

Nowy branch

Podstawowa komendą do stworzenia nowego brancha jest:

Oczywiście jest całe mnóstwo opcji, które można wykorzystać do jego stworzenia, ale w obecnej fazie wykorzystuję tą podstawową.

Dodatkowo, tworzone branche nie odwołują się do żadnego zdalnego brancha. Tą funkcjonalność dorobię w ramach Push i Pull.

Komponent VueJs

Do komponentu branch.vue musiałem dodać mini formularz który umożliwi mi wpisanie nazwy nowego brancha.

 

Po stronie komponentu do obsługi tworzenia nowego brancha mamy 2 funkcję:

clearCreationForm – prosta funkcja do czyszczenia stanu.

createBranch – tak jak w przypadku listy branchy, komponenty delegują całą logikę dotyczącą komunikacją z API do Vuex. A więc w tym przypadku wywołujemy akację CREATE_NEW_BRANCH. Przyjmuje ona jako parametr nazwę nowego brancha. Jeżeli operacja tworzenia przebiegnie pomyślnie, czyszczona jest forma z danymi.

Sama akcja w Vuex jest już bardziej skomplikowana:

Więc co tu się dzieje? Tak jak wspomniałem wcześniej, na początku wywoływana jest akcja CREATE_NEW_BRANCH. Akcja ta wywołuje serwis który z kolei wywołuje metodę API do stworzenia brancha. Jeżeli wszystko pójdzie zgodnie z planem to wywoływana jest akcja CHECKOUT_BRANCH.

W tej fazie projektu nowy branch jest automatycznie checkoutowany. I tak samo, jeżeli wszystko będzie w porządku to wywoływana jest (opisana wcześniej) akcja GET_ALL_BRANCHES.

W tym wpisie nie będę opisywał procesu checkoutowania., poświecę na niego osobny wpis.

Serwis odpowiedzialny za odwołanie się do API został zaimplementowany następująco:

API

Stworzyć nowy branch możemy odwołując się do poniższego zasobu:

Szybkie spojrzenie na kontroler oraz branchProvider:

W podstawowej formie żeby stworzyć branch należy jedynie wywołać metodę CreateBranch na obiekcie repozytorium oraz przekazać nazwę jako parametr.

Podsumowanie

Dzisiejszym wpisem rozpocząłem serię dotyczącą implementacji poszczególnych elementów projektu. Już powoli zaczyna coś działać! Strasznie mnie to nakręca do dalszego działania.

Widać wyraźnie, że biblioteka libgit2sharp jest naprawdę prosta w użyciu. Samo opisujące się metody i prosty interfejs sprawia, że bardzo dobrze się z niego korzysta. Dodatkowo community (github, stackOverflow) jest dość potężne, więc nie ma też problemu z rozwiązywaniem ewentualnych problemów czy błędów w samej bibliotece.

W kolejnym wpisie opisze kolejne części branchingu – a więc checkout brancha, zmianę nazwy oraz usunięcie.

4Developers 2017

To był bardzo bardzo ale to bardzo długi dzień.

Trudne początki

Co może być trudnego w dojeździe rano z Zabrza do Katowic? Hmm większość powie, że nic. Dzisiaj na własnej skórze przekonałem się, że z jednego przystanku autobusowego, ta sama linia może jechać w dwa różne kierunki. Tak, wsiadłem w ten zły… No ale przecież chill, 5 rano, godzina do odjazdu pociągu, a ja jestem na jakimś odludziu, chyba w rudzie śląskiej. Na szczęście jedyne 80 zł wydane na taksówkę i byłem w pociągu. Istny koszmar!

No ale to miała być relacja z konferencji więc zacznijmy.

Sama konferencja od samego początku robiła na mnie spore wrażenie. Ilość uczestników ~1500, 14 ścieżek tematycznych. Bardzo byłem ciekaw czy organizatorzy podołają temu szalenie trudnemu zadaniu.

Rejestracja

Na wstępie, genialna sprawa z tym, że była możliwość wcześniejszego odebrania wejściówki, nie w dniu samego wydarzenia. Wydaje mi się że dzięki temu zabiegowi czekaliśmy w kolejce jedynie parę minut! Jak na tyle osób zarejestrowanych, rewelacja!

Konferencja znajdowała się w hotelu niedaleko lotniska Chopina. Bardzo dobry dojazd ale… jednak to jest ponad 1500 osób i nie wydaje mi się, że to był odpowiedni obiekt na taką rzeszę ludu. Później jednak sobie pomyślałem, że mało jest takich miejsc odpowiednich do tego typu imprez, więc postanowiłem nie pastwić się nad tym aspektem.

Prelekcje

To po co tu przyjechałem a więc wiedza, dużo wiedzy.

Consumer-Driven Contractsna ten wykład niestety nie udało mi się zdążyć, byłem jedynie na ostatnich 10 minutach, a szkoda bo po pytaniach jakie padały w tym czasie, odniosłem wrażenie, że bardzo ciekawy temat poruszył Jędrzej.

Public enemy No. 1, mid-sized building blocks and hexagonal architecture in real life – Bardzo ciekawa prezentacja, pokazująca jak komponować, organizować nasz projekt. Niestety wydaje mi się, że problemem z tą prezentacją było zbyt mocne przywiązanie do technologii. Jakub prezentował wszystko na przykładach z Javy. Wydaje mi się, że było tego za dużo, jednak ścieżka architektury powinna wystawać ponad szczegóły implementacje danego języka czy frameworka.  Oczywiście nie miałem większego problemu zrozumieć jaki był ogólny przekaz tej prezentacji ale lekki niesmak pozostał.

Azure Service Fabric czyli wszędobylskie mikroserwisy – Tak jak już kiedyś wspominałem, nie za bardzo lubię tego typu prezentacje. Lubię prezentacje nastawione na problem, a nie na produkt. Ale poszedłem na nią aby „liznąć” troszkę tej technologii. Dużo o niej słyszałem od kolegi Szymona i postanowiłem zobaczyć co to takiego. Tym razem się nie zawiodłem. Rzetelnie poprowadzona, ciekawa prezentacja. Zdecydowanie na plus.

.NET Core w 2017 – Łukasz przekazał nam usystematyzowaną wiedzę na temat tego wszystkiego co się dzieje w MS w obrębie .NET. Jak wszyscy wiemy dzieje się sporo, i tego dobrego i złego. Super, że chciało mu się to wszystko ogarnąć i przekazać nam w tak dobry sposób!

Obiad – jak do tej pory byłem całkiem dobrze nastawiony, to jak przyszedł moment obiadu to jakoś wszystko przestało mieć znaczenia. To wszystko co wyżej pisałem słabawa lokalizacjia i milion ludzi sprawiło, że obiad przerodził się w jeden wielki dramat. Kolejki były wszędzie i nie wiadomo było gdzie stać. Niestety ale ten punkt uważam za najsłabszy w całym dniu. Choć sam obiad bardzo smaczny 😉 ale tu były bardzo skrajne opinię wśród kolegów również.

Ale poniżej kolejna duży minus.

JIT me baby one more time – Kurde w sposób w jakiś rozeszła się informacja o przesunięciu tej prelekcji godzinę wcześniej, dawał wiele do życzenia. Pytanie do organizatorów. Czy było jakieś info o przesunięciu na twiterze? Ja nie widziałem. Przecież to jest główne medium przekazu obecnie. Nawet mieliście taki telewizor co pokazywał „ćwierknięcia” Kurczę wiele osób czekało na występ Jarka. I jak przyszli to dowiedzieli się, że był godzinę wcześniej. C’mon!

Co do samej prezentacji – po raz kolejny najwyższy poziom! chapeau bas! Mimo, że nie siedzę w Javie, a w .NET poszedłem na tą prezkę. Ze względu właśnie na Jarka, a także na tematykę. Chciałem wiedzieć jak to „u Was” się robi. Było bardzo dobrze. Szkoda tylko, że tak krótko.

The only thing that matters – Szymon zapewniał, że będą żarty i będzie lepiej niż na BoilingFrogs (chociaż uważam, że było bardzo dobrze nic nie brakowało). Żart z krową mega! Sama prezentacja też wydaje mi się lepsza. Wiele kwestii zostało rozwiniętych dzięki czemu to co mówił Szymon było łatwiejsze do przyswojenia. Takich prezentacji powinno być zdecydowanie więcej. Mniej nowości z nowych Angularów więcej technicznych rzeczy proszę! Jedyną rzecz, i tu nie wiem do kogo to adresować. Zarówno część widowni jak i pewnie sam Szymon odczuł to, że ta prezentacja nie była o .NET!!!!!!!!!!!! i nie wiem czemu była na tej ścieżce. Naprawdę. Zdecydowanie lepiej by się wpasowała w jedną ze ścieżek Arch.

Po tej prezentacji naszło mnie takie zmęczenie, że już nie uczestniczyłem w pełnych prelekcjach. Chodziłem po salach i słuchałem po parę minut każdej. Z tego co zaobserwowałem to, że poziom był naprawdę wysoki. Dużo technicznych prezentacji, poruszających ciekawe problemy wydajnościowe, architektoniczne. Bardzo fajnie.

Na koniec został panel dyskusyjny Bottegi. Panowie, nieźle nieźle, trzeba przyznać, że bardzo dobrze się Was słucha. Dodatkowo publika była bardzo chętna do zadawania dobrych pytań! Szkoda tylko, że nie było Sławka Sobótki ;(

Podsumowanie

Wyjeżdżałem z Warszawy z mieszanymi uczuciami. Z jednej strony bardzo dobre prelekcje, dużo się dowiedziałem. Spotkałem kupę znajomych, przeprowadziłem sporo ciekawych rozmów. Z drugiej strony ten tłok i lekkie kłopoty organizacyjne – głównie obiad. Mimo wszystko uważam, że konferencja była dobra. Tylko nie wiem czy iście w tak dużą ilość osób jest dobrym pomysłem, no ale to już nie ode mnie zależy. Na pewno zjawie się za rok !

Gotowane żabki

161Jak to mówią praktyka czyni mistrza, idąc z duchem tego przysłowia postanowiłem napisać słów kilka o konferencji BoilingFrogs która odbyła się w ten weekend.

O konferencji dowiedziałem się stosunkowo niedawno, parę dni przed kupnem biletu, z tego tez powodu nie miałem jakiś specjalnych oczekiwań co do niej. Lecz szybki rzut oka na agendę i już wiedziałem że może być nieźle. Zacznijmy więc:

Rejestracja

Organizatorzy mówili że było koło tysiąca uczestników (sic!), i wiecie co? albo kłamali (nie wydaje mi się) albo doprowadzili proces rejestracji do perfekcji. Zjawiliśmy się na miejscu około godziny 8:30 z przekonaniem że będzie dramat, kolejki, ścisk pełno ludzi. Jakie było nasze zdziwienie jak zostaliśmy obsłużenie w niecałe 3 min. Perfecto. Skala, to jest dobre słowo. jak jest dużo osób to musi być dużo stanowisk rejestracyjnych, tym powinni się kierować min. organizatorzy konferencji DeveloperDays (rejestracyjny koszmar).

Jedzonko

Stosunkowo niski koszt konferencji nie nastawiał mnie na jakieś mega jedzenie. Po raz kolejny moje przeczucia były mylne. Jeżeli chodzi o dostępność kawy, przekąsek i dostęp do obiadu ( wiadomo jakieś kolejki muszą być) było bardzo dobrze. Kolejna piątka.

Prelekcje prelekcje jeszcze raz prelekcje

Clean architecture: co z tego możesz wziąć dla siebie? Mariusz Sieraczkiewicz – Szedłem na tą prelekcję z otwartą głową, nie wiedziałem czego się spodziewać, Mariusza nie znałem wcześniej. Szczerze mówiąc nie porwało mnie to niestety. Od początku nietrafiona byłą dla mnie i nie pasująca do całości anegdota do AI, a później nie było lepiej. Podstawy podstaw, niestety nic ciekawego nie potrafiłem wynieść z tej prezentacji. Nie wiem czemu, teoretycznie było wszytko co miało być, dobra dykcja, porządne slajdy, no ale sam content jakimś taki mizerny w moim odczuciu.

Back to forgotten roots Mariusz Gil – bardzo ciekawa osoba, dobrze mi się Mariusza słuchało. Na tyle dobrze że nie pamiętam o czym mówił ;D

Deweloper na detoksie Michał Płachta – ciekawie ciekawie, bardzo fajna forma prowadzenia prezentacji. Problem wyborów jakie podejmuje każdy developer sprowadzony do postaci pikselowego Jana. Super. Tylko szkoda że w końcu nie padła odpowiedź jaki wybór powinien Jan wybrać.

SLA i utrzymanie mikroserwisów Jakub Kubryński – Jakuba kojarzę już z jakieś konferencji ale nie pamiętam dokładnie jakiej. Bardzo dobra dykcja, prezencja i przygotowanie. Temat? hmm dla osób które siedzę w mikroerwisach może wydawać się banalny, oczywisty, taka osoba możliwe że mało co wyciągnie z tej prezentacji, poza paroma ciekawostkami. Dla mnie? Jako laik w sprawie mikro-serwisów muszę stwierdzić, że jak zaczynasz przygodę z tym podejściem, zobacz sobie prezentację. Wiele .tych banałów było wytłumaczone w porządny sposób z przykładami.

Data i czas dla programistów Michał Pipa – do tej prezentacji podszedłem sceptycznie, nie chciałem na nią iść bo wydawało mi się, ale nuda, chciałem iść na równoległą prelekcję z testami jednostkowymi. Jakież było moje zdziwienie po zakończeniu. No słów brak. Zaczynając od samego prowadzącego Michała, kurde taks obie wyobrażam gościa od Linucha, hejt na Windows przede wszystkim. Wysokie poczucie humoru połączone z ogromną wiedzą. A sam temat, tyle rzeczy to na całej konferencji nie dowiedziałem się co na tej prelekcji. Super.

The only thing that matters Szymon Kulec – człowiek z którym niejeden marzy pracować. Takiej wiedzy to jeszcze u nikogo nie widziałem. Poznałem Szymona na dotnetconf, gdzie mówił o programowaniu współbieżnym, wtedy już wydawało mi się że to demon wiedzy. Tak jak wtedy nie zawiodłem się, zdecydowanie najtrudniejsza prezentacja na konferencji. Poruszenie kwestii o których większość developerów nawet nie myśli. Przestawiona została w naprawdę przystępnej formie.

Memento Memori Konrad Kokosa – również czekałem bardzo na to co powie nam Konrad. Kolejna osoba która w moich oczach „wymiata”, jak po Szymonie nie do końca wiedziałem o czym będzie mówił, tak u Konrada to był pewnik Internals internal internals. Tak też się stało, 45 min przykładów i ciekawostek które na pewno otworzą mi oczy.

Podsumowanie

Zaskoczenie, to mało powiedziane, naprawdę jechałem tam z nastawieniem że ok, będzie spoko, ale to co tam zobaczyłem, ile ludzi poznałem przerosła moje najskrytsze oczekiwania. Super było też spotkać parę osób z naszego DevSlacka ;D A za tydzień Wroc# zobaczymy, poprzeczka w tym roku bardzo wysoko podniesiona.