All we do is looking for some way to fulfill our needs.

środa, 29 czerwca 2011

Tagged under: , , , , ,

Proste wprowadzenie do BDD cz. 1

Dzisiaj premiera screencasta, a w zasadzie pierwsze koty za płoty - eksperymentalne próby z blogowaniem wideo i taką formą dzielenia się spostrzeżeniami.

Na pierwszy ogień idzie Behaviour-Driven Development i JBehave. Narzędzie pozwalające bardzo poukładać sobie w głowie, jaką ścieżką przejść od wymagań do implementacji. W rolach głównych występują :) User Stories, Testy akceptacyjne, Test-Driven Development i JBehave. Razem będzie 5 filmów, teraz pierwsze dwa!

Oglądaj koniecznie w rozdzielczości 720p i na pełnym ekranie



Tagged under:

Naturalny porządek refaktoryzacji pod lupą cz. 5 Ewolucja architektury


Dalszym krokiem, na dużo wyższym poziomie abstrakcji i wymagającym dogłębnego zrozumienia systemu. Na bazie pojawiających się wzorców, rozwijających się obiektów dziedzinowych po pewnym czasie dostrzegamy konieczność modyfikacji architektury. Z pomocą mogą nam przyjść wzorce architektoniczne lub wprowadzenie innych mechanizmów architektonicznych. Na tego typu przekształcenia może się składać m. in.:
  wprowadzanie warstw;
  wprowadzenie lub zmiana O/RM;
  zmiana organizacji logiki biznesowej;
  wprowadzenie lub zmiana szkieletu aplikacji.
Często w systemach przyjmuje się, że stworzona raz architektura będzie doskonale spełniać swoje zadanie przez cały cykl życia produktu. Tymczasem zmienność wymagań oraz trudność stworzenia optymalnej architektury od samego początku powoduje, że założenia architektoniczne należy cały czas monitorować oraz wprowadzać ewolucyjne zmiany, tak aby powstające rozwiązania były proste. Sztywna, nie zmieniana architektura najczęściej prowadzi do powstawania rozwiązań trudnych w zrozumieniu, naszpikowanych obejściami.

Ciągła refaktoryzacja

Przedstawiony proces przedstawia koncepcję ciągłej refaktoryzacji, w której jest ona częścią prac projektowych na każdym poziomie – architektury, projektu, kodu. Nie jest wydzieloną fazą, samodzielną częścią – jest częścią integralną prac. Chcę zaznaczyć, że powyższy proces (mimo, że tak został przedstawiony) nie jest całkowicie liniowy. Często realizując jeden z późniejszych kroków należy wielokrotnie wracać do kroków wcześniejszych. Przedstawiona strategia przedstawia bardziej kierunek działań niż sztywny algorytm.
Tagged under:

Naturalny porządek refaktoryzacji pod lupą cz. 4 Refaktoryzacja do wzorców

Stosując dotychczasowe kroki zaczynamy mieć coraz bardziej kształtne rozwiązanie, jednak głównie to co otrzymujemy to metody pogrupowane w klasy. Nadszedł czas na zastosowanie zasad obiektowych (np. zebranych w SOLID). Analizujemy kod pod kątem powtarzalności, potrzeby elastyczności, zapachów kodu i wprowadzamy wzorce projektowe. Często tam gdzie mamy wiele metod o zbliżonym schemacie będzie można zastosować Template Method lub Strategy. Tam gdzie tworzymy złożone struktury, tam stosujemy wzorzec Builder. Tam gdzie mamy do czynienia z nieskomplikowaną maszyną stanową wprowadzamy State. Tam gdzie potrzebujemy polimorficznego tworzenia obiektów używamy Abstract Factory lub jej zdegenerowanej postaci Simple Factory.
Jeśli przyjrzymy się klasie TextObfuscatorMethods z przykładu, możemy zauważyć, że większość metod przyjmuje jako parametr przetwarzany tekst. Jest to sygnał, że te metody powinny być w klasie, która ma pole zawierające przetwarzany tekst. W zasadzie możemy odwrócić sytuację i w klasie TextObfuscatorMethods umieścić pole typu przetwarzany tekst, wtedy metody staną się praktycznie bezparametrowe. Tym samym klasa nabiera charakteru wzorca Builder.
Inną opcją, pod warunkiem, że chcielibyśmy uzyskać możliwość dowolnego składania przekształceń zaciemniających tekst (stosować je wybiórczo, w dowolnej kolejności, o czym chcielibyśmy decydować w czasie wykonania), wtedy można by zastosować wzorzec Decorator.
Wersja z Budowniczym wyglądałaby jak poniżej.

