Przyspieszone słuchanie podcastów i konferencji

play youtube faster

Czy oglądając video z konferencji nie nudzicie się czasem? Może za wolno? Zdecydowanie tak. Kiedykolwiek to pokazuję to każdy się zgadza, że można przyspieszyć.

Np. w youtube w prawym dolnym rogu klikamy Settings->Speed i dostaniemy wybór jak po prawej.

W Windows Media Player klikamy PPM->Enhancements->”Play speed settings”:

play windows media player faster

Oraz mój ulubiony (na androidzie), czyli prosty Music Speed Changer (to był jedyny który ściągnąłem, chętnie posłucham gdy są lepsze):

Android Music Speed Changer

Zyski

Ja oszczędzam w ten sposób bardzo dużo czasu. Gdy chodzi o podcasty to słucham na ok 140%. Gdy czasem ktoś mówi zbyt szybko to zmniejszam do 130%. W ten bardzo prosty sposób w 30 minut wchłaniam wiedzę z 40 minut.

Dobra muza do kodowania

Wiadomo jest to bardzo subiektywne. Wracam jednak często po podobne bity, więc tak bardziej dla siebie wrzuciłem wreszcie na bloga.

Niech się stanie FLOW

i kolejne części „Concentration \ Programming Music”

Pomodoro

Polecam równocześnie technikę pomodoro i ustawianie czasu na 25minut pracy, 5minut przerwy. Mój programik to http://e.ggtimer.com/pomodoro

Okazjonalne (regularne) czyszczenie kodu Resharperem

Powiedzmy, że mamy projekt, w którym wcześniej nie znano Resharpera. Otwierając taki kod „wszystko świeci” na różne kolory sugerując, że mamy w kodzie wiele problemów. Moje doświadczenie programistyczne mówi mi, że warto wysprzątać te miejsca, ponieważ na wstępnie z automatu poprawi się nam wiele bugów i znacznie zwiększy czytelność.

cleanup code in resharper

I tutaj staje się przed problemem czy poprawiać wszystko? Czy tylko ważne rzeczy? Czy też przy okazji te automatyczne poprzez Alt+Enter?

Kiedyś przerobiłem cały kod w solucji za pomocą opcji „Cleanup Code” (PPM na projekcie/solucji/katalogu).

cleanup code in resharper

Na początku żeby zacząć utworzyłem nowy profil, nazwałem go „just remove unused references”, i jak widać na obrazku robi to oraz dodatkowo sortuje. Jest to „bezpieczny” niewymagający naszej ingerencji refactoring. Dzięki niemu gdy będziemy już z głową refaktorować kod (usuwać duplikacje, zmieniać strukture itp, itd) nie będziemy się rozpraszać rzeczami, które może poprawić za nas automat.

Warto też od czasu do czasu jeszcze raz przerobić tym automatem cały kod w solution, ponieważ takie rzeczy (jeśli inne osoby o to nie dbają) regularnie zaśmiecają projekty.

Muszę kiedyś napisać o podejściu „Resharper green”, może to rzuci trochę więcej światła.

Jak nie dać się zwariować napływowi informacji

Angielski tytuł brzmiałby „It’s not what you read, it’s what you ignore” bo jest on tytułem znakomitego wystąpienia Scotta Hanselmana:

Od siebie mogę dodać kilka rzeczy, które robię:

  • Email prywatny w pracy jest w nieużywanej przeglądarce, więc prawdopodobieństwo jego przypadkowego przeglądania jest bardzo niskie.
  • Wyłączenie powiadomień mailowych na komórce (zarówno głosowych jak i wizualnych).
  • W pracy na stałe włączony jest tylko Slack projektowy.
  • Wyłączenie powiadomień Slackowych na komórce (tylko głosowe, wizualne zostały).

Dwa powyższe punkty (o emailach) sprawiły, że na dzień dzisiejszy mam +1000 nieodebranych emaili… i bardzo dobrze mi z tym 🙂 Oznacza to, że pewnie te rzeczy nie były tak ważne. Zysk z tego taki, że nic mnie w ciągu dnia nie pinguje i nie odrywa z tego co akurat robię – BEZCENNY. Z drugiej strony kiedyś już w 90% napisałem posta o Inbox Zero, bo to też jest fajne i chciałbym do tego wrócić. Na obecna chwilę nie chcę jednak zaprzątać sobie głowy zadaniem sprzątania skrzynki. Najważniejsze rzeczy mają odpowiednie priorytety i się dzieją.

