Subiektywnie o Lenovo Yoga700

Szukałem ostatnio sprzętu, który pozwoli mi uniezależnić się od stacjonarki. Postanowiłem nie iść w stronę klasycznego laptopa, a nabyć coś sprytniejszego. Wybór padł na Lenovo Yoga 700. Głównie przemawiały do mnie dotykowy ekran i „yoga transformacje”. Sprzęt nabyłem z pół roku temu, więc zdążyłem się już oswoić  z wieloma rzeczami. Super entuzjazm nie jest już taki super. Wielkie rozczarowania nie są już takie wielkie. Post ten postanowiłem napisać aby podzielić się swoimi spostrzeżeniami, których nie wyczytasz ze specyfikacji i nie znajdziesz w recenzjach ludzi, którzy dostali sprzęt tylko na tydzień i odpalili tonę testów. Nie będę pisał o parametrach sprzętu. Procesor, pamięć, grafikę itd. dobrałem do swoich potrzeb i one definitywnie robią robotę. Jeżeli jesteś ciekawy parametrów to opisuję sprzęt: Yoga700, a dokładniej Lenovo Yoga 700 14 i7-6500U/8GB/256/Win10 GT940M Srebrny.

Dotyk w laptopie

Matryca dotykowa to definitywnie jest mój ulubiony feature. Świetnie uzupełnia touchpad’a i zupełnie uwalnia od potrzeby posiadania myszki.

Mam już Asus’a Transformers’a, w którym zdecydowanie lubiłem dotyk, ale w Windowsie 8.1 jeszcze coś nie grało. Poza tym Asus okazał się zupełnie za słaby względem moich potrzeb, więc sprezentowałem go żonie. Jako tablet+, czyli sprzęt do przeglądania internetu, pisania postów, tworzenia dokumentów i puszczania dzieciom bajek, asus transformer daje radę. Może o nim też kiedyś wystukam jakiegoś posta.

Wracając do Yogi700 Windows 10 z dotykiem zdecydowanie uwalnia dodatkowy potencjał. Minusem dotykowej matrycy podobno może być „brzydki, opalcowany ekran”. Ja tego nie kupuje. Fakt faktem paluchy poodbijane są wszędzie, ale widać to tylko w trybie off. Nie jestem człowiekiem, któremu to w jakikolwiek sposób przeszkadza. Jedynym minusem jest efekt uboczny takiego featura. Łapie się na tym, że jeżeli tylko wyląduje przed klasycznym laptopem to gdy tylko się zapomnę próbuję coś zdziałać dotykiem:). Nawet ostatnio zwykły monitor zaczynam głaskać.

Niespodzianka z klawiaturą

Śmieszną niespodzianką i minusem jakiego nie byłem w stanie przełknąć jest klawiatura, a dokładnie jej górna część (cała reszta chodzi super, klawisze aż się palą od stukania). Lenovo wymyśliło sobie, że jak większość sprzętu pod przyciskami F1…F12 zrobią sobie dodatkowe przyciski funkcyjne. Rozwiązanie raczej standardowe, dla mnie przydatne. Jeżeli tylko da się ustać klasyczne efki jako domyślne, a dodatkowe w kombinacji z przyciskiem FN (funkcyjnym) to dla mnie super. Problem w tym, że Lenovo wymyśliło sobie też, że pod ESC również zrobią dodatkowy przycisk funkcyjny, który pozwoli przełączać tryb ekranu. Po uruchomieniu ultrabooka domyślnie pod F1..F12 mamy te dodatkowe funkcje, a dopiero w kombinacji z FN klasyczne. ESC działa normalnie, a z FN zmienia tryb ekranu. Ponieważ jednak do programowania wolę mięć klasyczne efki na pierwszym planie, więc w pierwszej kolejności postanowiłem to przełączyć.  I tu „niespodziewanka”! Dobre lenovo tak ustawiło sprzęt, że po takim switch’u zamiast klasycznego ESC mam zmianę trybu ekrakranu. Musze klikać FN+ESC, żeby np. zmieniać tryb w Vim’ie!!!

Yoga700 keyboard

Okazało się, że nie da się tego zmienić. Są jakieś poprawki w biosie bodajże, ale nie dotyczą mojego sprzętu. Myślałem, że zwariuję. Już miałem sprzęt oddać! Nienawidzę takiej wtopy! Do tej pory nie udało mi się tego naprawić, ale już praktycznie nie szukam rozwiązania. Ponieważ, nie chciałem klikać ani FN+F5 do kompilacji, ani FN+ESC dla zwykłej ucieczki  trzeba było coś wymyślić. Z pomocą przyszedł trik vim’owców, który już dawno chciałem wypróbować.  Przy pomocy programu SharpKeys zamieniłem sobie w rejestrze przyciski ESC i CAPSLOCK (którego i tak nie używam). Rozwiązuje to problem o tyle, że w ogóle nie sięgam do tego klawisza w prawym górnym rogu. Rozwiązanie fajne, koduje się nawet szybciej, szczególnie w edytorach pozwalających na tryb vim. Problem jednak w tym, że aby przyzwyczaić się do tego podejścia pozamieniałem te klawisze na firmowym kompie i stacjonarce. Teraz jak ktoś siada na moim kompie to nie wie co się dzieje, a dostając klasycznego kompa muszę uważać na mój nowy nawyk. Nie często ktoś stuka na mojej klawiaturze, a ja raz na jakiś czas mogę być bardziej czujny. Trudno, żyję z tym jakoś, ale DUŻY MINUS dla Lenovo za wymuszenie na mnie takiego tricku.

Yoga transformace

