wtorek, 31 grudnia 2013

Kalendarz w oracle

Z racji tego, że nowy rok się zbliża, postanowiłem napisać zapytanie, które zwraca dni w bieżącym miesiącu - taki kalendarzyk dla danego miesiąca. Poniżej jest przedstawiony kod. Proszę zauważyć, że pierwszy dzień tygodnia zaczyna się w niedzielę. Dla innej kultury będzie inne zapytanie.

with x
      as (
    select *
      from (
    select to_char(trunc(sysdate,'mm')+level-1,'iw') wk,
           to_char(trunc(sysdate,'mm')+level-1,'dd') dm,
           to_number(to_char(trunc(sysdate,'mm')+level-1,'d')) dw,
           to_char(trunc(sysdate,'mm')+level-1,'mm') curr_mth,
           to_char(sysdate,'mm') mth
      from dual
     connect by level <= 31
           )
     where curr_mth = mth
    )
    select max(case dw when 2 then dm end) Mo,
           max(case dw when 3 then dm end) Tu,
           max(case dw when 4 then dm end) We,
           max(case dw when 5 then dm end) Th,
           max(case dw when 6 then dm end) Fr,
           max(case dw when 7 then dm end) Sa,
           max(case dw when 1 then dm end) Su
      from x
     group by wk
     order by wk
;
Dla miesiąca grudzień mamy taki wynik:
Niestety dla ostatnich dni roku (30 i 31 grudnia) mamy problem ze standaryzacją numerów miesiąca w roku. Dla tych dwóch ostatnich dni, numer tygodnia w roku jest 1 dla parametru IW (więcej o parametrach daty znajdują się w funkcji to_char). Będziemy musieli skorzystać z parametru WW.
select *
      from (
    select to_char(trunc(sysdate,'mm')+level-1,'iw') wk,
           to_number(to_char(trunc(sysdate,'mm')+level-1,'ww')) wn,
           to_char(trunc(sysdate,'mm')+level-1,'dd') dm,
           to_number(to_char(trunc(sysdate,'mm')+level-1,'d')) dw,
           to_char(trunc(sysdate,'mm')+level-1,'mm') curr_mth,
           to_char(sysdate,'mm') mth
      from dual
     connect by level <= 31
           )
     where curr_mth = mth
;
I na końcu wystarczy zgrupować
with x
      as (
    select *
      from (
    select to_char(trunc(sysdate,'mm')+level-1,'iw') wk,
           to_number(to_char(trunc(sysdate,'mm')+level-1,'ww')) wn,
           to_number(to_char(trunc(sysdate,'mm')+level-1,'dd')) dm,
           to_number(to_char(trunc(sysdate,'mm')+level-1,'d')) dw,
           to_char(trunc(sysdate,'mm')+level-1,'mm') curr_mth,
           to_char(sysdate,'mm') mth
      from dual
     connect by level <= 31
           )
     where curr_mth = mth
    )
    select 
           --wk,
           --max(wn) wna,
           max(case dw when 2 then dm end) Mo,
           max(case dw when 3 then dm end) Tu,
           max(case dw when 4 then dm end) We,
           max(case dw when 5 then dm end) Th,
           max(case dw when 6 then dm end) Fr,
           max(case dw when 7 then dm end) Sa,
           max(case dw when 1 then dm end) Su
      from x
     group by wk
     order by max(wn)
;
A rezultat takiego zapytania wygląda następująco:

poniedziałek, 30 grudnia 2013

Kowale 2.0

Ostatnio oglądałem filmik przedstawiający modelowanie w stali. Ze stalą zawsze kojarzyły mi się wielkie i ciężkie konstrukcie mostów jak Golden Gate Bridge ( zwany również Mostem Samobójców). Ale konstrukcje stalowe mogą być na tyle lekkie i elastyczne, że mogą być modelowane poprzez ciśnienie. Prezenter 'nowej stali' przedstawia nie tylko technologię, ale również sposób projektowania mebli ze stali. Jednym z mebli przyszłości jest Polski Ludowy Obiekt Pompowany Powietrzem:


Zapraszam do obejrzenia filmiku:


sobota, 28 grudnia 2013

Odliczanie do Nowego Roku w PowerShell

Skoro już wcześniej zrobiłem odliczacz do świąt Bożego Narodzenia, to teraz będzie odliczacz do Nowego Roku.
function  Countdown-NewYear
{
    $dateNow = [DateTime]::Now
    $dateNewYear = [DateTime]::ParseExact( [string]
($dateNow.Year+1) + "-01-01-00-00-01", "yyyy-MM-dd-hh-mm-ss", $null) 
 
    return $dateNewYear - $dateNow
}

$newYearCounter = Countdown-NewYear
Write-Host "There are $($newYearCounter.Days) days and $($newYearCounter.Hours) hours until New Year"

Kod jest prawie identyczny jak w poprzednim odliczaczu. Tylko teraz dokładność czasu będzie uzależniona od odległości. Jeżeli do Nowego Roku będzie więcej niż 1 dzień to odliczacz przedstawi wartość w jednostkach dni, jeżeli będzie mniej niż jedna godzina, ale więcej niż jedna minuta to będzie w minutach, itp.
function ToCountdownString
{
    param
    (
        [timespan] $timeSpan
    )
    if($timeSpan.Days -gt 1)
    {
        return "$($timeSpan.Days) days"
    }
    if($timeSpan.Hours -gt 1)
    {
        $timeRemains = $timeSpan.Days * 24 + $timeSpan.Hours
        return "$timeRemains hours"
    }

    if($timeSpan.Minutes -gt 1)
    {
        $timeRemains = $timeSpan.Hours * 60 + $timeSpan.Minutes
         return "$timeRemains minutes"
    }

    if($timeSpan.Seconds -gt 1)
    {
        $timeRemains = $timeSpan.Minutes * 60 + $timeSpan.Seconds
         return "$timeRemains seconds"
    }

    $timeRemains = $timeSpan.Seconds * 1000 + $timeSpan.Milliseconds
    return "$timeRemains milliseconds"
}
Kod wywołania wygląda następująco:
$newYearCounter = Countdown-NewYear
$countdown = ToCountdownString -timeSpan $newYearCounter 
Write-Host "There are $countdown until New Year"
Nie przesadzajmy, nie musisz sprawdzać tego kodu w Sylwestra:) Idź i spędź ten czas z przyjaciółmi, ukochaną osobą albo z rodziną.

piątek, 20 grudnia 2013

Base64 z pliku

Raz na jakiś czas fajnie jest napisać jakiegoś jednolinijkowca :)
To tym razem proste przedstawię Ci pobieranie zawartości pliku zapisanego w formacie Base64 w PowerShellu:
function Get-Base64FromFile($Path)
{
    return [Convert]::ToBase64String((Get-Content $Path -Encoding Byte))
}
Wywołanie jest następujące:
Get-Base64FromFile file 
Możemy sprawdzić czy za pomocą funkcji odwrotnej można uzyskać zawartość pliku. Pomocne będą nam dwie funkcje:
function Get-ContentFromBase64($base64Str)
{
    return [Convert]::FromBase64String($base64Str)
}

[Reflection.Assembly]::LoadWithPartialName("System.Text")
function Get-StringFromContent( [byte[]] $content)
{

    return [System.Text.Encoding]::UTF8.GetString($content)
}
i sprawdzamy zawartość w następujący sposób:
Get-StringFromContent( Get-ContentFromBase64( Get-Base64FromFile file ))

sobota, 14 grudnia 2013

Czas do świąt w PowerShell

Święta coraz szybciej się zbliżają, ale za ile dni będą te święta? Z pomocą (jak zawsze) na odpowiedzenie przychodzi mi powershell :)

function  Countdown-Xmas
{
    $dateNow = [DateTime]::Now
    $dateXmas = [DateTime]::ParseExact( 
[string]($dateNow.Year) + "/12/25", "yyyy/MM/dd", $null) 
    
    if($dateNow -gt $dateXmas)
    {
        $dateXmas = $dateXmas.AddYears(1)
    }   
    
    return $dateXmas - $dateNow
}

A wywołanie wygląda następująco:

$xmasCounter = Countdown-Xmas
Write-Host "There are $($xmasCounter.Days) days and $($xmasCounter.Hours) hours until Xmas"


Enkapsulacja widoku raportu ETL

I znów post z cyklu wstęp do ETL. Tym razem opowiem Ci o końcówce procesu, która jest tą przyjemniejszą częścią. Wartość procesu ETL można ocenić na podstawie jego wizualizacji wyników. Na ogół cały proces ETL jest niewidoczny dla użytkownika. Wygenerowany raport z procesu ETL jest jedynym etapem w cyklu ETL, gdzie managerowie wyższego szczebla mogą dokonać oceny tego cyklu. Aby dane mogły być odpowiednio przedstawione w raporcie to wygląd tych danych musi być wielokrotnie przekształcany.

Na początku dane były w źródłach, a następnie dzięki procesowi ETL, dane te zostają przekształcone i załadowane do miejsca docelowego. Z wygenerowanych danych tworzony jest model raportu, w którym przedstawiamy jakie dane są potrzebne do wyświetlenia. Oczywiście nie wszystkie informacje powinny być przedstawiane. Widok raportu (report view) składa się z modelu raportów oraz formy przedstawiania tego raportu. Do wyglądu formy zaliczają się takie modyfikacje wyświetlanych danych jak :
- sortowanie
- filtrowanie
- grupowanie
- format wyświetlania wartości (np. dla daty)

Poniższy rysunek przedstawia przejście z surowych danych do wyglądu raportu:

niedziela, 8 grudnia 2013

Ostatnie posty w PowerShellu

Skoro już siedzę troszkę w PS to pomyślałem sobie, że napiszę skrypt do pobierania postów z bloga. Skorzystałe z feedburner jako zasób wpisów.
function Get-ArekOnSoftwarePosts
{
    $url  = "http://feeds.feedburner.com/ArekOnSoftware"
    $webClient =  New-Object Net.WebClient
    $webClient.Proxy = [System.Net.WebRequest]::DefaultWebProxy
    $webClient.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
    $webClient.Encoding = [System.Text.Encoding]::UTF8;
    $feed = $webClient.DownloadString($url)
    ([xml]$feed).rss.channel.item | Select title, pubDate, origLink, category, description
}

Możemy wziąć 3 ostatnie wpisy o powershellu:
$posts = Get-ArekOnSoftwarePosts 
$posts | ?{$_. category -icontains "PowerShell" } 
| select title,  origLink -first 3

A rezultat z działania skryptu jest następujący:

