Stack technologiczny w aktualnym projekcie

  • MVC 5 + WebApi 2 (najnowsze ale nie .NET Core)
  • Angular 1.5 (nie SPA, wtedy gdy trzeba na pojedynczej stronie) + TypeScript
  • TypeLite – biblioteka generuje DTO w TypeScript na podstawie DTO w C#. Gdy zmieniłem coś w C# to dostaję błędy kompilacji w TypeScript.
  • Bootstrap
  • AutoMapper
  • EntityFramework 6
  • MediatR – implementacja wzorca Command
  • SignalR – zarówno między ServerJS Client, jak i WindowFormServer, działa super.
  • Ninject
  • xUnit, Moq, AutoFixture
Opublikowano Programowanie | Dodaj komentarz

Jaki wyjątek rzucać gdy mamy nieobsłużonego enuma

Gdy sterujemy przepływem sterowania za pomocą switcha i tym co sprawdzamy jest enum to warto obsłużyć też przypadek default. Czyli co stanie się gdy enum ma wartość spoza tych wymienionych w case‚ach. Warto wtedy rzucić wyjątek.

Taki kod wygeneruje nam ReSharper (i jest to niezły kod):

void Execute(DocumentStatus documentStatus)
{
    switch (documentStatus)
    {
        case DocumentStatus.Draft:
            // Do sth
            break;
        case DocumentStatus.Released:
            // Do sth
            break;
        default:
            throw new ArgumentOutOfRangeException(nameof(documentStatus), documentStatus, null);
    }
}

Dlaczego jest to ważne? Poniższy kod zarówno się skompiluje jak i wykona poprawnie w runtime, mimo że żadna z wartości nie przyjmuje 111:

DocumentStatus AssignInvalidValue()
{
    return (DocumentStatus) 111;
}

Więcej w Rzutowanie na Enum z niepewnego źródła

Błąd, który dotychczas robiłem to wypełniałem 3-ci argument w konstruktorze klasy ArgumentOutOfRangeException. Pisałem tam coś w stylu:

throw new ArgumentOutOfRangeException(nameof(documentStatus), documentStatus,
    $"Enum '{documentStatus.GetType().Name}' has invalid value '{documentStatus}'");

Dzięki czemu przechwycony wyjątek wyglądał tak:

enum exception

Jest to dla tego przepadku zupełnie zbędne. Gdy przekażemy tam nulla to przechwycony wyjątek będzie wyglądał tak:

enum exception without message

A mając stack trace zobaczymy gdzie co i jak się podziało.

Metoda fabrykująca takie wyjątki

Jednak najlepszym sposobem jest jednak opakowanie tworzenia tego wyjątku. Dla mnie też kiedyś dziwne było żeby zwracać z funkcji wyjątek który dopiero później będzie rzucany. Przekonałem się jednak, że to dobra praktyka, takie scentralizowane tworzenie np message dla wyjątku. Np taka klasa:

public static ArgumentOutOfRangeException CreateMissingEnumException<T>(string paramName, T value)
    where T : struct 
{
    return new ArgumentOutOfRangeException(paramName, value,
        $"Enum '{value.GetType().Name}' has invalid value '{value}'");
}

i wywołanie oraz podgląd przechwyconego wyjątku:

enum create missing enum exception

Opublikowano Programowanie | Otagowano , , | 2 komentarzy

Przykład fajnej Extension Method

Kod, który mnie natchnął:

var propertiesToDelete = someEntity.Properties
    .Where(x => x.PropertyName == "NAME")
    .ToList();

foreach (var property in propertiesToDelete)
{
    someEntity.Properties.Remove(property);
}

Natchnął bo zmieniłem na:

foreach (var property in someEntity.Properties.Where(x => x.PropertyName == "NAME"))
{
    someEntity.Properties.Remove(property);
}

To było słabe… gdybym sprawdzał po kimś takie coś, to bym może zauważył, ale sam to zrobiłem i nie zauważyłem: modyfikowanie kolekcji po której się iteruje, leci wyjątek. Code Review – wiele oczu patrzy – naprawdę się przydaje, żeby takich problemów unikać. Anyway, nie o tym.

Szerszy kontekst

Properties z powyższego kodu to ICollection<T>, które oznacza zależność jeden do wielu i Entity Framework zmapuje to i dobrze zapisze/wyciągnie z bazy, podobnie będzie też wyglądać odpowiadające mu DTO lub ViewModel:

public class SomeEntity
{
    // składnia C# 6
    public virtual ICollection<Property> Properties { get; } = new List<Property>();
}

Pod spodem jest jednak List<T>. A na typie List jest metoda RemoveAll(Predicate<T> predicate).

Napisałem więc coś takiego

Kod do odpalenia i testy

Dzięki temu wywołanie kodu z którym wystartowaliśmy będzie wyglądać tak:

someEntity.Properties.RemoveAll(x => x.PropertyName == "NAME");

Co zdecydowanie zwiększa czytelność. Ominiemy też wywołowanie LINQ i wszystko odbędzie się na bardziej wydajnej RemoveAll() z klasy List<T>.

Problemy

Wydaje mi się to fajnym kawałkiem kodu. Czy może ktoś widzi tutaj jakiś potencjalny problem?

Opublikowano Programowanie | Otagowano , , , | 1 komentarz

Zbyt zajęty? Czyżby zapierdol w projekcie?

too busy

busy

are-you-too-busy-to-innovate1

Jakie mogą być efekty:

the-busy-bee-paradox-agile-tour-lille-2014-4-638

Co może pomóc:

small-batches

Moja opinia jest taka:

ZAWSZE są pilne rzeczy do zrobienia, ZAWSZE biznes oczekuje, że dostarczasz wartość.
I Ty ją oczywiście dostarczaj, ale to od Twojego profesjonalizmu i kultury pracy zależy czy tylko bezmyślnie napierdalasz Lines Of Code, czy może zastanawiasz się co i w jaki sposób najlepiej zrobić.

Opublikowano Tip of the day | 2 komentarzy

Jak wygląda poprawna implementacja enuma

Tak IMHO powinien wyglądać dobrze napisany enum:

public enum DocumentStatus : byte
{
    Draft = 1,
    Approved = 2,
    UnderRevision = 3,
    Released = 4
}

Nie enumerujemy od zera

„0” jest domyślną wartością dla enuma (bo pod spodem musi być typ całkowity). Dlatego chcemy aby nasze znaczące wartości zaczynały się od jedynki. Wtedy prościej wyśledzić w której ścieżce wykonania jest błąd, spowodowany nieustawieniem wartości. W naszych switchach zawsze wtedy wpadniemy w default gdzie najlepiej rzucić wyjątkiem.

Pozbyć się wartości Undefined

Ten enum mógłby wyglądać tak:

public enum DocumentStatus : byte
{
    Undefined = 0,
    Draft = 1,
    Approved = 2,
    UnderRevision = 3,
    Released = 4
}

Inne spotykane nazwy to Unknown, NotExists, NoValue, itp.

Niby podobnie do wzorcowego przykładu, ale jednak ma wady. Gdy generejemy instrukcję switch to z pomocą R# dostaniemy wypełnione wszystkie wartości enumów. I niestety dostaniemy też case dla Undefined, a lepiej żeby te przypadki wpadły do default i spowodowały wyjątek.

switch with undefined

Dziedziczyć po byte?

Wystarczy nie dziedziczyć po niczym wtedy domyślnie jest to int i wszystko jest w porządku. W przykładzie dziedziczę po byte ponieważ enum ląduje w bazie (korzystam z EF) i tam staram się używać typów, które mniej miejsca zajmują. W .NET nie ma to praktycznie znaczenia.

Czy nadawać wartości liczbowe wszystkim?

Kiedyś przeczytałem rozróżnienie, żeby nadawać wszystkie wartości tylko tym enumom, które lądują w bazie. To jest na pewno ważne, bo zdarza się często, że usuwamy jakąś wartość ze „środka”. Było tam też napisane, że dla enumów, które nie lądują w bazie nie powinno się tego robić, tylko zostawić to frameworkowi.

public enum DocumentStatus : byte
{
    Draft = 1,
    Approved,
    UnderRevision,
    Released
}

W praktyce wydaje mi się, że lepiej zdecydować się na jedno i zawsze nadawać wartości.

Czy macie sytuację gdzie lepiej nadać tylko pierwszą wartość równą 1 (żeby domyślnie nie numerowało od 0), a numerowanie pozostałych zostawić frameworkowi?

Opublikowano Programowanie | Otagowano , | 4 komentarzy

SOLID Architecture in Slices not Layers

Oglądałem wartą polecenia prezentację: „SOLID Architecture in Slices not Layers” preprowadzoną przez Jimmy’ego Bogarda (autor min AutoMapper, MediatR)

Obrazek który fajnie podsumowuje to:

slices per feature

Od teraz w ten sposób będę się starał organizować kod. Stare nawyki ciąglę są gdy chcę utworzyć nowy plik. Powoli ale do przodu.

Projekt Githubowy na dziś

Contoso University sample re-done the way I would build it – Project przykładów Microsoftowego Contoso Uniwersity zrobiony wg Jimmy’ego zgodnie z prezentacją.

Widok listy katalogów tego projektu:

Contoso university by jimmy bogard

Dziś miałem ciekawy przykład kiedy się od razu przydała taka organizacja: trzeba było wyrzucić jedną funkcjonalność. Dzięki temu jestem pewien (na tyle na ile mogę) że usunąłem wszystkie klasy powiązane z danym FeatereX. Wsześniej musiałbym gonić po całym projekcie aby z różnych katalogów usuwać wszystko związane z FeatereX.

Minusy

Jest to oczywiście inna konwencja niż „standardowe MVC”, jakiś junior może być zawiedziony że widoki nie są wszystkie w katalogu Views. Próg wejścia może być większy. Zgadzam się, ale nie demonizowałbym tego – są większe zalety.

Opublikowano Programowanie | Otagowano , , | Dodaj komentarz

Building Blocks dla początkującego architekta

bottega logo

Naczytałem się na http://bottega.com.pl/artykuly-i-prezentacje

Z powyższego linku wybrałem te najciekawsze i które radzę poczytać (mój subiektywny wybór):

Building Blocks dla Twojej lewej półkuli: połączenia podejścia obiektowego, proceduralnego, funkcyjnego w codziennej pracy z kodem

Cztery smaki odwracania (i utraty) kontroli: Dependency Injection, Events, Aspect Oriented Programming, Framework

Zarządzenie złożonością przez trójpodział logiki – Open/closed principle w praktyce

Podstawowe Building Blocks DDD

Zaawansowane modelowanie DDD – techniki strategiczne: konteksty i architektu- ra zdarzeniowa

Sposób na projektowanie złożonych modeli biznesowych

A dopiero potem:
Wzorce analityczne modeli biznesowych na przykładzie Party – odkrywanie krok po kroku kolejnych rozwiązań

Mapowanie relacyjno-obiektowe prawdziwych obiektów – rzecz o DDD i JPA

Co mi to dało? Już nie tak na ślepo decyduję czy dana metoda ma być tutaj a nie tam. Są pewne fajne receptury mówiące gdzie w architekturze powinna wylądować pisana przez nas funkcjonalność i z jakich klocków ją zbudować. Architektura to nie luksus.

Opublikowano Programowanie | Otagowano , , | Dodaj komentarz