Żeby nie opisywać wszystkich niedociągnięć, ciągiem przejdźmy do kolejnej zalety: transformacje yogi.

lenovo-yoga-700-03 lenovo-yoga-700-01 lenovo-yoga-700-02

Wszyscy mówili, że to się do niczego nie przyda, że dopłacam za jakieś wodotryski, które nie mają żadnego praktycznego zastosowania. Nic bardziej mylnego. Elastyczność dostarczona przez tego ultrabooka robi kawał dobrej roboty, ale tego chyba nie da się opisać, to trzeba poczuć. Pokaże tylko główne sytuacje kiedy lubię mieć taki bajer.

Po pierwsze: czytanie (blogów, tweetów, ebooków, co bądź) i oglądanie (youtube, filmy, tutoriale, co bądź).

Generalnie lubię mieć obraz zaraz przed oczami, wolne ręce i nie potrzebować do tego żadnej dodatkowej podstawki.

Photo Czytanie 01 Photo Czytanie 02

Po drugie: Praca na rozszerzonym środowisku.

To rzeczywiście zdaje egzamin. Kiedy pracuję na klawiaturze/myszce i rozszerzonym pulpicie na drugi monitor, laptopa traktuje jako dodatkowy wyświetlacz dotykowy, który fajnie jest mieć zaraz pod palcami. Klasyczna pozycja stwarzałaby tylko dodatkowy dystans przez klawiaturę której i tak nie używam.

Stanowisko pracy Yoga

Podsumowując poziome transformacje dają radę. Ustawienia pionowego nie zdarzyło mi się jeszcze potrzebować. Jest jeszcze tryb tabletu (całkowite rozłożenie), ale tego też używam sporadycznie. Podejrzewam jednak, że wielu osobom ten tryb tez znacznie by ułatwił życie.

Duszki na matrycy

Pora na kolejną niemiłą niespodziankę. Pierwszy dzień pracy. System postawiony, bawię się softem i nagle coś tu nie gra. Matryca wariuje, zachowuje się jakbym cały czas klikał pięcioma paluchami w jednej linii. Skorzystałem z odwiecznego prawa IT, wyłączyłem, włączyłem i jest. Gra i buczy. Sprawa  jednak raz na jakiś czas i tak wracała. Kombinowałem czy może nie trzeba czyścić tej matrycy ale też to nie to. Zastanawiając się czy nie zwrócić sprzętu postanowiłem zerknąć czy ktoś jeszcze nie miał takiego problemu. Co się okazuje? Masa ludzi miała taki problem i to nie jest problem hardware’u tylko software’u. Pierwsza wskazówka: kalibracja dotyku – wydawało się, że pomogła, ale jednak nie. Druga rzecz to firmware update – pobrać plik, kilka klików i po problemie.

Rozwiązanie się sprawdziło. Jak na razie wszystko gra. Zastanawiając się jednak to jest to trochę słabe podejście. Będąc zwykłym userem średnio by mnie kręciło sprawdzanie, szukanie, ściąganie jakiegoś update’u. Sam problem występował już w poprzednim modelu, a rozwiązanie znalazłem tylko na anglojęzycznej stronie producenta. Dziwi mnie to, że po wykryciu tego buga nie dało się wrzucić jakiejś aktualizacji automatycznej, czy wysłać komunikat na wadliwe kompy. Kolejna rysa na diamencie.

I jeszcze filmik z youtube prezentujący objawy usterki. Okazuje się, że już Yoga3 to miała i nowsza wersja nie dostała fix’a w gratisie. Nie rozumiem.

Ultrabook czy laptop

Długo się zastanawiałem czy kupić zwykłego lapka czy dołożyć i zainwestować w ultrabook’a. Gdybym decyzję podejmował z obecnym doświadczeniem nie zastanawiałbym się ani sekundy. Masa robi robotę. Zabieram go praktycznie wszędzie i noszę jak podręczny notes. Dodatkową robotę robi bateria. Mając minimum dniówkę na baterii nawet nie zastanawiam się czy zabierać ładowarkę ze sobą. Zupełnie nie tęsknię za CD-ROM’em, czy kartą sieciową (tą na stary dobry kabel). Zakupiony sprzęt ma osobną (niezintegrowaną) kartę grafiki więc nawet w gierkach powinien dorównać starej stacjonarce. Jedyne co pewnie zacznie mi doskwierać to pojemność dysku, ale póki co problem nie istnieje.

Ładowarka

Na koniec jeszcze ostania wtopa. Już najmniej przeszkadzająca ale śmieszna. Jak można wymyślić taką wtyczkę ładowarki:

 

Jest tyle rozwiązań. Widziałem różne wtyczki, ale w życiu bym nie pomyślał, że ktoś stwierdzi, że „najfajniej by było jakby nasza wtyczka zasłaniała dwa sąsiednie gniazda”.  Jakoś sobie to zorganizowałem, mam takie gniazdko gdzie to nie problem, więc póki co mnie to tylko bawi. Tym bardziej, że przed zakupem widziałem, że obśmiewają na youtube’ach to rozwiązanie w poprzedniku i zakładałem, że w kolejnej wersji to wyprostowali. No ale nic, być może to ma swoje zalety:).

Sumup

To już koniec moich przemyśleń. Sprzęt sprawuje się dobrze. Używam go na co dzień i polecam. Jest to ciekawa, tańsza alternatywa dla macbooka (w którym chyba nadal żałują użytkownikom dotykowego ekranu) i surface pro (który moim zdaniem jest jednak bardziej tabletem pro niż ultrabookiem).

Napisano w .net