Oczywiście w miejsce zmiennej $url możesz zmienić adres na RSS feed z innego bloga.

sobota, 7 grudnia 2013

Monitorowanie procesu ETL

Jak przy każdym projekcie, wcześniej czy później zespół dochodzi do wniosku, że potrzebne jest narzędzie/metody/procesy do monitorowania działania projektu. Chciałbym Ci przedstawić przykład monitorowania procesu ETL.


Proces ETL może być bardzo skomplikowany i niektóre zadania mogą nie działać poprawie. W tym celu dokonuje się logowania błędów. Logowanie pozwala na szybszą diagnozę, aby wywnioskować, co mogło wywołać błąd. Im więcej loguje się zdarzeń występujących w procesie ETL tym diagnoza jest dokładniejsza, ale każde logowanie wymaga dodatkowej przestrzeni pamięci. Same logowanie błędów nie wystarcza.

Oprócz logowania zdarzeń wymaga się narzędzia, które mogłoby sprawdzać różne części całego procesu ETL. Sprawdzenie połączenia do różnych zasobów jest dokonywana za pomocą mechanizmu pulsacji (heartbeat), które co dany interwał czasowy sprawdza zasób. Jeżeli dany zasób nie jest dostępny to wywoływany jest alarm (alert). Niektóre zasoby procesu ETL nie muszą być sprawdzane za każdym razem, a wystarcza, że zostaną sprawdzone raz przy uruchomieniu monitora (single alert). Monitor może sprawdzać czy istnieje połączenie do danych źródłowych. Na przykład, monitor sprawdza czy jest połączenie z bazą danych. Czasami samo sprawdzenie schematu bazy danych nie wystarcza i należy sprawdzić format zapisanych danych. W projektach rozproszonej odpowiedzialności, dane w bazie danych są zmieniane i zmiana formatu może spowodować nie wyekstraktowanie wszystkich danych lub co jest gorsze – ekstraktownie błędnych danych. Takie sprawdzenie ostrzeże nas przed uruchomieniem proces ETL. Dodatkowo możemy sprawdzić czy mamy dostęp do wymaganych plików oraz czy jest możliwość dostępu do sieci wewnętrznej. Sprawdzenie dostępu do sieci wewnętrznej nie tylko pozwoli nam na dostęp do danych referencyjnych, ale mamy możliwość sprawdzenia czy nie mamy problemów z połączeniem sieciowym. Czasami baza danych lub pliki są dostępne z jednego komputera (z danej podsieci), ale ten zasób może być niedostępny dla servera (z innej podsieci). Oprócz monitorowania danych wejściowych to dane wyjściowe (targets) również są monitorowane. Sprawdza się czy jest możliwość połączenia się do hurtowni danych (lub innego docelowego miejsca przechowywania danych).

Można monitorować komunikację w procesie ETL. Poszczególne komponenty ETL mogą komunikować się ze sobą za pomocą kolejki komunikatów (message queues) (lub przez Interprocess Communications). Każda kolejka jest wypełniana (produkcja) informacjami z jednego komponenty, a następny komponent wykorzystuje (konsumpcja) te informacje do dalszego działania. Jeżeli kolejka nie jest konsumowana to wiadomo, że następny komponent nie został wystartowany. Oprócz konsumpcji komunikatów sprawdzana jest ilość tych komunikatów. Jeżeli ilość jest za mała lub za duża to jeden z komponentów musiał wygenerować błąd lub istnieją duplikaty informacji.


Poniżej jest zawarty rysunek z przykładowym schematem monitorowania procesu ETL:


niedziela, 1 grudnia 2013

Kopiowanie nazw plików

Bardzo nie lubię pisać skryptu dwa razy tego samego - tak było z dzisiejszym skryptem. Postanowiłem na przyszłość zamieścić prosty skrypt, który kopiuje nazwy plików z jednej lokalizacji do drugiej. Pliki mają 0B - idę na ilość plików, a nie na ich wielkość :)

function Copy-File-By_FileName {
Param(
    [string] $sourceLocation,
    [string] $destinationClocation
)
$files = gci -force   $sourceLocation  -recurse

$files | foreach {
        $fileEnding = $_.FullName.Replace($sourceLocation, "");
        $secondItem = $destinationClocation  + $fileEnding ;
        
        if(Test-Path $secondItem)
        {
            write-host "File $secondItem exist";
        }
        else
        {
            Write-Host "Creating empty file at location: $secondItem";   
            New-Item $secondItem -type file       
        }
    }
}


Przykład użycia kopiowania nazw plików:
$elapsed = [System.Diagnostics.Stopwatch]::StartNew()
Copy-File-By_FileName -sourceLocation "C:\Files\" -destinationClocation "C:\EmptyFiles\"
write-host "Time: $($elapsed.Elapsed.ToString())"


sobota, 30 listopada 2013

Typy transformacji pól w ETL


Dalszy ciąg krótkiego wprowadzenia do ETL. Tym razem chciałbym Ci troszkę więcej powiedzieć o transformacji, a dokładnie o transformacji elementów ściąganych z źródła,


Transformacje pojedynczych elementów w procesie ETL dzielą się na transformacje pojedynczego pola oraz transformacje wielu pól. Transformacje pojedynczego pola są bardzo proste. Najczęściej jest to pewna modyfikacja starej wartości w nową wartość. Oprócz wartości możemy zmienić sposób prezentacji tej wartości. Można np. zamienić stopnie Fahrenheita na stopnie Celisiusza. Takie zamiany nazywają się transformacjami algorytmicznymi (algorithmic transformation), które wymagają obliczeń matematycznych.



Szczególnym przypadkiem transformacji pojedynczego pola jest transformacja wymagająca dodatkowej tabeli z odnośnika wartości (table lookup). Poniżej przedstawiona jest transformacja, która zamienia wartość „code” ze źródła na wartość „name”, wykorzystując przy tym dodatkową tabelę z wartościami. Taka transformacja może zamieniać skróty państw na całe nazwy państw. Głównym zadaniem tej transformacji jest zwiększenie czytelności docelowych danych.



Wśród transformacji wielu pół mamy transformacje „wiele do jeden” (zapisuje się w postaci M:1). Modyfikacja ta ma za zadanie scalanie wartości z różnych pól i zapisanie ich w jednym polu. Taką transformację stosuje się, w celu identyfikacji danego elementu. Przykładem może być tworzenia unikatowego klucza, który składa się z nazwy produktu, producenta oraz numeru dodatkowego.



Drugim typem transformacji wielu pól jest transformacja z jednego pola do wielu pól (1:M). Przykładem takiej transformacji może być w sytuacji kiedy wartość źródła składała się z wielu zmiennych. Powodem, dla którego przechowuje się kilka wartości w jednym polu jest wydajność jej metody archiwizacji w bazie danych. Jednak przy takiej transformacji istnieje niebezpieczeństwo zmiany formatu przechowywania wartości w źródle co może prowadzić do zakłócenia przebiegu procesu.



Oczywiście istnieje transformacja "wiele do wielu", ale jest to połączenie dwóch powyższych typów transformacji.

czwartek, 28 listopada 2013

Przemilczana premiera PowerShell 4.0

Korzystałem z Windows 8 i miałem możliwość aktualizacji systemu do Windows 8.1. Po aktualizacji (oprócz problemów z Apple Boot Camp'em oraz powrotu starego-dobrego przycisku Start) to nie zauważyłem jakieś większej różnicy z poprzednią wersją.

Któregoś dnia wywołałem polecenie $PSVersionTable, a tu dostaje taki wynik:


Okazuje się, że mam PowerShell w wersji 4.0. Ta wersja należy do pakietu Windows Management Framework 4.0 i ten pakiet można pobrać stąd. Instalując Windows 8.1 dostajesz do tego PowerShell v4. Nowy PS jest domyślnie dostępny dla systemów operacyjnym Windows 8.1 oraz Windows Server 2012 R2.


Wiem, już dawno nie byłem na PowerShell Magazine, a polska grupa użytkowników PowerShell jeszcze ma do nadrobienia i mogłem sam zainteresować się nową wersja, ale dziwi mnie to, że premiera PS została przemilczano przez Microsoft i pozostawiona bez większego odzewu.


W najbliższych dniach sprawdzę co jest nowego w PS v4.


niedziela, 24 listopada 2013

Wyciągnięta nauka z statystyki

Zastanawiam się, po co te wszystkie metody statycznej analizy danych, szukanie reguł i zależności, grupowanie elementów i inne bardziej lub mniej złożone metody analizy skoro możemy mieć błędne dane. Najważniejszą naukę jaką zdobyłem z analizy danych jest to, że metody analizy dobrze działają, ale dane zostały źle uzyskane.

Znasz to przysłowie:

Statystyka nie kłamie,
ale kłamcy liczą.


albo jak J.Stalin mawiał:
Nieważne, kto głosuje, ważne, kto liczy głosy.

Nawet w dzisiejszych czasach da się oszukać ludzi na wielką skalę.



sobota, 23 listopada 2013

Data Marty - uszczuplona hurtownia danych

Wcześniej pisałem o procesie ETL i w nim wspominałem o Data Martach jako zbiorze załadowanych danych. Data Marty są nazywane tematycznymi hurtownie danych. Są tworzone w celu zapewnienia wsparcia procesu podejmowania decyzji osobom odpowiedzialnym za konkretny obszar biznesowy. W przypadkach, gdy tylko część danych jest poddawana analizie, warto rozważyć użycie data martów. Data Mart jest generowany na bazie hurtowni danych i zawiera zagregowane dane zorientowane na jeden wybrany temat, które są często wyświetlane oraz łatwo i szybko dostępne dla użytkowników.

Hurtownia danych operuje na poziomie wszystkich dostępnych danych, przy czym tematyczna hurtownia danych jest używana z reguły przez jeden obszar danych w niej zawartych dotyczących jednego konkretnego tematu biznesowego. Dla banków może to być obszar produktów kredytowych lub obszar transakcji kontraktów krótkoterminowych

Typową i najczęściej spotykaną architektura w korporacjach jest jedna globalna hurtowna danych i bezpośrednio zależne i czerpiących z niej dane Data Marty.



Powyżej przedstawiony jest sposób działania Data Martów. Dostęp do nich mają tylko wyznaczone osoby (lub grupy ludzi). Dział raportujący ma dostęp tylko do danych potrzebnych do tworzenia i przeglądania raportów. Dział analiz ma dostęp do Data Martów do analizy oraz raportów. Natomiast grupa administracyjna ma dostęp do wszystkich obszarów danych, gdyż zarządzają tymi danymi.

Kluczowym problemem jest utrzymanie spójności z hurtownią danych. Najważniejsze te kwestie to definicja danych, sposób aktualizacji oraz zarządzanie danymi. Sposobem na ominięcie części problemów jest tworzenie data martu niezależnego od hurtowni danych. Zdarza się to najczęściej, gdy do utworzenia data martu wymagane jest dodatkowe źródło danych spoza hurtowni. Wtedy tematyczne hurtownie danych są zasilane i zarządzane przez procesy ETL (Extract-Translate-Load). Należy jednak pamiętać o tym, że tego typu architektura jest narażone na ryzyko niespójności w rozumowaniu danych.

Najczęstsze powody tworzenia data martów to:
- większa denormalizacja
- dane z zagregowanymi danymi
- dane ze specyficznego okresu czasowego istnienia tych danych ( np. wartość akcji z poprzedniego roku)
- dane dostępne tylko dla specyficznej grupy (dane tylko dla analityków, testerów lub administratorów)

poniedziałek, 18 listopada 2013

Kodowanie w stylu Rammstein

Natrafiłem na zdjęcie przedstawiające kod, który się czyta w melodii utworu "du hast" zespołu Rammstein. Jako wielki fan tego zespołu bardzo mi się spodobał ten kod :)