public class TextObfuscator
{
    private ObfuscatedTextBuilder builder = null;
    // ...
    public string Obfuscate(string text)
    {
        builder.NewText(text);

        builder.ChangeWordsOrderRandomly();
        builder.AddMeaninglessWordsRandomly();
        builder.RemoveSeparators();
        builder.AddSeparatorsRandomly();
        builder.RemoveSpaces();
        builder.ReplacePolishCharactersWithNonPolish();
        builder.ReplaceUpperAndLowercase();

        return builder.ToString();
    }
}
public class ObfuscatedTextBuilder
{
    // ...
    private List textParts = new List();
    public virtual void NewText(string text)
    {
        this.textParts = ParseTextForWordsAndNonWords(text);
    }
    // ...
    public virtual void RemoveSpaces()
    {
        for (int i = 0; i < textParts.Count; i++)
        {
            RemoveSpacesFromTextPart(textParts, i);
            RemoveTextPartIfEmpty(textParts, i);
        }
    }

    public virtual void AddMeaninglessWordsRandomly()
    {
        for (int i = 0; i < textParts.Count; i++)
        {
            if (ShouldAddMeaninglessWords())
            {
                textParts.Insert(i, TextPart.SpaceSeparator); i++;
                textParts.Insert(i, new TextPart(DrawMeaninglessWord(), TextPartType.WORD)); i++;
                textParts.Insert(i, TextPart.SpaceSeparator);
            }
        }
    }
    // ...
}

sobota, 11 czerwca 2011

Tagged under: , ,

Naturalny porządek refaktoryzacji pod lupą cz. 3 Extract Method

W następnym kroku przyglądamy się odpowiedzialnościom poszczególnych klas oraz metodom, pod kątem dopasowania do odpowiedzialności klasy. Najlepiej przeanalizuj wszystkie metody oraz pogrupuj je pod kątem wykonywania podobnych operacji. Szukamy dla nich miejsca w innych klasach lub w nowej klasie. Pamiętaj: jeśli w danej klasie istnieje znacząca metoda prywatna (dłuższa niż 3-4 wiersze), to metoda ta powinna znaleźć się w innej klasie.
W naszym przykładzie metody głównie skupiają wokół pojedynczych operacji mających na celu zaciemnianie tekstu oraz zapewniającym wykonanie operacji z pewnym prawdopobieństwem. Możemy wyodrębnić odpowiadające tym operacjom klasy TextObfuscatorMethods oraz Probability.
Kod po tej zmianie mógłby wyglądać tak:
public class TextObfuscator
{
    // ...
    public string Obfuscate(string text)
    {
        List<TextPart> parts = methods.ParseTextForWordsAndNonWords(text);
        methods.ChangeWordsOrderRandomly(parts);
        methods.AddMeaninglessWordsRandomly(parts);
        methods.RemoveSeparators(parts);
        methods.AddSeparatorsRandomly(parts);
        methods.RemoveSpaces(parts);
        // ...
    }
}

public class TextObfuscatorMethods
{
    // ...
    public virtual void RemoveSpaces(List<TextPart> parts)
    {
        for (int i = 0; i < parts.Count; i++)
        {
            RemoveSpacesFromTextPart(parts, i);
            RemoveTextPartIfEmpty(parts, i);
        }
    }

    private static void RemoveSpacesFromTextPart(List<TextPart> parts, int i)
    {
        parts[i] = parts[i].ReplaceContents(" ", "");
    }

    public virtual void RemoveSeparators(List<TextPart> parts)
    {
        for(int i = 0; i < parts.Count; i++)
        {
            RemoveSeparatorsFromTextPart(parts, i);
            RemoveTextPartIfEmpty(parts, i);
        }
    }

    public virtual void AddSeparatorsRandomly(List<TextPart> parts)
    {
        for (int i = 0; i < parts.Count; i++)
        {
            if (ShouldAddSeparator())
            {
                parts.Insert(i, TextPart.NewSeparator(DrawSeparator())); i++;
            }
        }
    }

    private bool ShouldAddSeparator()
    {
        return probability.ShouldBeDone(ADDING_SEPARATOR_PROBABILITY);
    }
    // ...
}