Music to Code By – czy to naprawdę productivity tool?

DotNetRocks słucham już ponad dwa lata. Przez ponad 200 podcastów dużo się dowiedziałem, zmieniłem swoje podeście do pracy i pogodziłem się z godzinnym dojazdem do pracy (tak jest! w jedną stronę!). Mimo to byłem sceptyczny gdy Carl Franklin reklamował swój projekt Music to Code By jako doskonałe narzędzie wspomagające produktywność. Jestem wielkim entuzjastą GTD, wszystko notuję w OneNote i chętnie sprawdzam na sobie wszelkie techniki i narzędzia wspomagania produktywności. Ponieważ jednak moje pierwsze dwa podejścia do pomodoro technique  zakończyły się fiaskiem, nie bardzo kupowałem muzykę, która wspiera tą technikę. Słuchając nagadywania trzy razy w tygodniu, patrząc na to co dostaję dzięki podcastowi za zupełną darmochę stwierdziłem: czemu nie. Pięćdziesiąt dolców za 9 utworów (wtedy było 9) co do których nie jestem przekonany, wydawało mi się dużo. Z drugiej strony czasem więcej wydaje się na gierkę lub na imprezę po której tylko kaca mogę przynieść do domu. Więc stało się. Kupiłem całą kolekcje i po kilku miesiącach obcowania z albumem moje wnioski wyglądają następująco.

Pomodoro Technique

Cały koncept music to code polegał na przygotowaniu utworów wspomagających wejście w tak zwane Flow i wspieranie pomidorowej techniki. Technika ta zakłada, że swoją pracę dzielimy na krótkie i intensywne iteracje. Jeden pomidor to 25 min pracy nad jednym taskiem w zupełnym skupieniu. Bez twittera, faceboka, skype’a i każdej innej rzeczy która nas wybija z rytmu. Po 25 min warto zrobić 5 min przerwy. Słysząc o pomodoro zawsze zakładałem, że 25 min to zbyt krótko, że po tym czasie dopiero się rozkręcam. Próbując stosować technikę pojawiła się kolejna niedogodność. Okazuje się, że w open spejsie bardzo trudno jest nie być rozpraszanym w trakcie pracy. W domu też nie jest łatwo.

Pomidor a teoria zarządzania czasem.

Jak pisałem już w komentarzu do posta o kanbanflow, miałem kiedyś okazję uczestniczyć w zajęciach na temat zarządzania czasem. Zgodnie z teorią głoszoną przez wykładowcę każde wejście na wysokie obroty podczas pracy nad pojedynczym, nietrywialnym taskiem zajmuje nam 15 minut. Każde rozproszenie natomiast zeruje ten licznik. Nie wiem czy to autosugestia,  czy samospełniająca się przepowiednia, ale u mnie tak to właśnie działa. Jeżeli już się wciągnę w coś to lobię popracować dłużej. Dlatego 25 min pomidora mnie odstraszało. Nie ma jednak żadnej przeszkody żeby zrobić trzy pomidory pod rząd i dopiero zrobić sobie przerwę.

Co daje Music To Code by?

Teraz do konkretów. Kupiłem masę empetrójek, więc trzeba było zacząć tego „używać”. Zacząłem od dłubania w domu i tu pierwsze zalety. Po pierwsze uświadomiłem sobie, że do tej pory trochę oszukiwałem. Puszczając sobie muzyczkę i kodując szybko odkryłem, że zaczynam odświeżać twittera, zerkać na skype, allegro, a utwór nadal gra. Ba! Nawet nie jest w połowie. Nie minęło to moje 15 minut. Szybko się przekonałem, że muszę popracować nad skupieniem się nad tym co robię.

Kolejna zaleta, która szybko wypłynęła to pomiar czasu. Robiąc swoje zajawki raczej nie planuję ile mi to zajmie, nie mam budżetu czy deadline’ów. Staram się jednak notować (lub przynajmniej być świadomym), ile czasu poszczególne czynności mi zajmują. Jest jednak z tym problem. Pracując nad wszystkim na raz trudno jest powiedzieć, że dokładnie 3 godziny spędziłem na kodowaniu. Puszczając 25 minutowe utwory pojedynczo, w kolejności i pauzując przy każdej przerwie (nie oszukujmy jest lepiej, ale przerwy zawsze będą) wszytko zaczyna mieć ręce i nogi. Skończyłem jakiś feature, coś zaimplementowałem,  coś skonfigurowałem. Ile to zajęło? No policzmy zacząłem od ścieżki 8, właśnie skończyła się 10. Trzy razy pół godziny daje mi półtorej. As simple as that.

Szybko też przeniosłem swoje zwyczaje do pracy i tu pojawiła się kolejna zaleta. W pracy niespecjalnie słuchałem muzyki. Okazuje się, że puszczając muzykę za bardzo się wsłuchuję. Z drugiej strony w pokoju panuje niepisana zasada nałożonych słuchawek. Nie masz słuchawek na uszach – można cię zagadnąć. Dochodziło do takich paradoksów, że zakładałem słuchawki nie słuchając absolutnie niczego. Niestety słyszałem wtedy rozmowy, a w niektóre lubię się włączyć. Music to code by dało mi tą wygodę, że słyszę dźwięk zagłuszający biurowe szumy, który przez 25 min nie zmienia swojego rytmu, intensywności, melodii. Po pięciu minutach staje się ignorowany.