niedziela, 17 listopada 2013

Co to jest ETL ?

Jak zaczynałem swoją pracę przy bardzo dużym projekcie ETL, to na początku nie wiedziałem co to jest i do tej pory nie ma zbyt dużo materiałów na ten temat. Przedstawię Ci krótki wstęp do ETL.

Skrót ETL oznacza ekstrakcję (extract), transformację (transform) i ładowanie (load). Jest to metoda procesowania danych. ETL składa się z 3 etapów:
1) ekstrakcja danych ze źródła danych - proces ten determinuje bazowe źródła dla hurtowni danych.
2) transformacja danych - etap ten ma za zadanie standaryzować dane, filtrację oraz sprawdzanie reguł biznesowych.
3) ładowanie danych do docelowego zbioru danych - etap zapisu wygenerowanych danych.




Na rysunku przedstawiony jest ogólny schemat działania procesu ETL. Do danych wejściowych (source) należą aplikacje (m.in. bazy danych), dodatkowe pliki oraz inne pomocne dane (m.in. metadane). Proces ETL przetwarza te dane i zapisuje je do wyznaczonego zbioru danych (target). Docelowy zbiór danych jest określony przez projektanta i może to być hurtowania danych, data mart lub zbiór plików zapisanych na serwerze. W praktyce 80% czasu spędzonego na rozwijaniu systemu BI jest poświęcone na rozwijanie procesu ETL. Jest to najbardziej czasochłonne zadanie przy budowaniu hurtowni danych i jednocześnie wymaga najwięcej wiedzy i doświadczenia. Bardzo często proces ETL nazywany jest procesem integracji danych, natomiast narzędzia ETL nazywane są platformą integracyjną.

Pierwsza częścią - ekstrakcja danych ze źródła danych - jest to najbardziej wymagający etap całego ETL. Większość hurtowni danych integruje dane z różnych źródeł danych. Każde źródło danych może się różnić organizacją danych czy sposobem dostępu. Najczęściej spotykanym źródłem danych są relacyjne bazy danych oraz pliki w formacie CSV. Celem ekstrakcji danych jest przekonwertowanie danych do ujednoliconego formatu, który jest przystosowany dla procesu transformacji.

Etap transformacji jest częścią opisującą przepływ danych, który zawiera zaaplikowane reguły biznesowe oraz szczegółowy opis kalkulacji i mapowania między danymi. Niektóre dane wymagają bardzo mało, a nawet brak modyfikacji danych. W większości przypadkach etap ten składa się pezynajmniej z jednego z poniższych zadań:
- wyselekcjonowanie tylko niektórych kolumn danych z tabeli
- transformacja sposobu zapisu danych. Jeżeli dana jest zapisana w postaci binarnej (1-0) to można zapisać słownie (Tak – Nie)
- transformacja formatu zapisu danych. Część dat jest zapisana w formacie skoordynowanego czasu uniwersalnego (UTC) lub czasu lokalnego
- wyliczenie nowej wartości, która jest zależna od wartości innych zmiennych
- sortowanie według danego kryterium
- łączenie danych z innymi danymi z innych źródeł - wzbogacanie danych
- rozdzielenie kolumny na kilka kolumn
- usuwanie zduplikowanych danych
- agregacja danych. Można wprowadzić data rollup ( wiersz podsumowujący dane)
- tworzenie unikatowego klucza (surrogate key) dla wszystkich elementów
- dokonywanie transpozycji oraz tworzenie tabeli przestawnej. Jest to proces, w którym kolumny zamieniane są na wiersze.

Faza ładowania danych odnosi się do zapisu do specjalnego obiektu docelowego (najczęściej jest to hurtowna danych). Obiekt docelowy jest zależny od wymagań danego projektu. Najczęściej istniejące dane w hurtowni danych są nadpisywane przez nowo wygenerowane. Inne hurtownie danych są czyszczone i na nowo załadowane, ale takie rozwiązanie niesie ze sobą problem „pustych danych”, gdyby wystąpił problem w etapie ładowania danych.

sobota, 16 listopada 2013

Szukanie referencji w projektach

Na moje szczęście programuje w solucji (.sln), która posiada ponad 100 projektów (.csproj). Czasami zdarza się szukać projektu, który korzysta ze specyficznej biblioteki lub może być nie spójne w referencjonowaniu (jeden projekt jest zależny od paczki nuget, a drugi od biblioteki zapisanej na dysku).

Poniżej jest skrypt w powershellu, który dla danej wzorca nazw projektów przeszukuje wszystkie csproje i zwraca wszystkie referencje jakie są w tych plikach. Przeszukiwanie rozpoczyna się od ścieżki uruchomienia skryptu.
function Get-Reference
{
[CmdletBinding()]
Param(
     [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] 
     [string] $projectNamePattern
)

BEGIN {
     Write-Host "Getting project References" 
     $projectFileExtension = ".csproj"
}

PROCESS{
    $searchingProjectPattern = $projectNamePattern + $projectFileExtension 
    $projectFullNames = Get-ChildItem  -Filter $searchingProjectPattern -Recurse | %{$_.FullName}

    foreach ( $projectFullName in $projectFullNames)
    {

        if( Test-Path $projectFullName)
        {       
            $projectName = [System.IO.Path]::GetFileNameWithoutExtension($projectFullName)
            [xml]$projectXml = Get-Content $projectFullName
            $itemGroups = $projectXml.Project.ItemGroup
            
            foreach ( $itemGroup in $itemGroups)
            {
                if($itemGroup.Reference -ne $null)
                {
                    foreach( $ref in $itemGroup.Reference)
                    {
                      $Object = New-Object PSObject -Property @{
                           RefPath = $ref.HintPath 
                           Name = $ref.Include
                           ProjectPath = $projectFullName
                           ProjectContent = $projectXml 
                           ProjectName = $projectName
                      }
                      $Object
                    }
                }
                
                if($itemGroup.ProjectReference -ne $null)
                {
                    foreach( $ref in $itemGroup.ProjectReference)
                    {
                      $Object = New-Object PSObject -Property @{
                           Name = $ref.Name 
                           RefPath = $ref.Include
                           ProjectPath = $projectFullname
                           ProjectContent = $projectXml 
                           ProjectName = $projectName
                      }
                      $Object
                    }
                }
            }
        }
    }
}

END{    
Write-host "`n`nHintPath => RefPath and Include => Name FOR Reference"
Write-host "Include => RefPath and Name => Name FOR ProjectReference"
}
}

A poniżej jest przykład użycia. Dajmy na to, że chcesz znaleźć referencje, które w ścieżce zawierają słowo Unity we wszystkich projektach, których nazwa zaczyna się od słowa ProjectA:
$projectNamePattern=  "ProjectA*"
$projectsPattern = @($projectNamePattern)
$projectsPattern  | Get-Reference | ? {$_.RefPath -ne $null} | ?{ $_.RefPath.Contains("Unity") } 



czwartek, 14 listopada 2013

Doc Sprint

Jak myślisz, kiedy należy pisać dokumentację do projektu?


Wiesz jak to jest, zespół nie ma czasu na pisanie dokumentacji do istniejącego projektu, bo PM zawsze mówi, że brakuje jakieś bardzo ważnej funkcjonalności bez której to projekt nie ma sensu i dopiero jak skończy się tą jedną funkcjonalności to będzie czas na zrobienie dokumentacji. Ale później będzie błąd krytyczny lub inna bardzo ważna i potrzebna funkcjonalność i nadal nie będzie czasu na pisanie dokumentacji.

W metodyce scrum, sprint (przebieg) to przedział czasowy dostarczający klientowi działający produkt. Ale co z dokumentacją? Kiedy należy pisać dokumentację? Na końcu bieżącego sprintu czy na początku następnego sprintu? Czy lepiej jest na bieżąco pisać, czy jednak zmiany są zbyt często i lepiej jest pisać dokumentacje co kilka sprintów. Może jednak należy wyznaczyć osobny sprint do pisania dokumentacji?

Nie znam odpowiedzi na te pytania, ale podoba mi się koncepcja krótkiego sprintu poświęconego tylko na dokumentacje. Ten sprint nazywa się Doc Sprint. Doc Sprint może trwać od 2 do 3 dni. Jeżeli ten sprint potrzebowałby trwać dłużej niż 3 dni to oznacza, że dokumentacja jest źle zarządzana, za bardzo było się skoncentrowany na samej funkcjonalności projektu, albo mamy problem ze zbieraniem danych potrzebnych do dokumentacji (problem z knowledge sharingiem).

Wiem, że sprint bardziej jest dla klienta produktu niż dla zespołu, gdyż zasadą jest, że zmiany wprowadzone w sprincie musza być namacalne dla użytkowników (musza mieć nową widoczną funkcjonalność). Ale w trakcie sprintu można wprowadzić wewnętrzny, mniejszy sprint poświęcony tylko dokumentacji.

wtorek, 12 listopada 2013

Dzwonienie do klientów banków

Jak wiadomo (albo nie) socjotechniki są bardzo ważne i nie doceniane. Natrafiłem na filmik przedstawiający jak pewien holender wyciągnął ponad 100 tyś euro dzwoniąc do klientów banków i prosząc od nich ich dane.

Automatyczna aktualizacja SVN

