DECLARE @v_name NVARCHAR(MAX)
DECLARE v_cursor CURSOR LOCAL STATIC FORWARD_ONLY READ_ONLY FOR
select * from ....
OPEN v_cursor
WHILE 1=1
BEGIN
FETCH NEXT FROM v_cursor INTO @v_name
IF @@fetch_status = 0
BEGIN
Begin TRY
.....
End TRY
Begin CATCH
PRINT Error_Message()
BREAK
End CATCH
END
ELSE BREAK
End
CLOSE v_cursor
DEALLOCATE v_cursor
W SSMS przydałby się edytor snippetów. Może kiedyś będzie Resharper dla t-SQL'a :)
Pokazywanie postów oznaczonych etykietą best practice. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą best practice. Pokaż wszystkie posty
czwartek, 3 marca 2016
Szablon do sql kursora
Pewne rzeczy nie można przeskoczyć - takie jak kursor w sql server. Często szukam przykładów z użyciem kursora, więc postanowiłem zamieścić szablon.
środa, 16 grudnia 2015
Dekompozycja projektu w R
Robiłem prezentacje i zastanawiałem się jak można zapisać cały projekt. Szukałem po sieci jakiś dobrych praktyk do dekompozycji plików. Ja wykombinowałem podział całego projektu na kilka plików:
Co w tych plikach jest? Zaczynając od początku:
Install.r - instalacja pakietów (ten skrypt wykonujemy tylko raz, aby pobrać paczki)
Functions.r - wszystkie funkcje
Load.r - ładowanie pakietów oraz przygotowywanie danych do prezentacji
Presentation.rpres - warstwa prezentacji, równie dobrze możne być to plik w Rmd czy z użyciem shiny (powód istnienia tego pliku jest TYLKO wyświetlanie tych danych jakie chcemy przedstawić, nie ma logiki biznesowej).
custom.css - customizacja warstwy prezentacji, czyli overridowane i dodatkowe css'y
I na końcu w folderze figures mam wszystkie zdjęcia.
Prezentacja o najpopularniejszych kryzysach ekonomicznych nie jest skończona. Jeszcze dużo chciałoby się dodać. Zaletą rpres jest to, że za każdym razem możemy mieć aktualne dane na prezentacji.
Poniżej rezultat wygenerowanej prezentacji:
Co w tych plikach jest? Zaczynając od początku:
Install.r - instalacja pakietów (ten skrypt wykonujemy tylko raz, aby pobrać paczki)
Functions.r - wszystkie funkcje
Load.r - ładowanie pakietów oraz przygotowywanie danych do prezentacji
Presentation.rpres - warstwa prezentacji, równie dobrze możne być to plik w Rmd czy z użyciem shiny (powód istnienia tego pliku jest TYLKO wyświetlanie tych danych jakie chcemy przedstawić, nie ma logiki biznesowej).
custom.css - customizacja warstwy prezentacji, czyli overridowane i dodatkowe css'y
I na końcu w folderze figures mam wszystkie zdjęcia.
Prezentacja o najpopularniejszych kryzysach ekonomicznych nie jest skończona. Jeszcze dużo chciałoby się dodać. Zaletą rpres jest to, że za każdym razem możemy mieć aktualne dane na prezentacji.
Poniżej rezultat wygenerowanej prezentacji:
niedziela, 13 kwietnia 2014
Pamiętaj o aktualizacji pomocy w PS
Dobrą praktyką przy pracy z PowerShellu jest aktualizacja pomocy. Niestety nie zawsze o tym pamiętam :) i dobrze jest dodanie sobie zdarzenia które będzie aktualizowało zadanie. Na samym początku tworzymy trigger, który będzie uruchamiany w piątki wieczorem jak komputer nie będziesz pracował przy komputerze oraz update będzie uruchamiany nawet jak notebook będzie działał na baterie (StartIfOnBattery).
$trigger = New-JobTrigger -Weekly -At "8:00 PM" -DaysOfWeek Friday $scheduledOption = New-ScheduledJobOption –StartIfIdle -StartIfOnBattery -RequireNetworkSkrypt, który wykonuje update wygląda następująco:
$updateScript = {Update-Help -Module * -Force}
Aby zarejestrować zdarzenie wystarczy wykonać poniższe polecenieRegister-ScheduledJob -Name UpdatePowerShellHelp -Trigger $trigger -ScheduledJobOption $scheduledOption -ScriptBlock $updateScriptAby zobaczyć wynik należy przejść do okna z harmonogramem zadań:
start "Taskschd.msc"
poniedziałek, 10 marca 2014
Szybka implementacja WhatIf i Confirm w PS
Kiedyś nie wiedziałem o parametrach SupportsShouldProcess i ConfirmImpact. Z powodu tej niewiedzy ręcznie implementowałem WhatIf i Confirm za pomoca [switch] w parametrze.
Ten poniższy kod jest bardziej dla mnie niż dla kogoś innego, ponieważ teraz prawie zawsze staram się używać tych dwóch parametrów, a zawsze zapominam sobie o tych nazwach :)
Kiedy wywoła się polecenie z parametrem WhatIF to wyświetli się poniższy komunikat:
W przypadku Conform to potwierdzenie jest uzależnione od hosta
Poniższy rysunek przedstawia 2 różne host. Małe okienko potwierdzenia należy do PowerShell ISE, a duże okienko tekstowe należy do PowerShell ConsoleHost:
Ten poniższy kod jest bardziej dla mnie niż dla kogoś innego, ponieważ teraz prawie zawsze staram się używać tych dwóch parametrów, a zawsze zapominam sobie o tych nazwach :)
function Get-CmdletJson
{
[cmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')]
param()
if($PSCmdlet.ShouldProcess(' $PSCmdlet'))
{
$PSCmdlet | ConvertTo-Json
}
}
Kiedy wywoła się polecenie z parametrem WhatIF to wyświetli się poniższy komunikat:
Get-CmdletJson -WhatIf #What if: Performing the operation "Get-CmdletJson" on target " $PSCmdlet".
W przypadku Conform to potwierdzenie jest uzależnione od hosta
Get-CmdletJson -Confirm
Poniższy rysunek przedstawia 2 różne host. Małe okienko potwierdzenia należy do PowerShell ISE, a duże okienko tekstowe należy do PowerShell ConsoleHost:
piątek, 28 lutego 2014
Generowanie start.bat dla projektu w VS
Czy kiedykolwiek musiałeś uruchomić aplikację z linii poleceń, która miała tak dużo linijek z argumentami, że nie mieściła się w oknie cmd? Ja miałe taką przyjemność i ten post jest właśnie o tym jak rozwiązać taki problem. Problem można rozwiązać za pomocą programu wsadowego (na ogół nazywam go start.bat). W nim zawarte jest polecenie startujące aplikację z argumentami. Aby debugować taką aplikację z poziomy VS to należy dodać parametry do właściwości programu. Poniżej są przedstawione 2 argumenty:
Napisałem skrypt w PS, aby wygenerować start.bat, który będzie mógł być wystartowany z tymi argumentami:
function New-StartBat
{
param(
[string] $csprojFilePath,
[string] $outputDir = "."
)
$userFileExtension = ".user"
$startBatFileName = "start.bat"
if(!(test-path $csprojFilePath))
{
throw "Wrong path to csproj file: $csprojFilePath"
}
[xml]$csprojContent = gc $csprojFilePath
[string]$outputType = ([string]$csprojContent.Project.PropertyGroup.OutputType)
.Trim();
if( -not($outputType -match "Exe"))
{
throw "Output type is not exe"
}
$assemblyName = ([string]$csprojContent.Project.PropertyGroup.AssemblyName)
.Trim()
$startbarContent = "start /B $assemblyName.$outputType"
$userFile = $csprojFilePath + $userFileExtension
if(!(test-path $userFile))
{
Write-host "No user file for $csprojFilePath"
$outputConditionStartBat = join-path $outputDir $startBatFileName
Write-Host "Genereting start.bat. Output is $outputConditionStartBat"
$startbarContent |
out-file $outputConditionStartBat -Encoding ascii
}
else
{
#region For each condition in user file
[xml]$userFileContent = gc $userFile
$userCondition = $userFileContent.Project.PropertyGroup.Condition
$csProjConditions = $csprojContent.Project.PropertyGroup.Condition
foreach($csprojCondition in $csProjConditions)
{
if($csprojCondition -eq $null)
{
continue;
}
[string]$conditionString = ([string]$csprojCondition)
.Trim()
$indexOfequals = $conditionString.LastIndexOf("==")+2;
if($indexOfequals -gt 2)
{
$conditionSimpleString = $conditionString
.Substring($indexOfequals)
.Trim()
.Replace("'","")
.Replace("|","_")
if($contains = $userCondition -contains $conditionString)
{
$propertyGroup = $userFileContent.Project.PropertyGroup |
?{$_.Condition -eq $conditionString }
$startArguments = $propertyGroup.StartArguments
$startBatContentWithArgs = $startbarContent+ " " + $startArguments
$outputConditionStartBat = join-path $outputDir ($conditionSimpleString + "_" +$startBatFileName)
Write-Host "Genereting start.bat for $conditionSimpleString. Output file is $outputConditionStartBat"
$startBatContentWithArgs |
out-file $outputConditionStartBat -Encoding ascii
}
}
}
#endregion
}
}
Dla różnej konfiguracji (Platform Configuration) możemy mieć różne parametry. Wygenerowany start.bat możemy uzyskać poprzez wywołanie polecenia: New-StartBat -csprojFilePath "SuperProjectName.csproj" -outputDir ".\bin\Debug"
sobota, 22 lutego 2014
MSCW jako proces normalizacji
Procesem normalizacji nazywa się proces, który przekształca dane źródłowe w ustandaryzowany format, nazwy oraz wartości bazując na pewnych regułach. Dane wyjściowe uzyskujemy z danych wejściowych oraz wykonanych regułach na tych danych. W tym przypadku będzie to normalizacja MSCW:
Reguły MSCW są regułami, które zapewniają istotne informacje (lub ich brak) w danych wyjściowych. Zapewne, nie świadomie korzystasz z tych reguł, gdyż są bardzo popularne, ale bardzo rzadko nazywa się je. Są bardzo ważne w bezpieczeństwie przesyłanych danych.
Znaczenie skrótu MSCW wyjaśnia wszystko:
Must - pole musi być w danych wejściowych oraz musi być sprawdzone i zwalidowane
Should - pole musi być w danych wejściowych, a jak nie ma wartości to zostanie zastąpione przez inną (być może domyślną) wartością
Could - jeżeli pole będzie w danych wejściowych, to te pole będzie procesowanie dalej
Won't - jeżeli pole będzie w danych wejściowych, to te pole będzie zablokowane
Przykładem normalizacji MSCW jest proces rejestracji użytkownika na stronie internetowej. Po rejestracji, dostępne informację dla innych użytkowników strony są ograniczone do podstawowych pól:
Normalizacja MSCW występuje również w dużych projektach ETL. Zawsze powinniśmy wiedzieć jakie dane powinny być procesowane, a jakie powinny być ukryte.
Reguły MSCW są regułami, które zapewniają istotne informacje (lub ich brak) w danych wyjściowych. Zapewne, nie świadomie korzystasz z tych reguł, gdyż są bardzo popularne, ale bardzo rzadko nazywa się je. Są bardzo ważne w bezpieczeństwie przesyłanych danych.
Znaczenie skrótu MSCW wyjaśnia wszystko:
Must - pole musi być w danych wejściowych oraz musi być sprawdzone i zwalidowane
Should - pole musi być w danych wejściowych, a jak nie ma wartości to zostanie zastąpione przez inną (być może domyślną) wartością
Could - jeżeli pole będzie w danych wejściowych, to te pole będzie procesowanie dalej
Won't - jeżeli pole będzie w danych wejściowych, to te pole będzie zablokowane
Przykładem normalizacji MSCW jest proces rejestracji użytkownika na stronie internetowej. Po rejestracji, dostępne informację dla innych użytkowników strony są ograniczone do podstawowych pól:
Normalizacja MSCW występuje również w dużych projektach ETL. Zawsze powinniśmy wiedzieć jakie dane powinny być procesowane, a jakie powinny być ukryte.
niedziela, 26 stycznia 2014
Error handling w PowerShellu
Tym razem o obsłudze błędów w PowerShell. Błędów w kodzie w PS jest bardzo dużo i jest to nieodłączny element PS :). Dlatego chciałbym Ci opisać najważniejsze kwestie związane w Error Handlingiem. Mamy 2 typy obsługi błędów - zakończające (terminating) i nie zakończające (non-terminating) działanie skryptu.
Przykład obsługi błędów zakończającego jest poniżej:
- występują składniowe błędy w skrypcie
- alarmować o błędach krytycznych
- rzucanie błędów w bloku try-catch-finally (tak jest, PS też ma try-catcha)
Stosuje się blok try-catch, aby przechwycić taki błąd:
Do drugiego typ (non-terminating) obsługi błędów stosuje się komendę Write-Error, a przykład jest przedstawiony poniżej:
Na końcu komunikatu jest tekst "After":
- chcemy zarejestrować błąd
- błąd nie przeszkadza w dalszym działaniu skryptu
- błąd jest przy wywołaniu elementów ( metod, właściwości) na obiektach .NETowych
Oprócz tych komend, ważne są zmienne pomocnicze
- $? - Jeżeli prawda to wywołanie zakończyło się bez błędu. Jeżeli fałsz to oznacza, że był błąd lub częściowy sukces (w trakcie wywoływania)
- $Error - jest to ArrayLista z błędami jakie wystąpiły w trakcie aktualnej sesji. Najmłodszy błąd jest dodawany na początek listy.
- $LastExitCode - Przy wywoływaniu aplikacji konsolowej, zmienna zawiera wartość ExitCode ostatniej uruchamianej aplikacji
- $MaximumErrorCount - Określa ilość trzymanych błędów w kolekcji $Error. Domyślna wartość jest 256 a maksymalna ilość zapisanych błędów może być 32 768.
- $ErrorActionPreference - Określa sposób zachowania się konsoli kiedy wystąpi błąd. Może przujmować takie wartości jak "SilentlyContinue", "Continue", "Stop", i "Inquire". Domyślna wartość to "Continue". Przykład użycia zapytania w momencie wystąpienia błędu jest przedstawiony poniżej:
- $ErrorView - określa sposób wyświetlenia błędów na host'ie. Domyślna wartość to "NormalView", ale w przypadku produkcyjnego środowiska można zmienić na "CategoryView", aby dostać zwięzły jednolinijkowy komunikat
Czasami przy niektórych komendach, które mogą zwrócić błąd można zastosować parametry -ErrorAction SilentlyContinue, aby komunikaty o błędach były 'przemilczane'. Jest to bardzo dobrze rozwiązanie, gdyż zmienna $ErrorActionPreference jest zmienną globalna dla wszystkich poleceń.
Następnym razem napisze coś o trapie i try-catch
Przykład obsługi błędów zakończającego jest poniżej:
"Before"; throw "Error!"; "After"Wtedy w konsoli mamy:
Before
Error!
At line:2 char:1
+ throw "Error!";
+ ~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (Error!:String) [], RuntimeException
+ FullyQualifiedErrorId : Error!
Na ogół taki typ obsługi błędów stosuje się gdy:- występują składniowe błędy w skrypcie
- alarmować o błędach krytycznych
- rzucanie błędów w bloku try-catch-finally (tak jest, PS też ma try-catcha)
Stosuje się blok try-catch, aby przechwycić taki błąd:
try
{
throw "Error!";
}
catch
{
Write-Host "Catch"
}
Więcej o try-catch można poczytać w about_Try_Catch_Finally.Do drugiego typ (non-terminating) obsługi błędów stosuje się komendę Write-Error, a przykład jest przedstawiony poniżej:
"Before"; Write-Error "Error!"; "After"
Na końcu komunikatu jest tekst "After":
Before
"Before";
Write-Error "Error!";
"After" : Error!
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
After
Typ obsługi błędów nie zakończający działanie stosuje się gdy:- chcemy zarejestrować błąd
- błąd nie przeszkadza w dalszym działaniu skryptu
- błąd jest przy wywołaniu elementów ( metod, właściwości) na obiektach .NETowych
Oprócz tych komend, ważne są zmienne pomocnicze
- $? - Jeżeli prawda to wywołanie zakończyło się bez błędu. Jeżeli fałsz to oznacza, że był błąd lub częściowy sukces (w trakcie wywoływania)
dir | %{ $?;$_.ABc(); $?}
I na outpucie mamy:True
Method invocation failed because [System.IO.DirectoryInfo] does not contain a method named 'ABc'.
At line:1 char:13
+ dir | %{ $?;$_.ABc(); $?}
+ ~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
False
True
Method invocation failed because [System.IO.DirectoryInfo] does not contain a method named 'ABc'.
At line:1 char:13
+ dir | %{ $?;$_.ABc(); $?}
+ ~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
False
Dla wywołanych programów konsolowych jest sprawdzany ExitCode. Jeżeli ma on wartość 0 to $? będzie przyjmował wartość true.- $Error - jest to ArrayLista z błędami jakie wystąpiły w trakcie aktualnej sesji. Najmłodszy błąd jest dodawany na początek listy.
- $LastExitCode - Przy wywoływaniu aplikacji konsolowej, zmienna zawiera wartość ExitCode ostatniej uruchamianej aplikacji
- $MaximumErrorCount - Określa ilość trzymanych błędów w kolekcji $Error. Domyślna wartość jest 256 a maksymalna ilość zapisanych błędów może być 32 768.
- $ErrorActionPreference - Określa sposób zachowania się konsoli kiedy wystąpi błąd. Może przujmować takie wartości jak "SilentlyContinue", "Continue", "Stop", i "Inquire". Domyślna wartość to "Continue". Przykład użycia zapytania w momencie wystąpienia błędu jest przedstawiony poniżej:
$ErrorActionPreference ="inquire" Write-Error "pop up text error"
- $ErrorView - określa sposób wyświetlenia błędów na host'ie. Domyślna wartość to "NormalView", ale w przypadku produkcyjnego środowiska można zmienić na "CategoryView", aby dostać zwięzły jednolinijkowy komunikat
Czasami przy niektórych komendach, które mogą zwrócić błąd można zastosować parametry -ErrorAction SilentlyContinue, aby komunikaty o błędach były 'przemilczane'. Jest to bardzo dobrze rozwiązanie, gdyż zmienna $ErrorActionPreference jest zmienną globalna dla wszystkich poleceń.
Następnym razem napisze coś o trapie i try-catch
niedziela, 19 stycznia 2014
3 najważniejsze komendy w PowerShell
Jedną z tych najważniejszych komend jest komenda, która zwraca listę komend - Get-Command. Jeżeli pierwszy raz spotkałeś się z PowerShellem to ta komenda powinna być jako pierwsza uruchomiana. Na ogól wszystko co może być odpalone w konsoli PS będzie zawarte w Get-Command.
Przypóśmy, że szukamy komendy, która zapisuje alias. Wiemy, że w nazwie będzie zaczynała się od czasownika i może mieć coś wspólnego ze słowem save :) i będzie posiadała rzeczownik na a:
Get-Command -Verb "invoke","set","save" -Noun "a*"I przed oczami widzimy komendę Set-Alias.
Lub jak będziesz chciał zobaczyć jakie komendy są dostępne dla obiektów to możesz napisać:
Get-Command *-object
Drugą bardzo ważny komendą, która pomoże Ci to jest Get-Help. Jeżeli chcesz wiedzieć w czym może Ci pomóc ta komenda to napisz:
Get-Help *
Możesz uzyskać pomoc o Get-Command
Get-Help get-command
I ostatnia z najważniejszych komend to Get-Member. Nie wiem ile razy użyłem tej komendy, ale wiele razy pomogła mi w rozpoznaniu obiektu. Możesz sprawić jakie dostępne opcje ma obiekt, który zwraca datę:
Get-Date | Get-Member
Bardzo często stosuję gm ( alias do get-member), aby sprawić jaki typ jest zwracany, ale czasami lepiej jest użyć starego dobrego GetType (alias gtn):
Get-Process | Select-Object -first 1 | get-typename
albo bardziej z.NET:
dir $env:windir | Group-Object {$_.GetType().FullName}
Get-Member stosuje jeszcze do sprawdzenia statycznych metod jakie są dla klasy, na przykład do sprawdzenia co ma do zaoferowania klasa Math.
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:
Cała magia jest w dwóch klasach abstrakcyjnych:
I druga generyczna klasa:
'Super' przykład dla StringBuilder jest przedstawiony poniżej:
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.
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.
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.
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?
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?
piątek, 5 kwietnia 2013
Najlepsze praktyki dla System.Collections.Generic
Krótko chciałem napisać 13 najlepszych praktyk przy używaniu generycznych kolekcji.
1) Nie używaj generyków jeżeli wiesz, że nie potrzebujesz
2) Używaj Stack<T> do implementacji list LIFO
3) Używaj Queue<T> do implementacji list FIFO
4) Używaj List<T> do implementacji listy z losowym dostępem do danych
5) Używaj LinkedList<T> jeżeli potrzebujesz dodawanie lub usuwanie elementów na brzegach listy
6) Używaj HashSet<T> jeżeli lista nie ma duplikatów lub potrzebujesz szybki zbiór danych
7) Używaj foreach na kolekcji kluczy zamiast używać pętli for po IDictionary<TKey,TValue>
8) Nie używaj metody ElementAt() czy ElementAtOrDefault()
9) Używaj dedykowanej klasy zamiast Tupli z dużą ilością parametrów.
10) Używaj SortedDictionary<TKey,TValue> jeżeli potrzebujesz mieć posortowane elementy
11) Używaj SortedSet<T> jeżeli potrzebujesz posortowany zbiór danych
12) Używaj KeyValuePair<TKey,TValue> zamiast Tuple<T1,T2>
13) Jeżeli implementujesz po interfejsie IEnumerable<T> to również zaimplementuj IEnumerable(z powodu wstecznej kompatybilności)
1) Nie używaj generyków jeżeli wiesz, że nie potrzebujesz
2) Używaj Stack<T> do implementacji list LIFO
3) Używaj Queue<T> do implementacji list FIFO
4) Używaj List<T> do implementacji listy z losowym dostępem do danych
5) Używaj LinkedList<T> jeżeli potrzebujesz dodawanie lub usuwanie elementów na brzegach listy
6) Używaj HashSet<T> jeżeli lista nie ma duplikatów lub potrzebujesz szybki zbiór danych
7) Używaj foreach na kolekcji kluczy zamiast używać pętli for po IDictionary<TKey,TValue>
8) Nie używaj metody ElementAt() czy ElementAtOrDefault()
9) Używaj dedykowanej klasy zamiast Tupli z dużą ilością parametrów.
10) Używaj SortedDictionary<TKey,TValue> jeżeli potrzebujesz mieć posortowane elementy
11) Używaj SortedSet<T> jeżeli potrzebujesz posortowany zbiór danych
12) Używaj KeyValuePair<TKey,TValue> zamiast Tuple<T1,T2>
13) Jeżeli implementujesz po interfejsie IEnumerable<T> to również zaimplementuj IEnumerable(z powodu wstecznej kompatybilności)
Subskrybuj:
Posty (Atom)