Podobno same utwory są stworzone wg wytycznych co do częstotliwości i melodii wspomagających koncentrację. Nie wiem na ile rzeczywiście tak jest, nigdy mnie nie ciągnęło żeby tej wiedzy szukać, ale na pewno poprawa wydajności jest dla mnie zauważalna. Odnotowałem też, że jak każdy dobry projekt przyrostowy, music to code by z każdą iteracją stawał się lepszy. Projekt wystartował od kilku utworów, zbierane były feedbacki i co jakiś czas były wypuszczane kolejne utwory. Te późniejsze są przesłuchiwane częściej, łatwiej mi przy nich pracować.

Sumup

Podsumowując. Myślę, że zakup okazał się trafiony. Podejście trzecie do pomodoro technique może być podejściem udanym. Zachęcam też do śledzenia projektu i twitter Carl’a, bo trafiło się tak, że w marcu nowy, dwunasty track był udostępniany za darmo. Zakładałbym, że promocja może się powtórzyć.

 

 

 

Napisano w .net

NUnit – TestCaseSourceAttribute

Chciałem pokazać działanie kilku ciekawych atrybutów w NUnit. Długo się zastawiałem które są najciekawsze, w jakiej formie je sprzedać, jakich przykładów użyć i na co zwrócić uwagę. Doszedłem do jednego wniosku: za długo się zastanawiam. Poniżej pierwszy atrybut, który często mi się przydaje, a może nie każdy jest świadom jego istnienia. Wiedza ze standardowej dokumentacji NUnit 2.6.4 (najnowszy NUnit ostatnio nie współpracował z resharperem, lub odwrotnie) okraszona kilkoma przykładami i przemyśleniami. Przykład może jest odrobinę naciągany, ale powinien fajnie obrazować co chcę osiągnąć.

Punkt wyjścia

Będziemy sobie testować implementacje interfejsu ISelectSourceService, która to ma dostarczać różne słowniki do select listy.

    public interface ISelectSourceService
    {
        Dictionary<int, string> GetCountries(Lang lang, bool withEmpty0 = false);
    }

Zacznijmy od testowania domyślnego wywołania GetCountries. Chcemy wiedzieć, że dla każdego języka dostajemy nie pusty słownik, niepustych wartości. Jakie mamy opcje.

Możemy sobie napisać test dla każdej wartości lang, ale podejście trochę słabe. Mnożymy kod, a poza tym możemy przegapić pojawienie się nowego języka. W takim razie napiszmy bazową metodę testującą i wywołajmy w teście dla wszystkich wartości enum’a Lang. Coś w ten deseń:

    [Test]
    public void GetCountriesShouldReturnNotEmptyDictionary()
    {
        ISelectSourceService service = new SelectSourceService();
        TestForLanguage(service, Lang.Polish);
        TestForLanguage(service, Lang.English);
        TestForLanguage(service, Lang.German);
    }

Fajnie, kodu mniej ale jak się wysypie nie sprawdzi pozostałych wartości, a jak nie przypilnujemy to nie wiemy, która wartość psuje test. Nadal przegapiamy pojawienie się nowej wartości enum. Możemy być sprytni, wyciągnąć wszystkie elementy enuma i uruchomić TestForLanguage dla każdego elementu. Podejście dobre i złe:). Dzięki temu mamy jeden test, nie przegapimy nowego enum’a,  ale gdy któraś wartość powoduje błąd to przerywamy test i nie sprawdzamy reszty.
Innym podejściem byłby test z paroma testcase’ami.

    [TestCase(Lang.Polish)]
    [TestCase(Lang.English)]
    [TestCase(Lang.German)]
    public void GetCountriesShouldReturnNotEmptyDictionary(Lang lang)

Wtedy rezultaty wyglądają lepiej, ale nadal boli mnie to że mogę przegapić pojawienie się nowego języka i mam już tego dosyć.

TestCaseSourceAttribute

Z pomocą przychodzi nam TestCaseSourceAttribute, który pozwala podać źródło naszych testcase’ów i przetestować każdy case nawet gdy któryś się poczerwieni.

Właśnie to jest rozwiązanie problemu, który kiedyś strasznie mnie dotykał. W TestCaseSourceAttribute możemy sobie, utworzyć kolekcję do przetestwania. Innym problemem w którym mi się to przydało jest ładowanie test case’ów z pliku json lub innego źródła. Korzytając z tego atrybutu testowanie nasze może zaprezentować się następująco:

        [TestCaseSource("LanguagesTestCases")]
        public void GetCountriesShouldReturnNotEmptyDictionaryForAnyLanguage(Lang lang)
        {
            ISelectSourceService service = new SelectSourceService();
            var received = service.GetCoutries(lang);
            Assert.NotNull(received);
            Assert.IsNotEmpty(received);
        }

        public static IEnumerable LanguagesTestCases()
        {
            var enums = Enum.GetValues(typeof(Lang));
            return enums;
        }

Tym sposobem jeżeli w samej implementacji pojawi się nowy element, który powinien być przetestowany, TestCase zostanie utworzony automatycznie.
Trochę mnie boli jeszcze prezentacja pojedynczych test casesów, ale jest akceptowalna. Rozwiązanie tej bolączki zaprezentuje w następnym przykładzie.

Sam parametr sourceName musi spełniać kilka warunków.

  • Musi to być nazwa pola, property lub metoda
  • Musi to być instancja lub element statyczny
  • Musi zwracać IEnumerable lub obiekt implementujący IEnumerable
  • Pojedyncze itemy muszą być kompatybilne z sygnaturą metody testującej.

TestCaseData

