wtorek, 28 sierpnia 2012

Gry improwizacyjne

Już jakiś czas uczestniczę w krakowskiej grupie improwizacyjnej. Bardzo mi się podoba to co my robimy na spotkaniach i chciałbym ci przedstawić parę moich pomysłów na gry improwizacyjne. Te 11 pomysłów powstało w trakcie robienia innych podobnych ćwiczeń.



1) ADHD

Gra dla 2-3 osób. Tworzy się platformę. Wszyscy aktorzy poruszają się tak samo. Udają, że maja ADHD i wykonują ten sam ruch, na przykład wszyscy skaczą, chodzą na czworakach, tańczą, rozmawiają z podniesioną ręką. Publiczność ustala jaki to jest ruch oraz miejsce akcji. Jest to gra bardzo dynamiczna.



2) Kontekstowy problem.

Gra dla 3 osób. Aktorzy maja do rozwiązania problem. Każda z tych osób musi komunikować się w innym kontekście (są 3 podstawowe konteksty: logiczny, emocjonalny i seksualny). Publiczność określa problem, jakie to są postacie i kto gra w jakim kontekście.



3) Mam dobrą wiadomość

Uczestnicy gry maja przedstawić 2 scenki z taka sama sytuacja i scenariuszem. W pierwszej scence maja do rozwiązania jakiś problem i za każdym razem, kiedy rozwiążą ten problem powstaje nowy, trudniejszy do rozwiązania problem. W drugiej scence uczestnicy maja te same problemy i rozwiązują je w tych samych kolejnościach, ale za każdym razem kiedy pojawia się problem są nastawieni pozytywnie i zaczynają zdanie od "jest super", "jest dobrze", " mam dobre wiadomości" itp. Gra uczy cię, żeby znajdywać coś pozytywnego w problemach.



4) Zagubieni w czasie

Gra jest dla 3 osób. Tworzy się platformę z problemem do rozwiązania. 2 osoby zaczynają scenkę. Publiczność określa jakimi postaciami historycznymi są aktorzy. Każda postać historyczna ma swój sposób na rozwiązanie problemu. Nowa osoba może wejść na scenę w każdej chwili i sama decyduje jaką postacią historyczna jest. Na scenie nie może być więcej niż 2 osoby i mniej niż 1 osoby. Kiedy trzecia osoba wychodzi na scenkę to jedna już uczestniczących osób w tej scence musi zejść. Za każdym razem, gdy osoba wchodzi na scenę jest nowa postacią historyczna.



5) Trzech doradców

Gra dla 3 osób. Publiczność ma pytania do doradców. Doradcy odpowiadają po kolei. Pierwszy doradca chce odpowiedzieć dobrze dla innych i jest perfekcjonistą. Drugi doradca jest sadysta i daje złe rady. Trzeci doradca jest chciwy i odpowiada tak, aby było dobrze dla niego, a złe dla innych ludzi. Po takiej turze jest zamiana postaciami. Każda osoba ma możliwość bycia innym doradca.



6) Problem sąsiada

2 osoby rozgrywają scenkę. Te osoby nie dążą się sympatią. Każda z tych osób ma inny problem do rozwiązania. Oni sami nie mogą rozwiązać tego problemu, ale może to jego sąsiad. Publiczność określa kim są ci sąsiedzi i jakie mają problemy.



7) Amerykański horror

Jest to 6-osobowa gra podobna do opowieści z wakacji. 5 osób bierze udział w grze jako aktorzy i 1 osoba opowiada historie w formie zdjęć. Wśród tych 5 osób jest jeden seryjny morderca. Kim jest seryjny morderca wie tylko on sam i osoba opowiadająca historie. Wszyscy aktorzy umierają. Morderca nie może ukazać się. Inni aktorzy i publiczność muszą zgadnąć kto jest morderca i jak upozorował morderstwo. Inspiracją do tej gry są takie filmy jak Krzyk, Koszmar minionego lata, Ulice strachu, Sekta, Memento, American Psycho czy Oszukać przeznaczenie.