Do przemyślenia w najbliższym czasie jest czy nie zrobić sobie kilku godzin w ciągu dnia z wyłączonym Outlookiem. Już tak kiedyś pracowałem – czasem trzeba wrócić z powrotem do dobrych, ale zapomnianych praktyk.

A jakie są wasze productivity tips?

Code Review a spacje i inne pierdoły

Chodzi o taką sprawę:

couple random spaces in Code Review

Te ciemno zielone to kilka dodatkowych spacji, które się pojawiło (a nie było ich wcześniej). Inne to: dodatkowo zbędna, podwójna linia, brak pustej linii, brak spacji w parametrach lub zbyt duża ich liczba, itp, itd.

Przypadkowo podczas pracy nad kodem gdzieś się pojawiło kilka spacji za dużo lub za mało. Czy chcielibyśmy przypieprzać się do takich rzeczy na Code Review? – nie bardzo, są ciekawsze rzeczy do kminienia. Jak unikać takich przeszkadzajek:

  • Formatować kod przed commitem, a najlepiej na bieżąco, skrót Ctrl+K, Ctrl+D.
  • Jeśli powyższego nie możemy zrobić, bo ogólnie cały kod jest syfiasty gdy chodzi o wcięcia/formatowanie to możemy formatować tylko kod, który dodaliśmy. Zaznaczamy kod i skrót Ctrl+K, Ctrl+F. To akurat robię rzadko.
  • Jeśli już nie możemy (albo nie chcemy) korzystać z automatycznego formatowania to przed pushowaniem do centralnego repozytorium powinniśmy oczyścić commity z takich przeszkadzajem (git rebase interactive).
  • Już naprawdę w ostateczności gdy nic z powyższych nie podziałało to podczas tworzenia pull requesta (obszerny opis o co w tym biega na przykładzie Git/BitBucketa) zobaczmy wszystkie nasze zmiany. Na tym etapie wyłapiemy te pierdoły, na które będzie tracił czas każdy robiący Code Review (a czasem jest to kilka osób, których czas byśmy zmarnowali).

Innym podejściem jest włączeniem do projektu StyleCopa. Dzięki temu wymusimy pewne standardy formatowania, czyli brudną robotę odwali za nas narzędzie.

Uciekaj szybko z metody i usuwaj „else”

Chciałem w sumie tylko podlinkować:

What really grind my gears #1 – IIIIIIIIIIIIIIIIF! by Oskar Dudycz.

TL;DR, taki kod:

zamieniamy na:

Codzienna prasówka – The Morning Brew

Chciałbym dziś napisać o jednej z metod poszerzania wiedzy.

Od zawsze nazywało się to dla mnie The Morning Brew. Jak sam autor pisze:

The Morning Brew
is a daily .NET software development link blog published by Chris Alcock a software developer from the north west of England.

Chris ma w tym doświadczenie, to już #2468 odcinek, pierwszy był 10 lat temu!

the-morning-brew-logo

Zawartość

Można się spodziewać kilkunastu lub dwudziestukilku linków do artykułów, które warto przeczytać a pojawiły się poprzedniego dnia (lub od ostatniej publikacji The Morning Brew, nowe wpisy ukazują się tylko w dni pracujące). Wybierane są tak zwane perełki. Dzięki temu nie zaglądam już do innych zagranicznych agregatorów technologicznych.

Czego tam szukam?

Nie warto czytać wszystkiego, przebiegam po tytułach i opisach. Już po sekundzie wiem co mnie interesuje. Dziennie klikam kilka linków. Więcej nie warto bo tematy są tam bardzo szerokie. Mają wspólny mianownik i jest nim .NET, ale trzeba być realistą, czytam o tych rzeczach, które przydadzą mi się w codziennej pracy.

Inny przykład to wpisy np Ayende. Jego blog sam w sobie w całości powinien być „must read”, jeśli jednak nie mamy aż tyle czasu to The Morning Brew wybierze dla nas te najciekawsze.

Gdy na co dzień pracowałem z Front Endem, czytałem o nowinkach z tego świata (dużo o TypeScript). Teraz pracuję w oderwaniu od UI (silnik obliczeniowy), więc nie klikam w nic związanego z TypeScriptem, a za to poznaję tematy .NET Standard/Core. Gdy projekt się zmieni na FE to znowu TypeScript dostąpi łask. Nie warto czytać na zapas. Samo pobieganie po tytułach daje mi ogólny obraz tego co się dzieje w świecie .NET.

Całkiem przyjemny obowiązek