Ciekawostką i rozwiązaniem wcześniej opisywanego problemu jest zwracanie elementów typu TestCaseData. Obiekt ten pozwala zdefiniować oczekiwany rezultat, wyjątek czy nazwę i opis test case’a. Dla przykładu mając property informujący czy trójkąt jest prostokątny możemy to testować w ten sposób.

        [TestCaseSource(nameof(TestCases))]
        public void IsRectangularShouldReturnProperValue(Triangle triangle, bool expectedResult)
        {
            var isRectangular = triangle.IsRectangular;
            Assert.AreEqual(expectedResult, isRectangular);
        }

        public static IEnumerable TestCases()
        {
            yield return new object[] {new Triangle(5, 4, 3), true};
            yield return new object[] {new Triangle(5, 4, 4), false};
            yield return new object[] {new Triangle(5, 2, 2), false}; //this one throws exception

        }

Podejście to sprawia jednak parę problemów.

  1. Nie możemy oczekiwanego rezultatu ustawić jako rezultat metody
  2. Nie możemy w jednym TestCaseSource sprawdzić czy dla złych danych (nie tworzących trójkąta) rzucany jest odpowiedni wyjątek.
  3. Test explorer nie pokazuje nic przyjemnego jako pojedyncze case’y. Jeżeli klasa TriangleEdges nie przeładowała ToString() wrzuca domyślny ToString()[screen1].
  4. Nawet jeśli przeładowaliśmy ToString() to:
    • nadal może nie być nasze oczekiwane rozwiązanie [screen2],
    • wymusza implemetacje ToString() pod testy.
screen1

Screen1

screen2

Screen2

Wszystkie te bolączki rozwiązują obiekty TestCaseData, przy pomocy których test mógłby wyglądać następująco:

        [TestCaseSource(nameof(TestCaseDataCases))]
        public bool IsRectangularShouldReturnProperValue2(Triangle triangle)
        {
            return triangle.IsRectangular;
        }

        public static IEnumerable TestCaseDataCases()
        {
            yield return new TestCaseData(new Triangle(5, 4, 3))
                .Returns(true)
                .SetName("Case for true");
            yield return new TestCaseData(new Triangle(5, 4, 4))
                .Returns(false)
                .SetName("Case for false");
            yield return new TestCaseData(new Triangle(5, 2, 2))
                .Throws(typeof(ThisIsNotTriangleException))
                .SetName("Case for exception");
        }

Test explorer też prezentuje się dużo lepiej.

screen3

Screen3

Oczywiście sam przykład mocno uproszczony i naciągany, ale pogląd na sprawę daje.
Mam nadzieję, że jest to zalążek wiedzy, która okaże się przydana i zainspiruje do przejrzenia dokumentacji NUnit.
Warto.

Napisano w .net, Nuget Tagi: , , ,

Nie tylko DotNetRocks warte posłuchania…

Początkowo planowałem napisać o podcastach DotNetRocks i wychwalić autorów pod niebiosa (bo należy im się za to co i jak robią). Tylko, że to chyba nie ma sensu. Linki do audycji przewijają się przez przeróżne blogi i wystarczy napisać, że naprawdę warto ich posłuchać. Ponieważ jednak dojazd do pracy zajmuje mi godzinę, a samych dotnetrocks’ów pojawia się tylko trzy odcinki w ciągu tygodnia rozglądam się, słucham, sprawdzam i myślę, że warto podzielić się wykopaliskami. Oto kilka podcastów, których słucham regularnie:

hanselminutes.com – to jeden z trzech podcastów wypuszczanych przez Scott’a Hanslelman’a. W sumie z całej trójki wg mnie najlepszy. Regularnie publikowane odcinki traktujące o przeróżnych zagadnieniach mniej lub bardziej związanych z branżą IT. Bitcoin’y, kreatywność, design, security, wirtualna rzeczywistość, web, mobile, IOT, czego tylko dusza zapragnie. Żadnej konkretnej technologii, żadnego wciskania microsoftu na siłę.

developeronfire.com – stosunkowo młody podcast (aktualnie 43 odcinki), który prowadzi Dave Rael. Każdy odcinek to praktycznie wywiad z doświadczonym developerem przeprowadzany wg bardzo podobnego scenariusza. Z każdego odcinka dowiesz się o między innymi początkach kariery, porażkach, sukcesach, polecanej książce, źródle wiedzy i dostaniesz 3 najistotniejsze rady dla developera. Pytania nie są specjalnie wyszukane, ale warto posłuchać jak różne refleksje i podejście mają ludzie do podobnych zagadnień, działający w tej samej branży. Świetna audycja na drogę powrotną z pracy. Pozwala mi wykrzesać jeszcze odrobinę motywacji i zapału do działania po powrocie, których nie miałem wychodząc z biura.

Hello World Podcast to podcast o tym jak obecnie odnoszący sukcesy liderzy, mentorzy, autorytety czy autorzy książek zaczynali w tym biznesie. Shawn Wildermuth  pyta swoich gości o najwcześniejsze doświadczenia z IT, o pierwszy komputer, pierwsze projekty, miejsce pracy i pierwszych mentorów na rozpoczynającej się ścieżce kariery. Często dygresje prowadzą do dyskusji o podejściu do branży, kariery, przewidywanej przyszłości i nadziejach związanych z branżą. W sumie odkąd jest developeronfire.com to trochę odcinków odpuściłem, ale warto było słuchać o tym jak różne ścieżki prowadzą do kariery programisty.