Chcę Ci przedstawić jeden z najbardziej używanych przeze mnie skryptów ( przynajmniej 2 razy w ciągu dnia m.in jak zaczynam prace przy komputerze ) - skrypcik do aktualizacji kodu źródłowego w SVN napisany w PowerShell. Skorzystamy z programu TortoiseProc, który może wykonać polecenia z linii komend:
function Invoke-Svn{
Param(
     
     [string] $command = "properties",
     [string] $path = ((get-location).Path)

)
$svnPath = "C:\Program Files\TortoiseSVN\bin\"
$appSvn = $svnPath+ "svn.exe" 
& $appSvn info


$appTortoise = $svnPath + "TortoiseProc.exe"
$commandLine = '/command:' + $command + ' /notempfile /path:"' + $path + '"'
& $appTortoise $commandLine

}
Aby wykonać aktualizację kodu źródłowego to wystarczy wywołać komendę update:
function Update-Svn{
Param(
     [string] $path = ((get-location).Path)
     )
     
Invoke-Svn -path $path -command "update"
}
Więcej komend można znaleźć na stronie automatyzacji TortoiseSVN. Możemy sprawdzić rejestr svn za pomocą komendy log:
function Log-Svn{
Param(
     [string] $path = ((get-location).Path)
     )
     
Invoke-Svn -path $path -command "log"
}
Aby zaktualizować kilka projektów wystarczy wykonać:
Write-Host "Updating"
Update-Svn -path C:\Code\Path1\Project1
Update-Svn -path C:\Code\Path2\Project2
Update-Svn -path C:\Code\Path3\Project3
Update-Svn -path C:\Code\Path4\Project4
Wywołanie takiego skryptu za pomocą pliku bat jest podane poniżej:
powershell -File "C:\Scripts\Invoke-Svn.ps1"



niedziela, 10 listopada 2013

Zabawa z blockly

Pamiętasz może Logo Komeniusza - prosty graficzny język programowania powstały na Massachusetts Institute of Technology w USA w latach '70, aby wprowadzić dzieci w świat programowania :) Super idea i gdyby nie ten język, wiele dzisiejszych programistów (w tym ja - tak uczyłem się go w gimnazjum i jestem z tego dumny ) nie robiło by togo, co teraz robi.
Znalazłem projekt blockly, który bardzo przypomina programowanie żółwia.

Oczywiście można zagrać w układnie algorytmu do rozwiązywania labiryntów.



Oprócz tego blockly można programować za pomocą schematów blokowych:





Istnieją też projekty, w których blockly jest wykorzystywany do bardziej trudniejszych problemów.


Myślę, że za kilka (kilkanaście) lat każda osoba będzie w stanie zaprogramować swojego 'robota' za pomocą schematu blokowego.

sobota, 9 listopada 2013

Nie trzymaj sie zasad w programowaniu

Wcześniej pisałem o Testivusie. Jednym ze wskazówek wielkiego mistrza był to, że test uświęca środki. Opowieść Testvusa na ten temat była o młodym programiście i dwóch mistrzach programowania, którzy mieli inny punkt widzenia.




Uczeń zapytał dwóch mistrzów programowania
"Nie mogę przetestować ten kod bez mockowania i naruszenia hermetyzacji. Co powinienem zrobić?"


Jeden mistrz programowania odpowiedział
"Mockowanie jest złe i nie powinieneś naruszać encapsulacji.
Zrefaktoryzuj kod, abyś mógł przetestować go właściwie"


Inny mistrz programowania odpowiedział:
"Mockowanie jest dobre, a testowanie jest ważniejsze niż hermetyzacja."


Uczeń zastanawiając się, poszedł na piwo.
W miejscowej tawernie ujrzał wielkiego mistrza programowania, który pił piwo i jadł skrzydełka z kurczaka.
"Wielki mistrzu"- powiedział uczeń - "Myślałem, że nie pijesz. Czy nie jesteś przypadkiem wegetarianinem?"


Wielki mistrz uśmiechną się i odpowiedział:
"Czasami pragnienie najlepiej ugasić piwem, a głód przez skrzydełka kurczaka"


Uczeń już nie był zdezorientowany


Po tym tekście uświadomiłem sobie, że nie jest ważne czy implementacja rozwiązania problemu spełnia pewne standardy czy zasady programowania, ale ważne jest czy rozwiązuje problem i czy da się ten problem rozwiązać w zgodzie i porozumieniu z innymi użytkownikami.

piątek, 8 listopada 2013

Róźne zwracane wartości w Moq

Moq jest fantastyczne, bardzo przejrzyste, proste w nauczeniu się oraz popularne narzędzie do mockowania obiektów. Przedstawiam Ci prosty extension metod dla Moq. Metoda dzięki której mock zwraca rożne wartości z podanej listy za każdym wywołaniem.
Będziemy mockować interfejs:
    public interface INumerable
    {
        int GetNumber { get; }
    }
Standardowo, aby uzyskać różne wartości przy wywołaniu należało wykonać coś takiego:
var listOfReturnedelements = new List<int> {1, 4, 1, 8};
int number = 0;
var numMock= new Mock<INumerable>();

numMock
   .Setup(x=>x.GetNumber)
   .Returns(() => listOfReturnedelements[number])
    .Callback(() => number++)
;
Musimy zdefiniować dodatkową zmienną określająca index listy oraz wywołać metodę Callback, aby zwiększać ten index.
Za każdym razem jak wywołamy num.GetNumber() to dostajemy inną wartość tablicy. Poniżej przykład użycia:
var num = numMock.Object;
var list = new List<int>();
for (int i = 0; i < 4; i++)
{
    list.Add(num.GetNumber);                
}

Zamiast tego to możesz skorzystać z metody:
public static void ReturnsInOrder<T, TResult>(this ISetup<T, TResult> setup, IEnumerable<TResult> results)
    where T : class
{
            setup.Returns(new Queue<TResult>(results).Dequeue);
}
A kod ustawiający obiekt mockujący wygląda następująco:
numMock
.Setup(x=>x.GetNumber)
.ReturnsInOrder(listOfReturnedelements)

Troszkę krótkie wywołanie, ale bardzo mi się podoba użycie kolejki w rozwiązaniu.

poniedziałek, 4 listopada 2013

Droga Testivusa

Już pisałem o Mistrzu Testivusie i jego pokryciu kodu w testach. Bardzo mi się spodobały opowieści o testowaniu w stylu starożytnych chin. Wiele innych wskazówek można pobrać z tego dokumentu. Postanowiłem przetłumaczyć podstawowe wskazówki.




Jeżeli piszesz kod, to pisz testy
Myśl o teście i kodzie jako całość
Najlepszy czas do testowania to wtedy, gdy kod jest świeży
Test jest ważniejszy niż jednostka
Tylko głupcy nie stosują narzędzi
Dobry test nie przechodzi
Test nie marnieją
Czasami test uswięca środki
Nieperfekcyjny test dzisiaj jest lepszy niz perfekcyjny test któregoś dnia
Brzydki test jest lepszy niż brak testu


niedziela, 3 listopada 2013

Testowanie prywatnych metod

Ok, ważna zasada testowania prywatnych metod - prywatne metody nie testuje się!!!. Traktuje się je jako szczegóły implementacji, które nie muszą być przedstawiane, a testy tych metod są poprzez metody publiczne. Jednak, jeżeli chcielibyśmy przetestować te "szczegóły implementacji" to moglibyśmy ukrytą implementację wyekstraktować do oddzielnej klasy. Inne możliwości przedstawiam Ci w tym wpisie.


Przypuśćmy, że mamy klasę, która w logice zwraca GUID typu string:
public class GuidReturner
{
        public string GetGuidString(int arg)
        {
            var cmplexStr = GetGuid(arg);
            return cmplexStr == Guid.Empty ? "" : cmplexStr.ToString();
        }
 
        private Guid GetGuid(int arg)
        {
            return arg == 0 ? GetEmptyGuid() : Guid.NewGuid();
        }
 
        private static Guid GetEmptyGuid()
        {
            return Guid.Empty;
        }
}
 
W tej klasie mamy prywatną metodę GetGuid(int) : Guid. Aby ją przetestować to możemy zmienić prawa dostępu na internal. Wtedy wystarczy zastosować InternalsVisibleToAttribute i wpisać do AssemblyInfo.cs
[assembly: InternalsVisibleTo("YourLib.Tests")]
Minusem takiego rozwiązania jest modyfikacja zależności między projektem produkcyjnym, a projektem testującym, przymus pamiętania o zmianie stringa przy zmianie nazwy assembly oraz dodawanie dodatkowych InternalsVisibleTo dla każdego projektu testowego.

Inną możliwością testowania prywatnej metody jest zmiana prawa dostępu na protected i dziedziczenia po tej klasie. Dla naszego przykładu mamy:
public class GuidReturner
{
        protected Guid GetGuid(int arg)
        {
            return arg == 0 ? GetEmptyGuid() : Guid.NewGuid();
        }
}
A w projekcie w którym mamy testy tworzymy klasę testowalną:
public class TestableGuidReturner : GuidReturner
{
        public Guid TestGetGuid(int arg)
        {
            return base.GetGuid(arg);
        }
}
Minusem takiego rozwiązania jest tworzenie dodatkowej klasy testowalnej. Ma to też swoje plusy, gdzie możemy dodać dodatkową implementację, logowanie lub walidację dla testów.

Jeżeli nie podobają Ci się sposoby zmiany praw dostępu to można użyć mechanizmów refleksji. Do tego użyjemy obiektu dynamic.
public class NonPublicInvoker<T> : DynamicObject
{
        private readonly T _closeType;
        
        public NonPublicInvoker(T closeType )
        {
            _closeType = closeType;
        }
 
        public override bool TryInvokeMember(InvokeMemberBinder binder, 
                            object[] args, out object result)
        {
            result = _closeType.GetType()
                     .InvokeMember(binder.Name, 
                      BindingFlags.Instance 
                        | BindingFlags.NonPublic 
                        | BindingFlags.InvokeMethod
                     ,null, _closeType, args);
            return true;
        }
}
Test może wyglądać następująco:
[Test]
public void Dynamic_It_should_return_empty_guid_for_0()
{
      dynamic sbc = new NonPublicInvoker<GuidReturner>(new GuidReturner());
      Assert.AreEqual(sbc.GetGuid(0), Guid.Empty);
}
Do tego stwórzmy dynamika dla metod statycznych:
public class StaticNonPublicInvoker<T> : DynamicObject
{
        public override bool TryInvokeMember(InvokeMemberBinder binder, 
                             object[] args, out object result)
        {
            result = typeof(T)
                          .InvokeMember(binder.Name, 
                           BindingFlags.NonPublic 
                              | BindingFlags.Static 
                              | BindingFlags.InvokeMethod
                          ,null, null, args);
            return true;
        }
}
[Test]
public void Dynamic_It_should_return_empty_guid_for_static_private_method()
{
            dynamic sbc = new StaticNonPublicInvoker<GuidReturner>();
            Assert.AreEqual(sbc.GetEmptyGuid(), Guid.Empty);
}