8) Triswitch

3 osoby odgrywają scenkę. Na komendę zmiana, każdy aktor zmienia się postacią. Zmiana jest zgodnie z ruchem wskazówek zegara. Przed grą publiczność określa kim są te postacie i jakie maja relacje. Gra dobrze działa, gdy każdy aktor ma wyznaczony obszar poruszania się.



9) Natarczywy sprzedawca

Gra dla 2 osób. Jeden aktor jest sprzedawca niepotrzebnej, ale wielofunkcyjnej rzeczy, a drugi aktor jest klientem, który nie chce kupić tej rzeczy. Sprzedawca musi wymyśleć zastosowania dla klienta, a klient musi przedstawić kontrargument (wady) produktu, aby nie dokonać zakupu. Największą liczbę ofert jest wysyłana przez sprzedawcę i wymaga od niego większej kreatywności. Wydaje mi się, że w taką grę grają większość sprzedawców.



10) Rozmowa klasyfikacyjna

Gra dla dwóch osób. Osoba szukająca pracy nie wie na jakie stanowisko aplikował. Za pomocą pytań aplikant powinien się domyślić jakie to jest stanowisko. Gra jest z życia wzięta. Kiedyś umówiłem się na spotkanie rekrutacyjne i jedyne co wiedziałem to imię rekrutera oraz miejsce i czas spotkania.

Okazało się, że taka gra już istnieje.



11) Znajomy Alzheimer

To jest gra, która bardzo często występuje w życiu. Do gry potrzebni są 2 aktorów. Jedna jak i druga postać nie wie kim jest jego rozmówca, ale oni sami wiedzą, że znają swojego rozmówcę. Te informacje określa publiczność. Aktorzy próbują nakierunkować się nawzajem używając samych pytań, aby ten drugi aktor mógł zgadnąć kim jest i skąd się znają. Trochę skomplikowana gra, ale wszystko wyjdzie w praniu :)



niedziela, 26 sierpnia 2012

3 role w firmie: Przedsiębiorca, Menedżer i Technik

Chciałbym ci powiedzieć o 3 podstawowych rolach w firmie. Te role to profil techniczny, menedżerski i przedsiębiorczy. Jest to metafora zamieszczona w książce The E-Myth Revisited: Why Most Small Businesses Don't Work and What to Do About It autorstwa Michael E. Gerber. Przedsiębiorca wyznacza kierunek działania firmy, Menedżer zarządza nią, a Technik wykonuje zadania. Według Gerberta, w małej firmie jest 10% przedsiębiorców, 20% menedżerów i 70% osób technicznych. Każda osoba, która zaczyna swoją pracę w firmie ma jedną z tych ról. Problem jest wtedy, gdy każda z tych ról chce być szefem i nikt z nich nie chce mieć szefa. Posiadanie bardzo dobrych techników czy samych menedżerów w firmie nie gwarantuje osiągnięcia sukcesu. Tak samo jest z posiadaniem samych dobrych pomysłów. Dobry pomysł bez odpowiedniego zespołu jest skazany na porażkę.



Kiedy jesteś technikiem to zastanawiasz się nad techniczną implementacją danego zagadnienie. Nie lubisz delegować zadań nowym osobom, bo wiesz, że mogą coś źle zrobić. Zawsze mówisz, "jak chcesz zrobić coś dobrze, to zrób to sam". Jesteś zorientowany na teraźniejszość. Bardzo nie lubisz zmian obecnych planów. Kiedy pracujesz nad swoją pracą to jesteś zadowolony wykonując tą jedną rzeczą. Jeżeli dostaniesz nowe zadania od menedżera to jesteś bardzo zdenerwowany tym, że nie możesz dokończyć wcześniejszego zadania. Najlepsza sytuacja dla ciebie jest, kiedy menedżer dyskutuje z przedsiębiorcą, bo wtedy możesz swobodnie wykonywać swoją pracę. Nie interesujesz się życiem firmy.