Uważam, że taka codzienna prasówka, powinna być obowiązkowa dla każdego Architekta/Tech Leada. Przynajmniej jedna osoba w zespole powinna być na bierząco. Takie przejście po tematach bardzo dobrze sprawdza się na komórce/tablecie podczas podróży z pracy/do pracy, podczas posiłku, lub wieczorem gdy nie chcemy odpalać kompa, ale jednak coś by się poczytało.

Polecam każdemu tydzień z The Moring Brew i wyrobienie sobie własnej opinii czy Ci to pomaga oraz wyrobienie własnego sposobu ile i czego czytać.

Prostsze rzucanie wyjątków, gdy nie mamy obsłużonego Enuma

Chcemy rzucić wyjątkiem, gdy mamy przypadek nieobsłużony poprzez case’y. Na przykład gdy pojawiła się nowa wartość enuma Shape.

public string GetDescription(Shape shape)
{
    switch (shape)
    {
        case Shape.Round:
            return "Round";
        case Shape.Square:
            return "Square";
        default:
            throw EnumGuard.CreateMissingEnumException(nameof(shape), shape);
    }
}

Zalety

  • dużo informacji do wyszukania w logach:
    • dostajemy nazwę parametru, który sprawił problem
    • dostajemy Typ, który wyszedł poza zakres
    • dostajemy wartość, która wyszła poza zakres
      (gdy jedyne co mamy to Exception z loga, bug się trudno reprodukuje, to każda dodatkowa informacja jest na wagę złota)
  • łatwa weryfikacja podczas CodeReview: ten oneliner jest zawsze taki sam, zmienia się tylko argument powtórzony w argument i nameof(argument).
  • w definicji nie ma żadnego ręcznie pisanego stringa

Alternatywy pisania „każdy po swojemu”

    throw new ArgumentException("Unhandled type", nameof(arguments.SomethingStrategy));
    throw new NotSupportedException($"Following configuration is not supported: {configuration}");

gdy poniższy kod zostanie przekopiowany to raz na jakiś czas ktoś zapomni że trzeba zmienić stringa, bo już inny typ sprawdzamy

    throw new InvalidOperationException($"Unknown something solution method: '{input.SomethingSolution}'");

czyli za każdym razem trochę inaczej.

Problem i rozwiązanie do rozważenia

Ktoś może zapomnieć wpisać throw i kod

EnumGuard.CreateMissingEnumException(nameof(shape), shape);

się skompiluje. Dlatego metoda ma atrybut [Pure], więc tylko jej wywołanie (brak throw) zwraca uwagę ReSharpera.

Periodic Solution Cleanup

Staram się automatyzować wiele rzeczy. Build skrypt przechodzący lokalnie i na serverze po każdym commit’ie to podstawa. Można to w prosty sposób zrobić. Jest jednak część rzeczy, które są zbyt trudne do automatyzacji, albo po prostu nie da się ich zautomatyzować.

daily cleanup

Wymyśliłem więc, że potrzebuję listę rzeczy, które trzeba co jakiś czas wykonać, aby nic nas nie zaskoczyło podczas sesji testowej lub przed „Releasem”. Później wyewoluowało to w przypominajkę w Outlooku z pełną listą kroków do wykonania. Aktualnie przypominajke mamy dla całego teamu co 2 tygodnie.

Co jest w takiej liście:

To keep clean rules like ReSpeller (which cannot be automated or it is too time consuming) we need to maintain some rules semi-automated or manual. So every 2 weeks responsible person will run the following task (can be also found in my calendar):

@all

  • Delete all branches that are not needed anymore (ie. from old PR)