W poniższym filmiki jest przedstawiony podobny sposób testowania prywatnych metod za pomocą obiektu PrivateObject



sobota, 2 listopada 2013

Magia Derrena Browna

Bardzo lubię sztuczki Derrena Browna. Najlepsze jest to, że jak oglądasz sztuczki po raz n-ty okazuje się, że wszystko jest jasne i proste i zastanawiasz się jak mogłeś tego wcześniej nie zauważyć... .

Polecam poniższy jego pokaz:



piątek, 1 listopada 2013

BDD Test Template

Wcześniej pisałem już o Korniszoku i BDD, ale teraz chciałbym przedstawić Ci template z jakim u mnie w pracy się pracuje. Template ten jest w modzie BDD. Testuje jedną klasę przy jednym zachowaniu. Jeżeli mielibyśmy n ważnych zachowań to potrzebujemy stworzyć n takich klas testowych.
Template wygląda następująco:
   [Category("BDD_MySuperClass")]
    public class when_we_run_special_methods : InstanceSpecification<MySuperClass>
    {
        protected override MySuperClass Create_subject_under_test()
        {
            return new MySuperClass();
        }

        [Test]
        public void It_should_do_special_stuff()
        {
            
        }
    } 


Cała magia jest w dwóch klasach abstrakcyjnych:
    public abstract class Specification
    {
        [SetUp]
        public virtual void BaseSetUp()
        {}

        [TearDown]
        public virtual void BaseTearDown()
        {}

        [DebuggerStepThrough]
        protected virtual void Establish_context()
        {}

        [DebuggerStepThrough]
        protected virtual void Because()
        {}

        [DebuggerStepThrough]
        protected virtual void Dispose_context()
        {}

        [DebuggerStepThrough]
        protected virtual void Initialize_subject_under_test()
        {}
    }

I druga generyczna klasa:
    public abstract class InstanceSpecification<TSubjectUnderTest> : Specification
    {
        protected TSubjectUnderTest SubjectUnderTest { get; private set; }

        protected abstract TSubjectUnderTest Create_subject_under_test();

        public override void BaseSetUp()
        {
            Establish_context();
            Initialize_subject_under_test();
            Because();
        }

        public override  void BaseTearDown()
        {
            Dispose_context();
        }

        protected override  void Initialize_subject_under_test()
        {
            SubjectUnderTest = Create_subject_under_test();
        }
    }


'Super' przykład dla StringBuilder jest przedstawiony poniżej:
[Category("BDD_StringBuilder")]
[TestFixture]
public class when_we_insert_char_into_empty_stringBuilder : InstanceSpecification<StringBuilder>
{
    public string SubjectUnderTestString { get { return SubjectUnderTest.ToString(); } }

    protected override StringBuilder Create_subject_under_test()
    {
        return new StringBuilder();
    }

    protected override void Because()
    {
        SubjectUnderTest.Insert(0, "first word");
    }

    [Test]
    public void It_should_start_with_word_first()
    {
        Assert.IsTrue(SubjectUnderTestString.StartsWith("first"));
    }

    [Test]
    public void It_should_not_be_empty_string_because_words_ware_added()
    {
        Assert.NotNull(SubjectUnderTest);
        Assert.IsTrue(SubjectUnderTestString.Any()); //any char
    }
} 


SubjectUnderTestString to pole pomocnicze. Przykład przedstawia wzorzec AAA (Arrange-Act-Assert). Metoda Create_subject_under_test() przygotowuje obiekt, metoda Because() wykonuje pewne zachowania na tym obiekcie i mamy dwie metody testowe.

Więcej szczegółów o testowaniu w stylu BDD możesz zaleź na elegantcode.com. Możesz pobrać code snippet z MyCodeSnippets.

czwartek, 31 października 2013

Konformizm w Poker Planningu

Wiesz może dlaczego rozgrywka w Poker Planningu jest tylko jeden raz??

Pięć osób gra w poker planning i estymują jak długo zajmie jedno zadanie.
W pewnym momencie wszystkie osoby pokazują swoje wyniki:

Pierwsza osoba - 8 godzin
Druga osoba - 5 godzin
Trzecia osoba - 8 godzin
Czwarta osoba - 5 godzin
Piąta osoba - 1 godzina


Ale, postanowili jeszcze raz zagrać.

Pierwsza osoba - 8 godzin
Druga osoba - 5 godzin
Trzecia osoba - 8 godzin
Czwarta osoba - 5 godzin
Piąta osoba - 5 godzin


Co się stało z estymatą piątej osoby??

To zjawisko dobrze przestawia eksperyment Solomona Ascha. W eksperymencie Ascha brali udział wolontariusze, którzy na samym początku musieli przyjrzeć się trzem liniom (A,B,C) o rożnej długości, a następnie mieli zdecydować, do której z tych lin najbardziej jest podobna linia czwarta. Linia czwarta była podobna do lini C i z tym stwierdzeniem nie było wątpliwości, jeżeli badani uczestnicy siedzieli sami.



Odpowiedz osób badanych się zmieniła, gdy ten sam przykład był przedstawiony 7 osobom w tym samym czasie. Tak na prawdę w tym eksperymencie było 6 osób podstawionych. Zawsze badana osoba odpowiadała na końcu. Założenie był takie: osoba badana nie zna osób podstawionych. 2 razy podstawione osoby odpowiedzieli poprawnie, ale za 3cim razem odpowiedzieli z błędem. W takiej sytuacji większość osób badanych podążyło za błędną odpowiedzią przedmówców i tak samo odpowiedzieli jak osoby podstawione.

Osoba badana podporządkowała się zdaniu grupy, przy braku nacisku z jej strony. Aschon przedstawił to badanie jako objaw uległości wobec większości - konformizm.

niedziela, 27 października 2013

Korniszonek w BDD

Wymagania szczegółowe aplikacji można zapisać w języku Gherkin. Język ten składa się z 5 słów kluczowych (Given, When, Then, And, But).
Poniżej jest przykład użycia tego języka:

Scenario 1: Zwrot zepsutych butów do magazynu w sklepie
GIVEN: klient kupił buty z naszego sklepu
AND: buty przepuszczają wodę w deszczowe dni
BUT: data zakupu nie starsza niż rok
WHEN: klient zwraca buty,
THEN: buty powinny być w magazynie


Scenario 2: Zakup pasty do butów o 50% taniej przy zakupie butów
GIVEN: klient kupił buty
WHEN: klient chce kupić pastę do butów
THEN: cena pasty do butów o 50% taniej


Są to proste przykłady zastosowania języka Gherkin, które przedstawiają różne zachowania aplikacji.
Więcej można poczytać w książce The Cucumber Book: Behaviour-Driven Development for Testers and Developers oraz na stronie jednego z projektów BDD dla języka php.

W tematyce BDD i Gherkin jestem świeżakiem, ale uważam, że warto zainteresować się tym językiem, gdyż nie wymaga umiejętności programistycznych ze strony testera, PM czy BA, aby napisać przypadek użycia. Książkę jeszcze nie przeczytałem, ale w wolnej chwili muszę się zabrać za nią :)

80% i nie mniej

Przeczytałem świetny tekst o testowaniu na stronie Alberto Savoia (Artima Developera) i uważam, że kwestia pokrycia kodu wciąż powraca, więc zamieszczę spolszczoną wersje Mądrości Testvusa o pokryciu.



Pewnego ranka, młody programista rozmawiał z wielkim mistrzem.
"Jestem gotowy pisać testy jednostkowe. Do jakiego pokrycia kodu powinienem dążyć"
Wielki mistrz odpowiedział:
"Nie przejmuj się pokryciem, po prostu pisz dobre testy"
Młody programista uśmiechnął się, podziękował i poszedł.


Później, tego samego dnia, inny programista zadał to samo pytanie.
Wielki mistrz wskazał na garnek wrzącej wody i powiedział.
"Ile ziarenek ryżu powinienem włożyć do garnka?"
Programista spojrzał zdziwiony i odpowiedział:
"Skąd mogę wiedzieć? To zależy ile ludzi chcesz nakarmić, jak bardzo są głodni, jakie inne jedzenie podajesz, ile masz dostępnego ryżu i tak dalej"
"Dokładnie" - odpowiedział wielki mistrz
Drugi programista uśmiechnął się, podziękował i poszedł.


Pod koniec dnia, trzeci programista przyszedł i zadał to samo pytanie odnośnie pokrycia kodu.
"Osiemdziesiąt procent i nie mniej" - odpowiedział mistrz surowym głosem uderzając ręką o stół
Trzeci programista uśmiechnął się, podziękował i poszedł.


Po ostatniej odpowiedzi, młody uczeń podszedł pod wielkiego mistrza.
"Wielki mistrzu, dzisiaj słyszałem różne Twoje odpowiedzi do tego samego pytania o pokryciu kodu. Dlaczego?"
Wielki mistrz wstał z krzesła.
"Choć napij się ze mną świeżej herbaty i porozmawiajmy o tym"


Po tym jak zaparzyli zieloną herbatę - wielki mistrz zaczął:
"Pierwszy programista jest nowy i dopiero zaczyna znajomość z testowaniem. Teraz ma dużo kodu, który nie ma testów. Długą drogę ma do przebycia, a koncentrując się w tej chwili na pokryciu kodu byłoby przygnębiające i bezużyteczne. Lepiej jest dla niego by przyzwyczaił się do pisania kodu i testów. Później będzie się martwił o pokrycie kodu"


"Drugi programista jest doświadczony w programowaniu i testowaniu. Kiedy odpowiedziałem pytająco, 'ile ziarenek ryżu powinno się umieścić w garnku', to pomogłem mu zrozumieć, że ilość wymaganych testów jest uzależnione od wielu czynników, a on wie lepiej niż ja - bo to jest jego kod. Nie mam jednej prostej odpowiedzi i on jest wystarczająco bystry, aby o tym nie wiedział".