Gdy jesteś menedżer to zastanawiasz się jak zoptymalizować procesy, procedury, jak zbudować stabilne środowisko dla firmy oraz jak zarządzać innymi. Jesteś pragmatyczny i żyjesz przeszłością. Dzięki twoim zdobytym doświadczeniom próbujesz dobrze planować (krótko- oraz długodystansowo ) i przewidywać trendy. Masz wszystko poukładane i bardzo nie lubisz dużych zmian. Starasz się być jak najbardziej produktywny. Powtarzasz osobom, że czas to pieniądz. Jesteś osobą, która po przedsiębiorcy "sprząta cały bałagan". Wszelkie zmiany zapisujesz. Musisz mieć dobre zdolności komunikacyjne z technikami, przedsiębiorcami, jak i innymi menedżerami. Stawiasz na gry zespołowe. Jako lider to ty jesteś odpowiedzialny za dobrą atmosferę w zespole. Lubisz delegować zadania innym osobom. Nie znam ludzi, którzy od razu zaczynali pracę od zarządzania osobami. Zanim ktokolwiek zacznie zarządzać innymi technicznymi osobami to wcześniej sam musiał być techniczną osobą, aby zrozumieć wszelkie procesy.



Ty jako przedsiębiorca jesteś marzycielem i masz wizje działania biznesu. Próbujesz znaleźć nowe drogi w firmie. Żyjesz przyszłością. Non stop przychodzą ci do głowy setki pomysłów w ciągu dnia, ale bardzo ciężko jest Ci zrealizować te pomysły. Jako wizjoner preferujesz rozgrywki jednoosobowe. Masz wizje całego systemu i nie koncentrujesz się na szczegółach. Chcesz mieć wszystko pod kontrolą. Za wszelką cenę chcesz kontrolować życie w firmie jak i poza nią. Kiedy będziesz chciał wykonać zadania technika to możesz wszystko popsuć.

Ale w gruncie rzeczy przedsiębiorca sam wcześniej był osobą techniczną. Właściciel firmy wypiekającej ciasteczka wcześniej sam był piekarzem. Właściciel firmy budowlanej zaczyna od pracy u kogoś na budowie. Właścicielka gabinetu stomatologicznego musiała wcześniej pracować jako stomatolog. Wydawca gazety zaczynał jako dziennikarz. Notariusz zaczynał jako aplikant. Większość technicznych osób myśli, żeby osiągnąć sukces w swojej firmie wystarczy mieć tylko techniczną wiedzę. Akurat ta wiedza może lekko przyczynić się do upadku firmy. Według autora tej metafory to przyczyną porażki małych firm jest spowodowane tym, że przedsiębiorcy są osobami technikami, kiedy to powinni spełniać rolę przedsiębiorcy. Wizjoner jest zniewolony zadaniami, których on sam nie powinien wykonywać. Jeżeli firma jest zależna zadaniowo od przedsiębiorcy to ten przedsiębiorca nie jest wizjonerem tej firmy, ale jest pracownikiem. Kiedy technik zaczyna być przedsiębiorcą, to będzie musiał zapomnieć wiele rzeczy jakich wcześniej się nauczył.



Możesz spróbować dopasować siebie do jednego z tych profili. Wiem, że nie jest to łatwe, tym bardziej, że jesteśmy mieszanką każdej z tych ról. Jeżeli twoje stanowisko w firmie jest niezgodny z tym co robisz albo jak postępujesz to możesz to zmienić. Każdego profilu można się nauczyć. To nie jest tak, że ktoś się urodził i od razu wie jak pisać artykuły do gazet, tworzy świetne pomysł czy zna prawo cywilne. Zdobywasz wiedzę i doświadczenie po to, aby być lepszym technikiem. Tak samo jest z profilem managerskim. Nie od razu wiesz jak prowadzić projekt czy jak dobrze rozmawiać z ludźmi. Brak równowagi dla tych ról może spowodować upadek wspólnego projektu. Każda osoba należąca do innej roli może zauważyć inny problem. Technik zauważy problemy techniczne, menedżer złą współpracę między ludźmi, a przedsiębiorca zły kierunek działania firmy.