Zaczynając słuchać podcastów czekałem na pierwszą polską inicjatywę. Pierwszy i na razie jedyny polski podcast jaki trafił na moją playlistę to devtalk.pl Macieja Aniserowicza. Odcinki techniczne przeplatane „miękkimi”. Super zrobiony temat „Kariery programisty z Pawłem Zdziechem„. Warto było posłuchać o gamedev z Przemysławem Czatrowskim, który współtworzył najnowszego Wiedźmina. Dowiedzieć się jak inny jest to świat w porównaniu z składaniem kolejnych biznesowy aplikacji. Podcast na pewno warty do dopisania do listy dla wszystkich, którzy nie stawiają tylko na język angielski (chociaż i w devtalk trafiła się konkretna pogadanka o CQRS z Udi Dahan).

Wiem, że pojawił just4fun.io ale jeszcze nie zdążyłem przesłuchać.

Jest jeszcze cała masa innych podcastów, które warto sprawdzić. Do tej pory głównym źródłem moich informacji o nowych projektach były blogi i (a jak) dotnetrocks.com. Ostatnio nadziałem się jednak na fajne źródło na github’ie: awesome-geek-podcasts. Nawet udało mi się uzupełnić repo o developeronfire. Myślę, że warto przejrzeć listę i sprawdzić parę pozycji. Jeżeli chcesz się podzielić refleksją na temat wymienionych projektów lub jest coś naprawdę warte polecenia, a ja w swej niewiedzy zupełnie to pominąłem, czekam na komentarz do wpisu.

 

 

 

Napisano w Rozwój Tagi: , ,

Proste template’y z DotLiquid

Po raz kolejny chciałbym podzielić się znaleziskiem z Nuget. Zdarzyło się, że potrzebowałem dostarczyć temlate’y wiadomości tak aby możliwe było ich przeredagowanie przez osoby bardziej twórcze. W sumie udało się odnaleźć parę rozwiązań, które mogłyby spełnić to wymaganie. Między innymi

Te i parę innych znalazłem na liście Top 20 NuGet packages for Templating

Po wstępnym rozpoznaniu tematu zdecydowałem się na DotLiquid. Jest to zportowana .Net’towa wersja popularnego (podobno) Ruby Liquid temlating language.
Zdecydowałem się głównie z braku czasu na konkretną weryfikację ale wyboru nie żałuję i na pewno rozwiązanie to będzie moim faworytem w przyszłości. Główne zalety, argumenty które do mnie przemówiły to:

  • Dostępność na nuget
  • Przyzwoita dokumentacja
  • Czytelność
  • Bezpieczeństwo – możliwość zachowania kontroli nad mapowaniem parametrów temlate’u.

Aby tym razem nie powtarzać przykładów z dokumentacji założyłem sobie takiego example case’a:
Chcemy udostępnić użytkownikowi możliwość otrzymywania mailingu z wybranych kategorii. Mamy więc klasy.

    [LiquidType("Name","Surname", "MailingCategories", "Weight", "Height", "Birthdate")]
    public class Mailing
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Surname { get; set; }
        public float Height { get; set; }
        public float Weight { get; set; }
        public DateTime Birthdate { get; set; }
        public string Email { get; set; }
        public string Secret { get; set; }
        public Guid ConfirmationGuid { get; set; }
        public Guid RemoveGuid { get; set; }
        public List<MailingCategory> MailingCategories { get; set; }
    }
    [LiquidType("Name")]
    public class MailingCategory
    {
        public int Id { get; set; }
        public String Name { get; set; }
    }

Chcemy aby po wpisaniu się do subskrypcji użytkownik potwierdził swój wybór. Tworzymy więc temlate’a maila i metodę dostarczającą treść maila.

Witaj, 

Aby otrzymywać mailing ze strony spamsender.com potwierdź swoje zgłoszenie:

Twoje dane:
Imię:  {{mailing.Name | Upcase }}
Nazwisko: {{mailing.Surname | Upcase }}
Wzrost/Waga: {{mailing.Weight}} / {{mailing.Height}}
Data urodzenia: {{ mailing.Birthdate | date:"MM/dd/yyyy" }}

Dopisałeś się do grup:
{% assign categories = mailing.MailingCategories | Sort: 'Name' %}{% for category in categories -%}
{{category.Name}}
{% endfor -%}

Aby potwierdzić zgłoszenie kliknij poniższy link:
{{ConfirmationLink}}

Aby anulować swoje uczestnictwo kliknij poniższy link:
{{RemoveLink}}

{{Secret}}

Powodzenia,
spamsender.com
    public class MailingMailContentProvider : IMailContentProvider<Mailing>
    {
        private readonly String templateText;
        private readonly String linkRootPath;

        static MailingMailContentProvider()
        {
            Template.NamingConvention = new CSharpNamingConvention();
            Liquid.UseRubyDateFormat = false;
        }

        public MailingMailContentProvider(string templateText, string linkRootPath)
        {
            this.templateText = templateText;
            this.linkRootPath = linkRootPath;
        }

        public string GetMailContent(Mailing item)
        {
            Template template = Template.Parse(templateText);
            Hash hash = Hash.FromAnonymousObject(new
            {
                mailing = item,
                ConfirmationLink = $"{linkRootPath}/confirm/{item.ConfirmationGuid}",
                RemoveLink = $"{linkRootPath}/remove/{item.RemoveGuid}"
            });
            String result = template.Render(hash);
            return result;
        }
    }