@Krzysztof Morcinek:

  • Remove all unused „usings”, https://dzienwpracy.wordpress.com/2016/08/17/okazjonalne-regularne-czyszczenie-kodu-resharperem/
  • Adjust namespaces
  • Search all “null” in solution and check how to rewrite them
  • Check if there are any TODOs without owner
  • Update all Nugets (the reason for this is to not spend time on other days to update libraries (and not even think about it)

    ○ Nugets that should not be udpated: SpecFlow

  • Clean build – fresh clone of repo (develop branch) into new folder, run build (not needed every time)
  • Check if on newest ‚develop’ can be run build script on SpecFlow VM

@Dariusz Wenderlich:

  • Verify if no misspelled words are in solution (ReSpeller)

Taka sama lista jest w OneNote (trzeba ją synchronizować).

We wcześniejszym projekcie miałem też punkt o tym, żeby puścić „test integracyjny”. Taki test nie był do końca wyizolowany. Trzeba było dopilnować kilku rzeczy, odpalić UI i rozpocząć automatyczny import trwający kilka godzin, a w tym czasie było się zblokowanym na uruchamianie aplikacji. Jeśli wydaje Wam się, że to słabe podejście to osobiście uważam, że doprowadzenie do takiego stanu to był już krok do przodu. Błędy znajdowaliśmy szybciej albo była pewność, że ich nie ma.

Po kilku miesiącach krok po kroku przy okazji innych tasków udało się ten „test integracyjny” w całości wyizolować i był już regularnie wykonywany na serwerze CI. Opuścił listę Periodic Solution Cleanup.

To tylko jeden z wielu przykładów, ponieważ ta lista jest dobrym miejscem na szukanie czasochłonnych aktywności, które można w całości zautomatyzować.

Budowanie paczki Nugetowej (przykład)

nuget logo

Buduję właśnie nugeta z solucji, która ma ponad 20 projektów. Ok 10 z nich ma wylądować w paczce. Reszta to Unit Testy i Functional Testy, których nie potrzebujemy. Paczka ta jest silnikiem obliczeniowym i będzie konsumowana przez większy system wewnątrz firmy. NuGet będzie hostowany tylko wewnętrznie.

Wygląda to tak:

  • Plik nuspec, w którym najważniejsze rzeczy to zdefiniowane id (unikalna nazwa NuGeta) oraz pattern jakie pliki wybrać, wygląda on prosto:
    <files>
     <file src="YourCompany.YourProject.*" target="lib\netstandard1.3" exclude="*.deps.json;*Tests*" />
    </files>
    
  • Ze skryptu PowerShellowego podaję odpowiednią versję w jakieś będzie paczka. Wersję pobieram z jednej DLLki (hardcoded)
  • Skrypt buduje solucję do folderu „BuildArtifacts”, pełne odpalanie wszystkich testów.
  • Przekazuję więc też gdzie szukać plików (powyższe „BuildArtifacts”).
  • NuGet zbudowany komendą:
    Write-Host "Building NuGet package" -ForegroundColor Green
    & nuget.exe pack "$code_dir\SolutionName.nuspec" -Version $nugetPackageVersion -Properties Debug -BasePath $build_artifacts_dir
    
  • Jeśli paczka w takiej samej wersji jest już na Serverze NuGetowym to skrypt ostrzega, ale nic nie podmienia. Nie chcemy przypadkiem nadpisać wersji, którą ktoś ściągnął. Jest wypisana sugestia, że może zapomnieliśmy podbić wersji.
  • Skrypt pyta czy wrzucić na Server NuGetowy (no dobra, na razie tylko folder share’owany), ale tylko jeśli jej tam nie ma, jak w punkcie powyżej.

Pliki, które lądują w paczce

Jeszcze w szczegółach chciałbym omówić, które pliki lądują w paczce a które nie i dlaczego.

<file src="YourCompany.YourProject.*" exclude="*.deps.json;*Tests*" />
  • „YourCompany.YourProject.*” – pozwala odfiltrować wszystkie dodatkowe biblioteki ściągnięte NuGetem.
  • „exclude=”*.deps.json;*Tests*” – odfiltrowuje DLLki naszych własnych testów, oraz pliki *deps.json powstałe podczas kompilacji.
  • chce mieć pliki *.pdb dołączone do paczki, więc ich nie filtruje. Dzięki temu osobom korzystający z paczki będzie łątwiej debugować kod, a większy rozmiar paczki nie jest aż tak istotny, bo to paczki NuGetowe i nie lądują w kontroli wersji.

Pełny kod skryptu

Task (korzystam z psake) który tworzy paczkę wygląda więc tak:

Task Create-And-Publish-Nuget -Depends Build {
    $libraryPath = Resolve-Path "$build_artifacts_dir\Jetbrains.Rider.dll"

    $assemblyVersion = get-assembly-version($libraryPath)

    $nugetPackageVersion = [string]$assemblyVersion.Major + "." + [string]$assemblyVersion.Minor + "." + [string]$assemblyVersion.Build
    
    Write-Host "Building NuGet package" -ForegroundColor Green
    & $nuget_exe_path pack "$code_dir\Rider.nuspec" -Version $nugetPackageVersion -Properties $build_configuration -BasePath $build_artifacts_dir

    $packageName = "Jetbrains.Rider." + $nugetPackageVersion + ".nupkg";
    
    $nugetServerDestinationPath = "$private_nuget_share\$packageName"

    $isAlreadyOnNugetServer = Test-Path $nugetServerDestinationPath

    if ($isAlreadyOnNugetServer ){
        Write-Host "Package in current version already exists on nuget server! Maybe you forgot to bump version?" -foregroundcolor "yellow"
    } else {
        while ($choice -notmatch "[y|n]"){
            $choice = read-host "Are you sure you want to update Jetbrains.Rider package on $private_nuget_share host? (Y/N)";
        }

        if ($choice -eq "y"){
            Copy-Item -Path "$packageName" -Destination $nugetServerDestinationPath
            Write-Host "New package is copied on server!" -foregroundcolor "green"
        }
    }    
}

function get-assembly-version() {
    param(
        [Parameter(Mandatory=$true)]
        [string] $file
    )
    
    $version = [System.Reflection.AssemblyName]::GetAssemblyName($file).Version;
    
    $version
}

Jeden wspólny AssemblyInfo dla całej solucji

Tak wygłada AssemblyInfo.cs stworzony przez Visual Studio w nowym projekcie:

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following 
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("YourProjectName")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("YourCompanyName")]
[assembly: AssemblyProduct("YourProjectName")]
[assembly: AssemblyCopyright("Copyright © YourCompanyName 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible 
// to COM components.  If you need to access a type in this assembly from 
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("7a08ceec-6dc3-45a1-8c2d-338ab1bac448")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version 
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers 
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Ja tu zawsze widzę dużo śmieci. Przy kilkunastu/kilkudziesięciu projektach tych śmiecie jest liniowo więcej. Może czasem niektóre z nich w Waszym kontekście są potrzebne. Moje doświadczenia są jednak takie, że ten plik mógłby wyglądać:

using System.Reflection;

[assembly: AssemblyVersion("1.0.0")]

bo jedyne co naprawdę mnie interesuje to podbijanie wersji. I od tej wersji się ostatnio zaczęło, bo trzeba to podbijać i najlepiej wszędzie na raz. Można to zrobić skryptem buildującym (np u mnie obecnie PowerShell). A można skorzystać z współdzielenia jednego AssemblyInfo między wszystkimi projektami.

Źródło: Shared AssemblyInfo for uniform versioning across the solution

Skorzystałem z ręcznego dodawania linków, które jest opisane w drugiej odpowiedzi do powyższego pytania, a wygląda:

  1. Right click on the project, in which you wish to add the Shared assembly file, and select Add -> Existing Item…
  2. Select the file “SharedAssemblyInfo.cs” from the solution folder.
  3. Instead of Add, click on the the arrow next to Add and click “Add as Link”
  4. Drag down the added linked file alongside AssemblyInfo.cs in the same folder.
  5. Repeat steps 1 – 4 for all projects for which you wish to add shared assembly file.

Wersję więc podbijam ręcznie, nie potrzebuję żadnych skryptów. Plik SharedAssemblyInfo.cs wrzuciłem na tym samym poziomie co solucja i dodałem do folderu „Solution Items” w solucji.

shared assemblyinfo in solution explorer

Oprócz tego czasem pojawia się zwykły plik AssemblyInfo.cs per projekt. Jedyną rzeczą, która w nim jest to attrybut InternalsVisibleTo:

using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("YourCompany.YourProject.Core.Tests")

Zestaw nugetów, które poznałem w ostatnim roku

Według mojej subiektywnej oceny „przydania się ostatnio”:

  1. MadiatR – implementacja mediatora (dla Command & Query)
  2. TypeLITE – generuje C#->TypeScript, opisane przeze mnie TypeLITE: generator C# => TypeScript
  3. Squirrel.WindowsSquirrel: It’s like ClickOnce but Works™, zaoszczędziło nam duuuuużo czasu.
  4. Microsoft.AspNet.SignalR.Client – SignalR znam już dawno i dobrze, po prostu dowiedziałem się że jest też klient w C# i można komunikację Client<->Server oprzeć też na SignalR (czy się powinno to inna kwestia).
  5. StyleCopAnalyzersStyleCopa (wcześniej FxCopa) lubiłem zawsze, jednak ta bilbioteka jest oparta na Roslynie i jest przez to super prosta w użyciu. Mój plik configurujący https://github.com/kmorcinek/dotnet-tools-settings/blob/master/StyleCopDefault.ruleset
  6. JetBrains.Annotations – już to chyba było w projektach w których brałem udział, ale teraz sam zrobiłem setup i użyłem. Skorzystałem z Hunt your bugs in design time
  7. SolutionScripts – dzięki temu z konsoli nugeta w VS mogę korzystać ze skrótów do długich komend (jak np update-database z EF z opcjami który projekt i gdzie szukać konfiguracji).
  8. MoreLINQ – rozszerzenia do LINQ. Jedyna metoda, z której korzystamy, to „DistinctBy” – ale już dlatego warto. Inne się kiedyś pozna.