O książce można poczytać na stronie e-myth.com lub tutaj. Skrót e-myth oznacza entrepreneurial myth.

sobota, 11 sierpnia 2012

Nie bądź krabem

Nie jestem miłośnikiem owoców morza, ale chciałbym Ci opowiedzieć o krabach i krabobraniu. Na ogół kraby są bardzo szybkie. Weźmiesz jednego kraba do pudełka i on ucieknie z niego. Wystarczy, że do tego samego pudełka włożysz drugiego kraba. Kiedy jeden krab będzie chciał wyskoczyć z pudełka, to ten drugi złapie go i nie pozwoli, aby on mógł uciec. Jeden i drugi wie o tym, że zaraz zginie, ale nie pozwoli, aby drugiemu udało się przeżyć. Nawet, gdyby działali osobno to mogli by z tego pudełka uciec. Takie zachowanie można zaobserwować w ludziach i nazywa się to syndromem krabów w wiaderku. Na pewno już spotkałeś się z taką sytuacją. To co mogę Ci doradzić to jak najszybsze odseparowanie się od takiej osoby.




A jeżeli ty jesteś krabem, to wiedz o tym jak one kończą.

wtorek, 26 czerwca 2012

Co jest w Microsoft.VisualBasic

Microsoft.VisualBasic jest niedocenianą biblioteką. Ma bardzo dużo mechanizmów jakich standardowo potrzebuję. W tym poście postaram przedstawić ci te najciekawsze informację o niej.

W Microsoft.VisualBasic znajdują się typy związane z datą. To między innymi FirstDayOfWeek czy DateInterval. Już kilka razy pisałem enum z dniami tygodnia. Inne typy to m.in. TriState

Statyczne klasy Information oraz Interaction mają bardzo przydatne metody.
var isArray1= Information.IsArray(new int[2]); //true
var isArray2 = Information.IsArray(new ArrayList()); //false

var isDBNull = Information.IsDBNull( null); //false

var isReference1 = 
    Information.IsReference(new Int32()); //false

var isReference2 = 
    Information.IsReference(new string('a', 2)); //true

var getRGB = Information.RGB(255, 127, 0); //32767

var isNumeric1 = Information.IsNumeric("123.4"); //true
var isNumeric2 = Information.IsNumeric("123.4 num"); //false

var getTypeName = Information.TypeName(
                 new FieldAccessException());
                 //FieldAccessException

Interaction.Beep();
Interaction.InputBox("Info", "Title");

string decadeRange = 
        Interaction.Partition(80, 0, 99, 10); //" 80: 89"

Zawsze potrzebowałem metody, która sprawdzi mi czy dana zmienna jest DBNull. Interesowało mnie czy jest jakieś okienko z textboxem do wpisania tekstu. Teraz już wiem, że można skorzystać z Interaction.InputBox. Nietypowa metoda jest Interaction.Partition, która zwraca przedział.

Mamy możliwość operacji na stringu, gdzie standardowo w BCL nie było takiej możliwości. Możemy m.in. usuwać wolną przestrzeń tekstu z dowolnej strony.
string text = " te st ";
var r1 = Strings.LTrim(text);
var r2 = Strings.Trim(text);
var r3 = Strings.RTrim(text);

var rightChars = Strings.Right(text,3);
Co ciekawe, w tej biblioteczce znajduje się klasa odpowiedzialna za parsowanie pliku tekstowe. Jest nią TextFiledParser. Za pomocą tej klasy można w prosty sposób parsować plik CSV. Jeżeli będziesz chciał skopiować katalog do innego folderu to będziesz mógł wykorzystać metodę FileSystem.CopyDirectory albo FileSystem.DeleteDirectory, aby usunąć katalog. W tej bibliotece jest jeszcze wiele innych interesujące możliwości, choćby nawet możemy pobrać informacje o komputerze (Devices.ComputerInfo().TotalPhysicalMemory) czy możemy pingować (Network.Ping).
Ta klasa ma jeszcze jedna, bardzo interesująca możliwość. Możemy uruchomić aplikację w postaci singletona.