Rozumiem - odpowiedział młody uczeń - ale skoro tam nie ma pojedynczej odpowiedzi, to dlaczego odpowiedziałeś trzeciemu programiście 'Osiemdziesiąt procent i nie mniej'?
Wielki mistrz zaczął się śmiać tak mocno i głośno, że było widać, że wypił coś więcej niż zieloną herbatę.
"Trzeci programista chciał tylko prostych odpowiedzi - nawet, gdyby nie było prostych odpowiedzi, a i tak nie będzie ich przestrzegał"
Młody uczeń i siwy wielki mistrz skończyli pić herbatę w kontemplacyjnej ciszy.


Inne mądrości Testvusa można poczytać na stronie artima lub w wersji pdf.

sobota, 26 października 2013

Statyczne analizy kodu w czasie

Tak się zastanawiam, co by było gdybyśmy wiedzieli jak z biegiem czasu zmieniały się nazwy klas, metod, słowa-klucze używane w naszych projektach. Co jakiś czas kod źródłowy byłby skanowany i informacje byłyby zapisywane do bazy. Z tego można by było przedstawić jaka klasa z biegiem czasu/releasów jest najbardziej popularna, czy nazwy obiektów są zależne od nazwy klas, ile jest komentarzy, jakie jest kodowanie tekstów itp. Mamy narzędzia, aby dokonać statycznej analizy kodu, ale jeszcze nie ma możliwości analizy tych wyników dla okresów czasowych.

Taki pomysł przyszedł mi do głowy przy oglądaniu prezentacji o n-gram. Bardzo zapraszam do obejrzenia:



piątek, 25 października 2013

Testowanie po IEquatable

Tak się zastanawiam nad testowaniem obiektów, które można przyrównać do obiektów tego samego typu (metoda Equals). Przypuśćmy, że masz klasę, która implementuję IEquatable<WrappedString>.
public class WrappedString : IEquatable<WrappedString>
{
        public string StringValue { get; set; }
 
        public WrappedString(string stringValue)
        {
            StringValue = stringValue;
        }
 
        public bool Equals(WrappedString other)
        {
            return this.StringValue == other.StringValue;
        }
}
Każda klasa implementująca IEquatable<WrappedString> powinna spełniać parę standardów, m.in. jeżeli T jest strukturą to domyślna wartość powinna zwrócić tą samą wartość, a kiedy obiekt klasy porównujemy do null zawsze powinna zwracać fałsz.
 public abstract class EquatableRelation<TType> 
        where TType : IEquatable<TType>
{
        public abstract TType GetItemX();  //object to test
        private bool IsValueType()
        {
            return typeof (TType).IsValueType;
        }

  #region Default values
        protected virtual void It_should_return_false_because_comparing_to_null()
        {
            if (!IsValueType())
            {
                TType number1 = GetItemX();
                Assert.IsFalse(number1.Equals(null));
            }
        }
 
        protected virtual void It_should_return_true_for_default_value_in_valueType()
        {
            if (IsValueType())
            {
                var value1 = default(TType);
                var value2 = default(TType);
                Assert.IsTrue(value1.Equals(value2));
            }
        }
        #endregion
}

Obiekt powinien spełniać warunki relacji równoważności.
 public abstract class EquatableRelation<TType> 
        where TType : IEquatable<TType>
{
public abstract TType GetItemX();
public abstract TType GetItemY();
public abstract TType GetItemZ();

#region relation
//relacja zwrotna
protected virtual void It_should_be_reflexive_relation()
{
            TType number1 = GetItemX();
            if (!IsValueType())
            {
                Assert.IsNotNull(number1);
            }
            Assert.IsTrue(number1.Equals(number1));
}

 //relacja symetryczna
protected virtual void It_should_be_symmetric_relation()
{
            TType number1 = GetItemX();
            TType number2 = GetItemY();
 
            bool number1To2 = number1.Equals(number2);
            bool number2To1 = number2.Equals(number1);
            Assert.AreEqual(number1To2, number2To1);
}

//relacja przechodnia
protected virtual void It_should_be_Transitive_relation()
{
            TType number1 = GetItemX();
            TType number2 = GetItemY();
            TType number3 = GetItemZ();
 
            Assert.IsTrue(number1.Equals(number2));
            Assert.IsTrue(number2.Equals(number3));
            Assert.IsTrue(number1.Equals(number3));
 
}
#endregion
}
Oprócz tego zawsze powinno się zwracać taką samą wartość porównania:
 public abstract class EquatableRelation<TType> 
        where TType : IEquatable<TType>
{
private const int NumberOfRepeatedTestRuns = 10;

protected virtual void It_should_return_always_the_same_value_for_Equals()
{
            var bools= new List<bool>();
            for (int i = 0; i < NumberOfRepeatedTestRuns; i++)
            {
                TType number1 = GetItemX();
                TType number2 = GetItemY();
                bools.Add(number1.Equals(number2));
            }
            Assert.IsTrue(bools.All(x => x));
}
 
protected virtual void It_should_return_always_the_same_value_for_reflexive()
{
            var bools= new List<bool>();
            for (int i = 0; i < NumberOfRepeatedTestRuns; i++)
            {
                TType number1 = GetItemX();
                TType number2 = GetItemX();
                bools.Add(number1.Equals(number2));
            }
            Assert.IsTrue(bools.All(x => x));
}

protected virtual void It_should_return_always_true_for_default_values_in_valueType()
{
            if (IsValueType())
            {
                for (int i = 0; i < NumberOfRepeatedTestRuns; i++)
                {
                    var value1 = default(TType);
                    var value2 = default(TType);
                    Assert.IsTrue(value1.Equals(value2));
                }
            }
}
}
Oraz w różnym czasie domyślna wartość powinna zwracać tą samą wartość
 public abstract class EquatableRelation<TType> 
        where TType : IEquatable<TType>
{
 protected virtual void It_should_return_always_the_same_value_for_default_value_in_valueType_for_diffrent_timeTics() //super długa nazwa
{
            if (IsValueType())
            {
                Random r= new Random(12345);
                var defaultvalues = new List<TType>();
                for (int i = 0; i < NumberOfRepeatedTestRuns; i++)
                {
                    Thread.Sleep(r.Next(100,500));
                    defaultvalues.Add(default(TType));
                }
                Assert.IsTrue(defaultvalues.All(x => x.Equals(default(TType))));
            }
        }
}
Ok, to teraz masz standardy jakie powinien spełniać każdy obiekt implementujący IEquatable<WrappedString>. Możemy do tego stworzyć interfejs z tym standardem.
public interface IStandardEquatable
{
  void It_should_fulfill_IEquatable_standards();
}

 public abstract class EquatableRelation<TType>  :IStandardEquatable
        where TType : IEquatable<TType>
{
 public virtual void It_should_fulfill_IEquatable_standards()
{
            It_should_return_true_for_default_value_in_valueType();
            It_should_return_false_because_comparing_to_null();
            It_should_be_reflexive_relation();
            It_should_return_always_the_same_value_for_reflexive();
            It_should_be_coreflexive_relation_because_same_value();
            It_should_return_always_the_same_value_for_Equals();
            It_should_be_symmetric_relation();
            It_should_be_Transitive_relation();
            It_should_return_always_the_same_value_for_default_value_in_valueType();
            It_should_return_always_true_for_default_values_in_valueType();
            It_should_return_always_the_same_value_for_default_value_in_valueType_for_diffrent_timeTics();
}
}
A nasz pierwszy abstrakcyjny test
 public abstract class EquatableRelationTest<TType>  : EquatableRelation<TType>
        where TType : IEquatable<TType>

{
[Test, Explicit("Run test which are required for standardization")]
public override void It_should_fulfill_IEquatable_standards()
{
            base.It_should_fulfill_IEquatable_standards();
}
}

Jeżeli będziesz chciał przetestować int to możesz:
[TestFixture]
public class IntEquatableTest : EquatableRelationTest<int>
{
        public override  int GetItemX()
        {
            return 1;
        }
 
        public override int GetItemY()
        {
            return 1;
        }
 
        public override int GetItemZ()
        {
            return 1;
        }
}
Tak samo dla WrappedString
[TestFixture]
public class WrappedStringEquatableTest :  EquatableRelationTest<WrappedString>
{
        public override WrappedString GetItemX()
        {
            return new WrappedString("Abc");
        }
 
        public override WrappedString GetItemY()
        {
            return new WrappedString("Abc");
        }
 
        public override WrappedString GetItemZ()
        {
            return new WrappedString("Abc");
        }
}
Można skorzystać z TestCasów
[TestFixture]
public class WrappedStringEquatableTest3
{
        [TestCase("Abc", "Abc", "Abc")]
        [TestCase("Abc ", "abc", "Abc")]
        public void It_should_be_eq(string str1, string str2, string str3)
        {
            IEqStdFulfillable tuple =
                new EquatableRelationTuple(new WrappedString(str1), 
                                                          new WrappedString(str2),
                                                          new WrappedString(str3));
            tuple.It_should_fulfill_IEquatable_standards();
        }
}
Do tych testów pomocna będzie nam Tupla i Checker (2 dodatkowe wrappery).
public class EquatableRelationTuple<T> : Tuple<T, T, T>, IStandardEquatable
        where T : IEquatable<T>
{
        private readonly EquatableRelationChecker<T> checker;
 
        public EquatableRelationTuple(T item1, T item2, T item3)
            : base(item1, item2, item3)
        {
            checker = new EquatableRelationChecker<T>(item1, item2, item3);
        }
 
        public void It_should_fulfill_IEquatable_standards()
        {
            checker.It_should_fulfill_IEquatable_standards();
        }
}

 public class EquatableRelationChecker<T> : EquatableRelation<T>
        where T : IEquatable<T>
{
        private readonly T _vakue1;
        private readonly T _value2;
        private readonly T _value3;
 
        public EquatableRelationChecker(T value1, T value2, T value3)
        {
            _vakue1 = value1;
            _value2 = value2;
            _value3 = value3;
        }
 
        public override T GetItemX()
        {
            return _vakue1;
        }
 
        public override T GetItemY()
        {
            return _value2;
        }
 
        public override T GetItemZ()
        {
            return _value3;
        }
}


poniedziałek, 21 października 2013

Problem z statycznymi metodami

Może kiedyś się spotkałeś z klasą, która posiadała dwie metoda (jedna statyczna, druga instancyjna) o jednakowej nazwie,ale innych parametrach i wywołanie nie działało tak jak byś się tego spodziewał. Dla zwyczajnej klasy mamy metodę, która przyjmuje object jako parametr.
public class StaticTestClass
{
        public void Do(object str)
        {
            Console.WriteLine("instance: Do");
        }
}