Samego działania możemy się oczywiście spodziewać, ale dla pewności zweryfikujmy to prostym testem.

    [TestFixture]
    public class MailingMailContentProviderTests
    {
        private IMailContentProvider<Mailing> provider;
        private readonly string linkPath = "www.moromind.pl";
        [SetUp]
        public void Init()
        {
            string temlateText = File.ReadAllText(@"Templates\MailingConfirmationTemlate.txt");
            provider = new MailingMailContentProvider(temlateText, linkPath);
        }

        [Test]
        public void TestGetEmailContentTestShouldReturnContentWithPropertiesIncludes()
        {
            Mailing mailing = new Mailing()
            {
                Id = 1,
                Name = "Grzegorz",
                Surname = "Morawski",
                Email = "testemail@domain.com",
                Birthdate = new DateTime(1985,1,31),
                ConfirmationGuid = Guid.NewGuid(),
                RemoveGuid = Guid.NewGuid(),
                Height = 175F,
                Weight = 78F,
                Secret = "my secret text"
            };
            mailing.MailingCategories = new List<MailingCategory>()
            {
                new MailingCategory() {Id=1, Name = "Humor"},
                new MailingCategory() {Id=2, Name = "Programming"},
                new MailingCategory() {Id=2, Name = "Extreme sports"}
            };
            string confirmationLink = $"{linkPath}/confirm/{mailing.ConfirmationGuid}";
            string removeLink = $"{linkPath}/remove/{mailing.RemoveGuid}";

            string mailContent = provider.GetMailContent(mailing);
            StringAssert.Contains(mailing.Name.ToUpper(), mailContent);
            StringAssert.Contains(mailing.Surname.ToUpper(), mailContent);

            StringAssert.Contains(mailing.MailingCategories[0].Name, mailContent);
            StringAssert.Contains(mailing.MailingCategories[1].Name, mailContent);
            StringAssert.Contains(mailing.MailingCategories[2].Name, mailContent);

            StringAssert.Contains(confirmationLink, mailContent);
            StringAssert.Contains(removeLink, mailContent);

            StringAssert.DoesNotContain(mailing.Secret, mailContent);

            Console.Out.Write(mailContent);
        }
    }

Output testu wygląda następująco:

Witaj, 

Aby otrzymywać mailing ze strony spamsender.com potwierdź swoje zgłoszenie:

Twoje dane:
Imię:  GRZEGORZ
Nazwisko: MORAWSKI
Wzrost/Waga: 78 / 175
Data urodzenia: 1985-01-31 00:00:00

Dopisałeś się do grup:
Extreme sports
Humor
Programming

Aby potwierdzić zgłoszenie kliknij poniższy link:
www.moromind.pl/confirm/1d12c918-2c25-44c2-bad7-4d028888fc8e

Aby anulować swoje uczestnictwo kliknij poniższy link:
www.moromind.pl/remove/4c4bf2a9-39cd-4ef5-8ae5-cf4e9b804e9d

Powodzenia,
spamsender.com

Na tym prostym przykładzie widzimy, że możemy mieć kontrolę nad:

  • Dostępem do properties
  • Listami
  • Tagami
  • Formatem danych

Oraz paroma innymi rzeczami. Oczywiście to nie wszystko z podstawowych funkcjonalności, a  jako ambitni programiści możemy całość rozszerzyć o swoje filtry, tagi, block tagi, ale o tym innym razem (lub w dokumentacji).

Napisano w .net Tagi: , , ,

Kanbanflow – ciekawa implementacja tablicy tasków

Pracując w różnych projektach i śledząc blogi udało mi się zapoznać z wieloma wirtualnymi tablicami tasków. Do tej pory do prywatnych zastosowań najbardziej przemawiały do mnie Kanbanize i Trello. Oczywiście jest jeszcze Jira ale to już inna liga, inny kaliber. Po wykopaniu na Dotnetomaniak’u wpisu  „Dobre nawyki programisty C#” moją uwagę zwrócił Kanbanflow, umieszczony w linkach do posta. Sam tool swoją prostotą kojarzy się z trello. Pozwala tworzyć proste tablice tasków, dodawać kolumny i taski wraz ze szczegółami. Jest jednak kilka smaczków, które przekonują mnie do uruchomienia tego w jakimś mały projekcie.  Poniżej przedstawiam kilka feature’ów, które do mnie przemawiają.

Czas szacowany i faktyczny

W kanbanflow do każdego taska możemy przypisać Time spend i Time estimated. Przy odpowiedniej konfiguracji oba czasy są ładnie wyeksponowane na tablicy. Jest to jeden ze szczegółów, którego zawsze mi brakowało w trello. Kanbanize ma swoje Custom fields, ale w zupełności wystarcza mi to co dostaje w standardzie Kanbanflow.

Daty deadline

Kolejną fajną rzeczą w tool’u jest możliwość dodania na danym tasku daty deadline dla znalezienia się w zadanej kolumnie. Jeżeli data jest przekroczona to system odpowiednio oznacza karteczkę na tablicy. Feature o tyle fajny, że dla każdej kolumny taką datę można ustawić i zaplanować sobie planowany flow. Dodatkowo możemy ustawić notyfikację na dzień przed upłynięciem due date.

Pomodoro timer

Kolejnym dodatkiem, który może się spodobać, a na pewno zwrócił moją uwagę jest pomodoro timer. Kto stosuje i lubi metodę pomodoro nie musi sięgać po osobne narzędzie. Stoper pozwala skonfigurować czas pracy, krótkiej przerwy, dłuższej przerwy i zdefiniować co ile pomidorów mamy dłuższą przerwę. Nie jestem fanem tej techniki (a nawet jestem antyfanem), więc raczej mi się nie przyda.

Konfiguracja wyświetlania per kolumna