Testy jednostkowe dla Expression

Pisałem test dla wyrażeń lambda i to co mnie zaskoczyło to test, który nie przechodził dla zmiennych typu epression.
[Test]
public void TestExpressionPlusOne()
{
    Expression<Func<int, int>> increase1 = x => x + 1;
    Expression<Func<int, int>> increase2 = x => x + 1;

    Assert.AreEqual(increase1 , increase2 );
}
Test nie przechodził, gdyż zmienne do porównania są anonimowymi delegatami. Należało skompilować wyrażenie, gdyż CLR próbuję w locie stworzyć nową klasę. Wtedy uzyskałem do porównania dwa skompilowane wyrażenia. Podając argumenty mogłem dostać wartości dla których można porównywać te wyrażenia. Dla łatwiejszej implementacji wykorzystałem atrybut Values, który wypełniał parametr w funkcji.
[Test]
public void TestExpressionPlusOne( 
    [Values(-99,-9,-1,0,1,9,99)] int values)
{
    Expression<Func<int, int>> increase1 = x => x + 1;
    Expression<Func<int, int>> increase2 = x => x + 1;

    Func<Expression<Func<int, int>>, int> 
compileAndInvoke = expression => expression
                                .Compile()
                                .Invoke(values);
 
    Assert.AreEqual(compileAndInvoke (increase1 ), 
                    compileAndInvoke (increase2 ));
 
}
W taki sposób utworzyło się 7 testów dla różnych argumentów wyrażenia.


Testy dla DateTime.Now

Załóżmy, że mamy klasę, w której podajemy dowolną datę i w której jest metoda zwracająca różnicę w ilościach dni między tą datą, a dzisiejszą datą. W implementacji takiego zadania stosujemy statyczną właściwość DateTime.Now. To pole przy każdym wywołaniu ma inną wartość. Problem może pojawić się kiedy będziemy musieli przetestować metodę zwracającą ilość dni (GetDaysFromNow), która w różnych momentach zwraca inny wynik.
    public class NowDateTimeCalculator
    {
        public  DateTime dateTime { get; private set; }
        public NowDateTimeCalculator(DateTime dateTime)
        {
            this.dateTime = dateTime;
        }
 
        public int GetDaysFromNow()
        {
            var timeSpanDiff = DateTime.Now - dateTime;
            return (int)timeSpanDiff.TotalDays;
        }
    }
Mamy kilka sposobów, aby mieć możliwość przetestowania tej klasy. Pierwsza możliwość to zastosowanie pośredniej klasy (interfejsu), która mogłaby dostarczyć informacji o aktualnej dacie. Tworzymy interfejs zwracający datę (Now) oraz klasę implementującą to pole.
    public interface INowDateTime
    {
        DateTime Now { get; }
    }
    public class NowDateTime : INowDateTime
    {
        public DateTime Now
        {
            get { return DateTime.Now; }
        }
   }

Jeszcze będziemy musieli zmienić naszą klasę NowDateTimeCalculator. Parametr z interfejsem będziemy wprowadzać przez konstruktor. To nam uprości pisanie testów.
public class NowDateTimeCalculator
{
    public  DateTime dateTime { get; private set; }
    private INowDateTime nowDateTime;

    public NowDateTimeCalculator(
                               DateTime dateTime,
                               INowDateTime iNowDateTime)
    {
        this.dateTime = dateTime;
        nowDateTime = iNowDateTime;
    }
 
    public int DaysFromNow2()
    {
        DateTime now = nowDateTime.Now;
        var timeSpanDiff = now  - dateTime;
        return (int)timeSpanDiff.TotalDays;
    }
}
Wywołanie wygląda następująco:
var dateTimeToCheck= new DateTime(2012, 06, 26);

var calc = new NowDateTimeCalculator(
dateTimeToCheck, new NowDateTime());