public class Probability
{
    private Random random = new Random();

    public bool ShouldBeDone(double probability)
    {
        if (probability < 0.0 || probability > 1.0)
        {
            throw new ProbabilityException("Probability should be in range [0.0, 0.1]");
        }

        return random.NextDouble() < probability;
    }
}

wtorek, 7 czerwca 2011

Tagged under: ,

Czy myślałeś kiedyś o karierze trenera/konsultanta?

Jako że nasza działalność (BNS IT http://www.bnsit.pl) nabiera coraz większego rozmachu, pojawia się miejsce dla osób, które są chętne, aby pracować z innymi w celu dzielenia się wiedzą i doświadczeniem oraz chcą wspierać zespoły w zwiększaniu efektywności pracy.
Zatem jeśli masz doświadczenie praktyczne w pracy na projektami programistycznymi, jesteś kompetentny w PRZYNAJMNIEJ W JEDNYM z następujących obszarów:
- wzorce projektowe
- dobre praktyki pracy z kodem (refaktoryzacja, czysty kod, obiektowość (SOLID, GRASP, interfejsy))
- test-driven development
- domain-driven design
- scrum (agile)
- komunikacja w zespole (w kontekście projektów programistycznych),
- zarządzanie czasem dla programistów,
- zarządzanie projektami,
- zarządzanie wymaganiami, analiza.

Ważna jest wiedza i doświadczenie projektowe, co do warsztatu trenera, jesteśmy w stanie odpowiednio do tego przygotować.

Jesteśmy głównie zainteresowani stałą współpracą. Aczkolwiek ewentualnie opcja współpracy od czasu do czasu też wchodzi w grę.

Pisz śmiało: m [kroppka] sieraczkiewicz [mauppa] bnsit [kropkka] pl
Tagged under: , , ,

Naturalny porządek refaktoryzacji pod lupą cz. 2 Compose Method

Compose Method

Analiza metod takich jak przedstawiona w części 1. najczęściej prowadzi nas do zrozumienia, jakie są główne punkty algorytmu zawartego w metodzie. I to jest właśnie kolejny krok – postaraj się podzielić dużą metodę na mniejsze kroki wyodrębniając je do osobnym metod (refaktoryzacja Extract Method). Tym samym pierwotna metoda będzie się składać z sekwencji wywołań metod składowych. Przy odpowiedniej konwencji nazewniczej uzyskamy kod, który czyta się jak książkę.
Przy okazji warto co nieco posprzątać – głównie wprowadzić zmiany w mało intuicyjnych nazwach. Przykład znajdziesz poniżej.

public class TextObfuscator
{
    // ...
    public string Obfuscate(string text)
    {
        String result = ChangeWordsOrderRandomly(text);
        result = AddMeaninglessWordsRandomly(result);
        result = RemoveSeparators(result);
        result = AddSeparatorsRandomly(result);
        result = ReplacePolishCharactersWithNonPolishCharacters(result);
        result = ReplaceUpperAndLowerCharactersRandomly(result);
        result = RemoveSpaces(result);
        return result;
    }
    public String RemoveSpaces(String text)
    {
        return text.Replace(" ", "");
    }

    public String RemoveSeparators(String text)
    {
        return Regex.Replace(text, SEPARATORS_REGEX, "", RegexOptions.CultureInvariant);
    }


    public String ReplacePolishCharactersWithNonPolishCharacters(String text)
    {
        return text
                .Replace("ą", "a")
                .Replace("ł", "l")
                .Replace("ę", "e")
                .Replace("ń", "n")
                .Replace("ż", "z")
                .Replace("ź", "z")
                .Replace("ó", "o")
                .Replace("ś", "s")
                .Replace("ć", "c")
                .Replace("Ą", "A")
                .Replace("Ł", "L")
                .Replace("Ę", "E")
                .Replace("Ń", "N")
                .Replace("Ż", "Z")
                .Replace("Ź", "Z")
                .Replace("Ó", "O")
                .Replace("Ś", "S");
    }

    public String ReplaceUpperAndLowerCharactersRandomly(String text)
    {
        String result = "";
        char[] textArray = text.ToCharArray();

        foreach (char currentCharacter in textArray)
        {
            if (ShouldBeUpperAndLowerReplaced())
            {
                result += ReplaceLowerAndUpper(currentCharacter);
            }
            else
            {
                result += currentCharacter;
            }
        }

        return result;
    }
    // ...
}