A wywołanie tej metody działa normalnie:
public void Test()
{
  StaticTestClass abc= new StaticTestClass();
  abc.Do("ASD"); 
}

Jeżeli byśmy mieli dodatkową metodę statyczną, która przyjmuje dokładniejszy typ:
public class StaticTestClass
{
   public static void Do(string str)
   {
      Console.WriteLine("static: StaticTestClass.Do");
   }

   public void Do(object str)
   {
      Console.WriteLine("instance: Do");
   }
}

To mamy wtedy błąd kompilacji
public void Test()
{
  StaticTestClass abc= new StaticTestClass();
  abc.Do("ASD"); //cannot be accessed with an instance reference
}



Kolekcja danych testowych

Jakiś czas temu pisałem o TestCase w NUnit. Czasami takie rozwiązanie może zaoszczędzić troszkę czasu. Zauważyłem, że bardzo często testuje metody dla takich samych danych wejściowych. Dla parametru typu string sprawdzam jak metoda zadziała dla null, pustego stringa i stringa z białym znakiem.
public class SimpleTestClass
{
    [TestCase(null)]
    [TestCase("")]
    [TestCase(" ")]
    public void SimpleTestCase(string parametr)
    {
        Assert.IsTrue(string.IsNullOrWhiteSpace(parametr));
    }
}

A gdyby tak trzymać kolekcję przypadków testowych w oddzielnym miejscu? Mamy taką możliwość - możemy użyć TestCaseSource. Niestety wszystkie metody muszą być statyczne.
[TestCaseSource(typeof(StringTestCaseSource), "NullAndWhiteSpaceStrings")]
public void It_should_return_true(string arg1)
{
   Assert.IsTrue(string.IsNullOrWhiteSpace(arg1));
}

Implementacja metody, która zwraca nam potrzebne dane testowe:
public static class StringTestCaseSource
{
public static IEnumerable<TestCaseData> NullAndWhiteSpaceStrings
{
   get
   {
     yield return new TestCaseData(null);
     yield return new TestCaseData("");
     yield return new TestCaseData(" ");
   }
}
}

Inny przypadek użycia - wartości enumów. Chcielibyśmy uruchomić test dla wszystkich przypadków enuma. Możemy podawać nazwy elementów w enumie jak i jego wartości. Dla enuma:
public enum MoneyDirection
{
        Pay,
        Receive,
}

Możemy napisać proste testy:
[TestCaseSource(typeof(EnumTestCaseSource<MoneyDirection>), "Names")]
public void It_should_parse_moneyDirection_string(string nameOfEnums)
{
           var objectEnum = Enum.Parse(typeof (MoneyDirection), nameOfEnums);
           Assert.IsNotNull(objectEnum);
}
 
[TestCaseSource(typeof(EnumTestCaseSource<MoneyDirection>), "Values")]
public void It_should_parse_moneyDirection_type(MoneyDirection valuesOfEnums)
{
           Assert.IsTrue(Enum.IsDefined(typeof(MoneyDirection), valuesOfEnums));
}
A sama implementacja metod jest następująca:
public static IEnumerable<TestCaseData> Names
{
    get
    {
                return Enum.GetNames(typeof(T))
                       .Select(x => new TestCaseData(x));
    }
}
public static IEnumerable<TestCaseData> Values
{
   get
   {
                return Enum.GetValues(typeof(T))
                      .Cast<T>()
                      .ToTestCaseData(); //with extension method
   }
}

Przypuśćmy, że mamy klasę, która zawiera statyczne formaty dat:
public class DateTimeRequiredFormats
{
        public const string Req1 = "yyyyMMdd"; //const is 
        public readonly static string Req2 = "yyyy  MM  dd";
        public static string Req3 = "yyyy MM dd";
        public string Req4 = ""; //not used because not static
        
        
        ////////////
        public string Req5 { get { return "a"; } }
        public string Req6 { get; set; }
 
        public DateTimeRequiredFormats(string req6)
        {
            Req6 = req6;
        }
 
}

Aby sprawdzić działanie statycznych formatów (Req1, Req2, Req3) wystarczyło wywołać:
[TestCaseSource(typeof(FieldTestCaseSource<DateTimeRequiredFormats>), "Static")]
public void It_should_parse_dateTimeFormat(object arg1)
{
   var dateTime = DateTime.ParseExact("20131029", arg1.ToString(), null,
               DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AllowInnerWhite );
   Assert.AreEqual(new DateTime(2013,10,29), dateTime);
}

A metoda, która zwraca te zmienne ma implementację:
public static class FieldTestCaseSource<T>
{
   public static IEnumerable<TestCaseData> Static
   {
      get
      {
         var propertyInfos = typeof(T).GetFields()
                    .Where(x=>x.IsStatic)
                    .Select(x=>x.GetValue(null))
                    ;
         return propertyInfos.ToTestCaseData();
       }
   }
 }

A co z metoda? Tutaj już jest troszkę trudniejsza sytuacja. Oprócz klasy z metodami to potrzebny będzie nam obiekt, który będzie mógł uruchomić metodę. Poniżej klasa z metodami do uruchamiania w teście:
public class InformationGetter
{
   public static int GetSuperNumber()
   {
     return 77;
   }
 
   public static int GetNotSuperNumber()
   {
      return 7;
   }
 
   public string GetCharAt(int indexNumber)
   {
      return _specialString[indexNumber]
.ToString(CultureInfo.InvariantCulture);
   }
   private string _specialString;
 
   public InformationGetter(string specialString)
   {
     _specialString = specialString;
   }
 
   public void ConsoleWrite()
   {
      Console.WriteLine("ConsoleWirte:" + _specialString);
   }
}
Poniżej sam test. Zauważ, że podany tej tutaj typ zwracany przez metodę (int).
[TestCaseSource(typeof(MethodTestCaseSource<InformationGetter,int>), "Static")]
public void It_should_return_int_bigger_than_0(MethodInvoker<int> staticMethodToInvoke)
{
   Assert.Greater(staticMethodToInvoke.Invoke(), 1);
}
public static class MethodTestCaseSource<T, TReturn>
{
   public static IEnumerable<TestCaseData> Static
   {
     get
     {
       var methodInfos=  MethodTestCaseSource<T>.GetStaticMethods()
                    .Where(x => x.ReturnType == typeof (TReturn));
       var methodInvokers = MethodInvoker<TReturn>.ToInvoker(methodInfos);
       return methodInvokers
                    .ToTestCaseData(x=>x.Method.Name);
      }
   }
   public static IEnumerable<TestCaseData> NonStatic
   {
      get
      {
        var methods = MethodTestCaseSource<T>.GetInstanceMethods()
                    .Where(x => x.ReturnType == typeof(T));
 
        var methodInvokers = MethodInvoker.ToInvoker(methods);
        return methodInvokers
                    .ToTestCaseData(x => x.Method.Name);
       }
   }
}
Klasa MethodInvoker wywołuje daną metodę. Klasa ma dwie postacie (bez i z użyciem generyków). Jedna i druga metoda ma podobną implementację.
public class MethodInvoker<TReturn> : MethodInvoker
{
   public MethodInvoker(MethodInfo methodInfo):base(methodInfo){}
 
   public TReturn Invoke(object obj=null, object[] parameters=null)
   {
     return (TReturn)Method.Invoke(obj, parameters);
   }
 
   public static IEnumerable<MethodInvoker<TReturn>> ToInvoker(IEnumerable<MethodInfo> methodInfos)
   {
     return methodInfos.Select(x => new MethodInvoker<TReturn>(x));
   }
}
Dzięki MethodInvoker możemy też przesyłać metody, które nie są statyczne. Wystarczy dla metody Invoke podać obiekt:
[TestCaseSource(typeof(MethodTestCaseSource<InformationGetter, string>), "NonStatic")]
public void It_should_return_first_char(MethodInvoker<string> nonStaticMethodToInvoke)
{
  InformationGetter getter=new InformationGetter("Abc");
  var fistCharString = nonStaticMethodToInvoke.Invoke(getter, new object[] {0});
  StringAssert.AreEqualIgnoringCase("a", fistCharString);
}

Kod źródłowy projektu jest udostępniony na GitHubie. Coś może dodam do tych kolekcji testcesów np. wygenerowane losowe stringi, dane z plików resx, najważniejsze daty w DateTime, adresy url i mail.
Możesz też zainstalować sobie paczkę nugetową. Wystarczy wpisać:
>Install-Package Nunit.Framework.TestCaseStorage



niedziela, 20 października 2013

Fluent notation

Osoby, które kodują razem ze mną to od razu wiedzą, że jestem autorem danej części kodu. Pisany kod jest w stylu Fluent notation ( również zwany Fluent interface, gdyż przygotowujesz całe API). Co prawda wielu osobom się to nie podoba, ale chciałbym Ci przedstawić mój sposób widzenia:

Zapis LINQ w tradycyjny jednolinijkowy sposób pisania kod:
var firstNumberSelector = GetNumbers().Where(x => x > 0).
    ToLookup(x => x.ToString().First()).Select(x => new{x.Key, Items = x,Count = x.Distinct().Count()}).ToList();

A tutaj mój sposób pisania kodu:
var firstNumberSelector = GetNumbers()
                .Where(x => x > 0)
                .ToLookup(x => x.ToString()
                                .First())
                .Select(x=>new {x.Key, 
                                Items=x, 
                                Count=x.Distinct()
                                        .Count()})
                .ToList();
Projekt Fluent NHibernate korzysta z takiego zapisu i kod może wyglądać tak:
_SessionFactory = Fluently 
                .Configure() 
                .Database(MsSqlCeConfiguration 
                              .Standard 
                              .ConnectionString("Data Source=MyDb.sdf") 
                              .ShowSql()
                               )
                .Mappings(m => m.FluentMappings 
                           .AddFromAssemblyOf<NHibernateHelper>()) 
                .ExposeConfiguration(cfg => new SchemaExport(cfg) 
                                        .Create(true, true)   //create table in db 
                                        ) 
                .Cache(c=>c 
                    .UseSecondLevelCache() 
                    .UseQueryCache() 
                    .ProviderClass<HashtableCacheProvider>() 
                    ) 
                .BuildSessionFactory();
Dla mnie jest to kod bardziej czytelny i łatwiej mi jest określić jaka metoda jest uruchamiana dla danego obiektu.
Może Tobie też spodoba się taki sposób pisania kodu.

środa, 16 października 2013

Kolorowanie składni w Visual Studio

Edytor środowiska programistycznego (IDE) jest narzędziem, przy którym programista spędza 99% swojego czasu. Nie będę Ci mówił, że kolorowa składnia jest bardzo ważna. Celem tego wpisu jest przesłanie Ci ciekawych rozwiązań zestawu kolorów.