var fromNow= calc.GetDaysFromNow();
W łatwy sposób będziemy mogli zamokować interfejs INowDateTime. Test może wyglądać następująco:
[Test]
public void Check_if_GetDaysFromNow_Work_With_Mock()
{
    DateTime date_26_06_2012 = new DateTime(2012, 06, 26);
    var nowDateTimeMock = new Mock<INowDateTime>();

    nowDateTimeMock
               .Setup(x => x.Now)
               .Returns(date_26_06_2012);

    var calcToday =
 new NowDateTimeCalculator(date_26_06_2012,
                           nowDateTimeMock.Object);
 
   Assert.AreEqual(0, calcToday.GetDaysFromNow());

    var calcTomorrow =
 new NowDateTimeCalculator(date_26_06_2012.AddDays(1),
                           nowDateTimeMock.Object);
 
   Assert.AreEqual(-1, calcTomorrow.GetDaysFromNow());

    var calcYesterday =
 new NowDateTimeCalculator(date_26_06_2012.AddDays(-1),
                           nowDateTimeMock.Object);

    Assert.AreEqual(1, calcYesterday.GetDaysFromNow());
}
Takie rozwiązanie jest łatwe w implementacji i w testowaniu, ale ma 2 ważne wady - tworzymy zależności od interfejsu INowDateTime oraz takie rozwiązanie musi być znane dla całego zespołu.


Innym rozwiązanie jest zastosowanie statycznej klasy.
internal static class SystemTime
{
    internal static Func<DateTime> 
                SetDateTimeNow = () => DateTime.Now;
 
    internal static DateTime Now
    {
        get { return SetDateTimeNow();}
    }
}


public class NowDateTimeCalculator
{
    public  DateTime dateTime { get; private set; }

    public NowDateTimeCalculator(DateTime dateTime)
    {
        this.dateTime = dateTime;
    }
 
    public int GetDaysFromNow()
    {
        DateTime now = SystemTime.Now;
        var timeSpanDiff = now  - dateTime;
        return (int)timeSpanDiff.TotalDays;
    }
}
Testy wyglądają następująco:
[Test]
public void Check_if_GetDaysFromNow_Work_With_SystemTime()
{
    DateTime date_26_06_2012 = new DateTime(2012, 06, 26);

    SystemTime.SetDateTimeNow =
               () => date_26_06_2012;
    var calcToday = 
        new NowDateTimeCalculator(date_26_06_2012);
    Assert.AreEqual(0, calcToday.GetDaysFromNow());


    SystemTime.SetDateTimeNow = 
              () => date_26_06_2012.AddDays(2);
    var calcTomorrow =
    new NowDateTimeCalculator(date_26_06_2012.AddDays(1));

    Assert.AreEqual(1, calcTomorrow.GetDaysFromNow());


    SystemTime.SetDateTimeNow = 
              () => date_26_06_2012.AddDays(-2);
    var calcYesterday =
    new NowDateTimeCalculator(date_26_06_2012.AddDays(-1));

    Assert.AreEqual(-1, calcYesterday.GetDaysFromNow());
}
Takie rozwiązanie pozwala na przyjemniejsze testowanie naszej klasy. Podoba mi się łatwa zmiana aktualnej daty poprzez wyrażenie lambda. 'Wadą' może być to, że korzystamy z globalnej i statycznej klasy, która musi być znana dla całego zespołu.


Jest jeszcze jedno rozwiązanie tego problemu. To rozwiązanie jest znane tylko dla osoby, która pisze testy. Zastosujemy porównywanie wartości uwzględniając przy tym błąd(margines) w wartościach. Do tego potrzebny nam będzie interfejs z informacją o marginesie.
    public interface IMarginComparer<T> 
    {
        T CompareMargin { get; }
    }