Pora na najważniejszy feature, który odróżnia kanbanflow i przekonuje mnie do dania mu szansy w projekcie, a więc konfiguracja tablicy. Autorzy sprytnie wydedukowali, że przecież nie na każdej kolumnie potrzebujemy dokładnie tych samych informacji. Narzędzie pozwala więc skonfigurować każdą kolumnę oddzielnie. Ja założyłbym sobie taką konfigurację.

  • Kolumna Backlog, na której wyświetlam tylko tytułu taksów.
  • Kolumna To do, na której wyświetlam dodatkowo szacowany czas, listę subtasków.
  • Kolumna In progress, która pokazuje maksymalnie dużo szczegółów. Na pewno chcę widzieć tytuł, szczegóły, osobę która realizuje, labelki i poszczególne czasy. W końcu tutaj są tylko te zadania, które faktycznie realizujemy i o których musimy wiedzieć najwięcej.
  • Kolumna Done, w której interesowałoby mnie tylko czas szacowany i faktyczny.

Kanbanflow_screen

W praktyce pewnie konfiguracja jeszcze się zmieni, więc tym bardziej dobrze wiedzieć, że mamy takie możliwości.

Wersja premium

To podstawowe rzeczy, które zwróciły moją uwagę. Wszystko to jest za free w podstawowej wersji. Gdy tool się spodoba to warto przemyśleć przejście na wersję premium. Za jedyne pięć dolców miesięcznie możemy dostać między innymi:

  • wyszukiwanie/filtrowanie
  • dodawanie tasków mailem
  • eksport/import danych
  • załączniki, dashboard, API
  • raporty wydajności
  • cztery role użytkowników

Wszystkie feature’y można doczytać na kanbanflow.com. Ja sam na razie do premium się nie garnę. Ale na pewno z wersją free bliżej się poznam.

Napisano w Tools

ManyConsole – pomysł na console application prosto z Nuget

Czasami zdarza się, że musimy dopisać do systemu prostego konsolowego tool’a pozwalającego na wykonanie kilku wybranych funkcjonalności. Czy to jakiś prosty raport tekstowy, sprawdzenie stanu, cokolwiek. Bywa, że z dumą przystępujemy do pisania „od zera”. Czasami mamy już swoje wypracowane rozwiązanie, a czasem ruszamy na poszukiwania. Tym szukającym właśnie wychodzi naprzeciw ManyConsole.

ManyConsole to biblioteka dostępna na nuget pozwalająca w prosty sposób rozwijać i zarządzać aplikacją konsolową. Używa i zależy od parsera NDesk.Options z tym, że główną wartością dodaną jest obsługa wielu komend z różnymi parametrami do czego przyzwyczaił nas git. Automatyczny help jest już wisienką na torcie:).

Zgodnie z instrukcją z GitHub aby użyć wystarczy:

  1. Dodać bibliotekę z nuget
  2. W main wywołać ConsoleCommandDispatcher
  3. Dodać wymagane komendy jako klasy dziedziczące z ConsoleCommand

Wystarczy zerknąć na przykładowy kod żeby zrozumieć co i jak.
W samym main w bazowej implementacji wystarczy nam tylko:

class Program
{
    class Program
    {
        static int Main(string[] args)
        {
            // locate any commands in the assembly (or use an IoC container, or whatever source)
            var commands = GetCommands();

            // then run them.
            return ConsoleCommandDispatcher.DispatchCommand(commands, args, Console.Out);
        }

        public static IEnumerable<ConsoleCommand> GetCommands()
        {
            return ConsoleCommandDispatcher.FindCommandsInSameAssemblyAs(typeof(Program));
        }
    }
}

Mamy więc ConsoleCommandDispatcher dzielnie poszukujący komend w Assembly.
Implementacja przykładowej komendy wygląda następująco:

    public class ExampleCommand : ConsoleCommand
    {
        public ExampleCommand()
        {
            this.IsCommand("Example", "Example implementation of a ManyConsole command-line argument parser Command");

            this.HasOption("b|booleanOption", "Boolean flag option", b => BooleanOption = true);

            //  Setting .Options directly is the old way to do this, you may prefer to call the helper
            //  method HasOption/HasRequiredOption.
            Options = new OptionSet()
            {
                {"l|list=", "Values to add to list", v => OptionalArgumentList.Add(v)},
                {"r|requiredArguments=", "Optional string argument requiring a value be specified afterwards", s => OptionalArgument1 = s},
                {"o|optionalArgument:", "Optional String argument which is null if no value follow is specified", s => OptionalArgument2 = s ?? "<no argument specified>"}
            };

            this.HasRequiredOption("requiredOption=", "Required string argument also requiring a value.", s => { });
            this.HasOption("anotherOptional=", "Another way to specify optional arguments", s => {});

            HasAdditionalArguments(2, "<Argument1> <Argument2>");
        }

        public string Argument1;
        public string Argument2;
        public string OptionalArgument1;
        public string OptionalArgument2;
        public bool BooleanOption;
        public List<string> OptionalArgumentList = new List<string>();

        public override int Run(string[] remainingArguments)
        {
            Argument1 = remainingArguments[0];
            Argument2 = remainingArguments[1];

            Console.WriteLine(@"Called Example command - Argument1 = ""{0}"" Argument2 = ""{1}"" BooleanOption: {2}", Argument1, Argument2, BooleanOption);

            OptionalArgumentList.ForEach((item) => Console.WriteLine(@"List Item {0} = ""{1}""", OptionalArgumentList.IndexOf(item), item));

            if (BooleanOption)
            {
                throw new Exception("Throwing unhandled exception because BooleanOption is true");
            }

            return 0;
        }
    }

Mam nadzieję, że tym krótkim wpisem zachęcę kogoś do wypróbowania ManyConsole albo przynajmniej zaznaczę obecność tej biblioteki w świadomości użytkowników nuget.

Napisano w .net, Nuget Tagi: , , ,