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

piątek, 27 maja 2011

Tagged under: , , ,

Naturalny porządek refaktoryzacji pod lupą cz. 1

(Rozwinięcie tego wpisu powinno pojawić się w najbliższym SDJ http://sdjournal.pl/)


Refaktoryzacja to odwieczny (to chyba nie najlepsze słowo jak na krótki czas funkcjonowania dyscypliny inżynierii oprogramowania ;-)) problem - bo wszyscy wiedzą, że powinno się to robić, a nikt nie ma na to czasu. 
Jak już zaczniesz refaktoryzować, najczęściej nie wystarczy po prostu refaktoryzać, bo łatwo wpaść w szał refaktoryzacji, który polega na refaktoryzowaniu wszystkiego i za wszelką cenę. Przedstawię poniżej strategię refaktoryzacji, która w sposób systemowy pozwala podejść do tego często niewdzięcznego zadania, jednocześnie przyczyniając się do ewolucyjnego rozwoju projektu i architektury. Podpowiada też, jak się zabrać za kod odziedziczony i zacząć go refaktoryzować. Oto magiczne punkty:
1.   Zacznij od prostego rozwiązania, zgodnie zasadą Keep it simple stupid. Nie myśl zbyt dużo o wzorcach, o wprowadzaniu wszelkiej możliwej elastyczności.
2.   Z dużych metod zaczynaj wyodrębniać mniejsze składowe metody (refaktoryzacja Extract Method). Dąż do realizacji wzorca Compose Method – niech Twoja główna metoda składa się z serii wywołań mniejszych metod.
3.   Kiedy Twoje klasy będą składały się z dużej ilości małych metod, zacznij analizować odpowiedzialność klasy. Przesuń metody, które realizują inne odpowiedzialności do bardziej odpowiednich dla nich klas.
4.   Z czasem zaczynasz dostrzegać, że w Twoich rozwiązaniach potrzeba elastyczności – zacznij wprowadzać wzorce projektowe, tam gdzie potrzeba.
5.   Raz na jakiś czas (raz na kilka miesięcy przy większych projektach), analizuj to, co dzieje się z Twoim projektem. Architektura wymaga regularnego odświeżania i wprowadzania zmian, aby przystawała do pojawiających się wymagań.


Załóżmy, że mamy napisaną klasę udostępniającą metodą służącą do zaciemniania tekstu, będącego parametrem metody. Przykładowy kod znajdziesz na poniżej.
public class TextManager
{
    private TextManagerHelper _hlp = null;
    // ...
    public TextManager(TextManagerHelper _helper)
    {
        this._hlp = _helper;
    }

    private Random rnd = new Random();

    public string Convert(string text)
    {
        String result = "";
        List<TextPart> prts = _hlp.Convert(text);

        for (int i = 0; i < prts.Count; i++)
        {
            if (prts[i].Type.Equals(TextPartType.WORD) && rnd.NextDouble() < 0.2)
            {
                if (i + 2 < prts.Count)
                {
                    TextPart t = prts[i];
                    prts[i] = prts[i + 2];
                    prts[i + 2] = t;
                }
            }
        }

        for(int i1 = 0; i1 < prts.Count; i1++)
        {
            if (rnd.NextDouble() < 0.2)
            {
                prts.Insert(i1, new TextPart(" ", TextPartType.NONWORD)); i1++;
                String[] wds = new String[] { "i", "a", "aczkolwiek", "poniekąd" };
                int ind = rnd.Next(wds.Length);
                prts.Insert(i1, new TextPart(wds[ind], TextPartType.WORD)); i1++;
                prts.Insert(i1, new TextPart(" ", TextPartType.NONWORD));
            }
        }

        String result2 = "";

        foreach (TextPart part in prts)
        {
            result2 += part.Contents;
        }

        result = result2;
        result = Regex.Replace(result, @"[\?!-\.,:;'\(\)]", "", RegexOptions.CultureInvariant);

        String result1 = "";

        for ( int i2 = 0; i2 < result.Split(' ').Length - 1; i2++)
        {
            if (rnd.NextDouble() < 0.5)
            {
                char [] chs = new char[] { '.', ',', '!' };
                int j = rnd.Next(chs.Length);
                result1 += result.Split(' ')[i2] + chs[j];
            }
            else
            {
                result1 += result.Split(' ')[i2] + " ";
            }
        }
        result1 += result.Split(' ')[result.Split(' ').Length - 1];
        result = result1;

        result = result
            .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");

        String result3 = "";
        char[] tArray = result.ToCharArray();

        foreach (char ch in tArray) {
            if (rnd.NextDouble() < 0.3)
            {
                char? newCh = null;
                if (Char.IsLower(ch))
                {
                    newCh = Char.ToUpper(ch);
                } else
                {
                    newCh = Char.ToLower(ch);
                }

                result3 += newCh;
            }
            else
            {
                result3 += ch;
            }
        }

        result = result3.Replace(" ", "");

        return result;
    }
}



C. D. N.