Już dawno temu Atwood, Hanselman czy Restrepo pisali o kolorowaniu środowiska programistycznego.

Na stronie Studio Style można pobrać style do edytora Visual Studio. Oprócz tego sam możesz stworzyć własny styl dopasowany do Twojego gustu. Oczywiście w każdym momencie można wrócić do domyślnego stylu.

Dla Visual Studio 2013 (i innych wersji od VS2010) jest jeszcze dodatek Color Theme Editor, który zmieniasz menu VS.

niedziela, 13 października 2013

Jestem OK ponieważ

Czy Ty jesteś OK
Zrób takie małe ćwiczenia. Zapisz 4 zdania określające Ciebie, czy jesteś w porządku. Np.
Jestem OK, dopóki pomagam innym
Jestem OK, bo mam luksusowy dom
Jestem OK, ponieważ noszę markowe ubranie
Jestem OK, gdyż jestem poważany

Teraz napisz 4 zdania określające ciebie.
Napisz teraz.





Z pewnej książki zapoznałem się z metodyką "Jestem Ok, ponieważ ..."
Jest to metoda, która uświadomiła mnie jakie mam lęki, dlaczego moje wartości są kruchliwe oraz wzmocniła moje poczucie własnej wartości.

Jest to metoda, która określa Twój szacunek do samego siebie. Na przykład, jeśli rodzice chwalili cię wtedy kiedy zdobywałeś dobre oceny w szkole to mówiłeś do siebie "jestem OK, dopóki mam dobre oceny". Z biegiem lat mogłeś rozwinąć warunkowe poczucie własnej wartości i jeżeli nic nowego się nie zdarzyło, to taka "wartość" towarzyszyła Ci przez okres dojrzałości prowadzać do rozczarowań oraz wątpliwości we własne możliwości, kiedy nie będzie odnosiło się sukcesów.
Warunkowa wartość jest rozwijana wewnątrz nas. Problem powstaje, kiedy takiego warunku nie jesteśmy w stanie spełnić, co będzie prowadziło do poczucia niskiej wartości. Zamiast takiej wartości można zadać sobie wartość Jestem OK, niezależnie od tego czy odnoszę sukces.

Inne warunki określające naszą wartość to:
Jestem OK, ponieważ uczę się
Jestem OK, ponieważ wygrywam
Jestem OK, ponieważ jestem wolontariuszem
Jestem OK, ponieważ ciężko pracuję
Jestem OK, ponieważ znam się na kinie
Jestem Ok, bo dużo zarabiam
Jestem OK, dopóki mam co robić
Jestem OK, dopóki mam wiele przyjaciółek
Jestem OK, dopóki jestem dla kogoś ważny/-na
Jestem OK, dopóki pomagam innym
Jestem OK, bo jadam w drogich restauracjach
Jestem OK, bo jestem z moim partnerem/-ką
Jestem OK, bo jestem uczciwy
Jestem OK, bo kontroluje innych
Jestem OK, bo chodzę w modnym ubraniu
Jestem OK, bo chodzę na siłownię
Jestem OK, bo wiem co jest smaczne
Jestem OK, bo znam się na nowościach technologicznych




Przez warunkową wartość możemy robić coś, co nie daje nam satysfakcji. Dążenie do celu nie jest z powodu chęci (motywacja pozytywna), ale z powodu strachu (motywacja negatywna). Dochodzi do tego, że można wykonać cele wbrew naszym wewnętrznym wartościom. Sprawdź czy Twoje cele są zgodne z Twoimi wartościami.

piątek, 11 października 2013

Microsoft Security Fundamentals

Ostatnio zdałem egzamin MTA:Security Fundamentals 98-367

Z dwóch powodów polecam ten egzamin osobom pracującym w firmach, które dbają o bezpieczeństwo (instytucje finansowe, banki, ubezpieczenia, firmy medyczne itp.)

1) przygotowanie się do tego egzaminu pozwali Ci na zaznajomienie się z podstawowymi technikami włamywania się do firm, a w szczególności uświadamia ludzi o socjotechnikach
2) egzamin jest nakierowany na teoretyczną i ogólną wiedzę, a nie na szczegóły implementacji. Osoby, które twierdzą, że Microsoft jest 'beee' i nie znają jego produktów mogą zdać ten egzamin. Co prawda pamiętam jedno pytanie z BitLockera (microsoftowy TruCrypt) i o wersje Windows, w której to rozwiązanie jest używane (źle odpowiedziałem), ale było to jedno pytanie.

Jeżeli byś chciał się przygotować do niego to przydatny będzie Ci oficjalny przewodnik po tym egzaminie
Dodatkowo możesz poczytać inne książki z obszaru bezpieczeństwa Windows - na przykład Google books udostępniło książkę Windows Security Essencials.

Obejrzałem jeszcze filmiki na trainsignal.com oraz cbt nuggets.

Wydaje mi się, że książka przygotowująca do egzaminu w zupełności by wystarczała, ale wiedzy nigdy za wiele.

sobota, 5 października 2013

Walka z CSS

Tak się zastanawiam i dochodzę do wniosku, że osoby, które potrafią stworzyć piękne strony za pomocą modyfikacji css'a muszą mieć coś z artysty. Ja (niestety) nie mam takiej umiejętności, a bardzo bym chciał. Może w przyszłości troszkę się pobawię, ale zawsze jak biorę się za selectory, to muszę całą stronę zepsuć.
Rozbawiła mnie znaleziona grafika Petera Griffina jak próbuje ustawić żaluzje i fantastycznie przedstawia moją walkę z CSS.

środa, 2 października 2013

Porównanie C5 z System.Collections.Generic

Jestem po lektorze książki ".NET 4.0 Generics" napisanej przez Sudipta Mukherjee (wcześniej na jego stronie można było ściągnąć całą książkę). Najbardziej cenie tą książkę za przedstawienie wyników szybkości działania różnych typów kolekcji. Autor porównuje typy, które znajdują się w bibliotece C5 oraz w System.Collections.Generic. O bibliotece C5 już wcześniej pisałem. Chciałbym przedstawić zdjęcia z wynikami z tej książki.

Eksperyment nr 1:
Ile czasu potrzeba, aby sprawdzić czy element w liście istnieje.

Eksperyment nr 2:
Ile czasu potrzeba, aby znaleźć pierwsze wystąpienie elementu w liście.


Eksperyment nr 3:
Ile czasu potrzeba, aby znaleźć ostatnio występujący element w liście


Eksperyment nr 4:
Ile czasu potrzeba, aby dodać element w losowym miejscu w liście


Eksperyment nr 5:
Ile czasu potrzeba, aby usunąć pojedynczy element w losowym miejscu w liście


Eksperyment nr 6:
Ile czasu potrzeba, aby uzyskać dostęp do elementu w kolekcji asocjacyjnej (Dictionary, SortedDictionary, C5.HashDictionary, C5.TreeDictionary)


Eksperyment nr 7:
Ile czasu potrzeba, aby znaleźć unie dwóch zbiorów


Eksperyment nr 8:
Ile czasu potrzeba, aby sprawdzić czy jeden zbiór zawiera się w drugim zbiorze


Kod źródłowy dla tych testów można było pobrać stąd. Mam nadzieję, że Sudipta reaktywuje swoją stronę.


poniedziałek, 30 września 2013

Kiedy pisać Unit Test?

TDD jest bardzo popularnym podejściem do pisania kodu. Najpierw piszesz test sprawdzający funkcjonalność, który nie przechodzi, później implementujesz ta funkcjonalność, aby ten test mógł przejść, a na końcu refaktorujesz kod i od nowa zaczynasz pisać kolejny test.

Dużo jest przeciwników TDD, gdyż uznaje się, że TDD jest zbyt wolny, nie nadaje się do małych zmian i nie ma czasu na 'ekperymentowanie' z TDD. Nie jestem w tym ekspertem, ale jedno wiem. Pisanie kodu produkcyjnego z TDD nie jest wolniejsze od samego pisania kodu, ale pisanie kodu eksperymentalnego z TDD jest wolniejsze od samego pisania kodu. Jest to najprostszy argument, przeciwko TDD.

Innym podejściem do pisania testów jest zasada Test-First. Kiedyś byłem, na praktyce w zagranicznej firmie, w której dwóch doświadczonych programistów pisało kod z takim podejściem. Jedna osoba pisała testy, a druga osoba implementowała te testy. Wszystko ok, ale bardzo często implementator kodu przychodził do twórcy testów, aby zmienić testy - w trakcie rozwoju aplikacji funkcjonalność się zmieniała jak i pomysły rozwiązania problemów. Test-First bardzo dobrze uzupełnia się z TDD, gdyż jedna osoba (na ogół jest to architekt) pisze podstawowe testy (kontrakty), a implementator kodu dodaje bardziej szczegółowe testy.

Ale, skoro TDD zawiera bardzo dużo czasu, a testy pisane metoda Test-First są często zmieniane to może pisać testy metoda Test-After? Minusem Test-After jest to, że bardzo trudno jest uzyskać wysokie pokrycie kodu. Mamy wtedy wewnętrzną potrzebę, aby zmienić coś w kodzie, aby łatwiej można było napisać test, nie mając przy tym gwarancji, że po zmianie wszystko będzie działało. Na dodatek nigdy nie ma czasu na testy i wszyscy mówią (managery), że po ważniejszych zmianach będzie można przetestować funkcjonalność. Oczywiście po tych zmianach nie mamy pewności czy wszystko działa tak jak wcześniej działało.

Może pisanie testów nie powinno być z góry określone, kiedy należy pisać. Może wystarczą testy, kiedy mamy taką potrzebę - Test-Whenever. Coś takiego jak zasada 80-20. 20% testów sprawdza 80% funkcjonalność. Niektóra funkcjonalność nie potrzebuje testów, a przy kodzie, gdzie mniej bezpieczniej się czujemy to możemy napisać więcej testów. I ta metoda ma swoją wadę. Zawsze jak zaczynam pisać nowy kod to mam wrażenie jakby wszystko było czytelne, oczywiste, proste i wszyscy powinni zrozumieć co kod robi, ale jak po roku wracam do swojego kodu to klnę na autora tego spaghetti kodu :)

Może testy nie powinny wyjść z potrzeby autora code, ale od osoby, która robi code review.

Dylematy z pisaniem testów jest bardzo dużo. Każda metoda ma swoich zwolenników i przeciwników. Może lepiej będzie zastosować metodę Test-Never?