Dla naszych testów będziemy musieli zaimplementować dwie porównywające klasy. Porównamy wartości dla typu DateTime oraz int.
public class DateTimeComparer : 
             IComparer<DateTime>, 
             IMarginComparer<TimeSpan>
{
    public DateTimeComparer(TimeSpan marginOfDateTime)
    {
        this.CompareMargin = marginOfDateTime;
    }
 
    public int Compare(DateTime x, DateTime y)
    {
        var margin = x - y;
        if (margin <= CompareMargin)
        {
            return 0;
        }
        return new Comparer(CultureInfo.CurrentUICulture)
                                       .Compare(x, y);
    }
 
    public TimeSpan CompareMargin
    {
        get; private set; 
    }
}
 



public class IntComparer : 
             IComparer<int>, 
             IMarginComparer<int>
{
    public IntComparer(int margin)
    {
        CompareMargin = margin;
 
    }
    public int Compare(int x, int y)
    {
        var diff = x - y;
        if (diff <= CompareMargin)
        {
            return 0;
        }
        return new Comparer(CultureInfo.CurrentUICulture)
                                       .Compare(x, y);
    }
    public int CompareMargin { get; private set; }
} 
Mając margines możemy określić jaka może być różnica między aktualną, a oczekiwaną wartością. Aby obliczyć ten margines będziemy musieli znać datę pisania testu (dateTimeCodeWritten) i na podstawie tej daty obliczamy ilość dni na różnicę. Gdybyśmy tą różnicę nie obliczyli, a wpisalibyśmy stałą wartość to mogłoby się okazać, że któregoś dnia wszystkie nasze testy przestałyby przechodzić.
[Test]
public void Check_if_GetDaysFromNow_Work_With_Comparer()
{
var dateTimeCodeWritten = new DateTime(2012, 06, 25);
DateTime date_20_06_2012 = new DateTime(2012, 06, 20);

var calc = new NowDateTimeCalculator(date_20_06_2012);

var dateTimeCodeWrittenDiffTimeSpan =
 DateTime.Now - dateTimeCodeWritten;

int dateTimeDiffDays = 
(int)dateTimeCodeWrittenDiffTimeSpan.TotalDays;



var dateTimeComparer = 
new DateTimeComparer(new TimeSpan(dateTimeDiffDays, 0, 0,0));

Assert.IsTrue(dateTimeComparer
.Compare(calc.dateTime.AddDays(5), DateTime.Now) == 0);


var intComp = new IntComparer(dateTimeDiffDays);

Assert.IsTrue(intComp
.Compare(calc.GetDaysFromNow(), 5) == 0);  
   
}
Nie jest to najlepiej napisany test, ale można przetestować DateTime.Now. Zaletą tej techniki jest to, że nie musimy znać (zmieniać) implementacji kodu.

Te rodzaje rozwiązań można zastosować dla wielu innych statycznych metod w tym danych środowiskowych takich jak Environment.MachineName czy Thread.Sleep().

poniedziałek, 25 czerwca 2012

Double są szalone

Typ podwójnej precyzji zawarty w .NET jest bardzo dziwny. Zapisując liczbę mamy tak naprawdę liczbą zaburzoną pewnym błędem reprezentacji.
Poniższe przykłady przedstawiają "dokładność" metody zaokrąglającej oraz prostą operację dodawania.
double res0 = Math.Round(0.500000000000000000000000000D); //0
double res1 = Math.Round(1.500000000000000000000000000D); //2
double res2 = Math.Round(2.500000000000000000000000000D); //2
double res3 = Math.Round(3.500000000000000000000000000D); //4
double res4 = Math.Round(4.500000000000000000000000000D); //4
double res5 = Math.Round(5.500000000000000000000000000D); //6
double res6 = Math.Round(6.500000000000000000000000000D); //6
W komentarzach jest informacja co metoda zwraca.
double d = 0D;
decimal m = 0M;
 
double growD = 0.1D;
decimal growM = 0.1M;
for (int i = 0; i < 10; i++)
{
    d += growD;
    m += growM;
    Console.WriteLine("double :" + d.ToString("R"));
    Console.WriteLine("decimal:" + m.ToString("G"));
    Console.WriteLine();
}
 
A wynik prostego dodawania przedstawiony jest poniżej:



Jak widać na doublach można się mocno przejechać.