čtvrtek 22. prosince 2011

Desatero uživatele Twitteru

Twitter je tu už více než pět let. Je na čase, aby někdo stanovil pravidla pro chování uživatelů :-)

  1. Nebudeš využívat jiné sociální sítě. Drž se Twitteru a budeš svobodný. Odprosti se od užívání Facebooku a Google+, které Tě svádí z cesty a narušují Tvé schopnosti stručného vyjadřování.

  2. Nebudeš posílat dotazy na nové tweety nadarmo. Nesmíš mě neustálým ručním dotazováním donucovat, abych Ti vracel nové tweety každých několik vteřin. Dost nám to zatěžuje systém. Nechej to na Tvém klientovi, který má interval občerstvování určitě nastavený rozumně.

  3. Budeš zachovávat každý den několik minut odpočinku. Během této doby se na Twitter ani nepodíváš. Naužírej se strachem, že zmeškáš nějaký zajímavý tweet, můžeš se kdykoliv podívat do historie.

  4. Budeš ctít zakladatele Twitteru i jeho mateřskou firmu Ordeo Inc. Budeš sledovat uživatele @Jack, @Biz, @Noah, @Crystal, @Jeremy, @Adam, @TonyStubblebine, @Ev, @Dom, @Rabble, @RayReadyRay, @Florian, @TimRoberts a @Blaine, protože právě oni byli na počátku vzniku našeho Twitteru.

  5. Nebudeš provádět Unfollow. Nebudeš přestávat sledovat uživatele, jenom proto, že je to Tvůj konkurent a protože nechceš, aby Tě předstihl v počtu followerů.

  6. Nesmilníš a nevložíš příspěvek do jiné mikroblogovací služby. Nemáš zapotřebí, aby ses karikaturami nezralých a příživnických mikroblogovacích služeb připravil o radost ze skutečného Twitteru. Drž se ho a naučíš se psát zajímavě a trefně a ocení Tě mnoho followerů.

  7. Neukradneš obsah cizího tweetu. Nesnaž se zalíbit tím, že zajímavý tweet označíš za svůj. Používej raději Retweet. Co získáš na oblíbenosti a počtu followerů, to ztratíš na klidné mysli.

  8. Nebudeš vystupovat pod falešnou identitou. Nesnaž se být zajímavý tím, že budeš vystupovat za známou osobnost. Twitter Tě odhalí a zablokuje Tvůj účet. Snižuješ důvěryhodnost celé sítě a sám sebe.

  9. Nebudeš žádostivě dychtit po followerech toho, kdo Tě sleduje. Nevnucuj se a nevyžaduj laciné retweety, jenom aby jsi získal rychlé followery. Svým chováním můžeš způsobit rozvrat a Unfollow dotyčného. Buď trpělivý a followeři si cestu k Tobě určitě najdou.

  10. Nebudeš závistivě projíždět seznamy followerů top uživatelů a chamtivě vyhlížet své nové followery. Neužírej se tím, že máš málo followerů. Někomu to jde líp a stačí mu pouze jeho jméno. Někdo to má těžší. Drž se své vize a kvalitním obsahem si své followery určitě získáš.

středa 21. prosince 2011

Vlastní úlohy pro MSBuild

Automatizujte. Váš čas je drahý. Nedělejte ručně činnosti, které za Vás mohou udělat stroje během několika okamžiků a s minimální chybovostí.

Součástí Visual Studia je buildovací systém MSBuild. MSBuild pracuje ve Visual Studiu na pozadí při kompilaci projektů do spustitelného kódu. MSBuild je také využíván při týmovém vývoji na speciálních buildovacích serverech. Ať už provádíte build produkční verze aplikace, build testovací verze, build kontinuální integrace nebo úplně jinou automatizovanou úlohu, může se stát, že vyvstane specifická potřeba, kterou standardní úlohy MSBuildu nezvládnou. Pak se přiblíží okamžik, kdy budete potřebovat napsat úlohu vlastní. Určitě se toho nebojte. Odměnou Vám bude zrychlení práce a uznání ostatních členů vývojového týmu ;-)

Vytvoření knihovny s úlohou

Vytvoříme projekt typu Class Library. V našem příkladu založíme projekt Firma.Nastroje.Build.Ulohy.

Do projektu přidáme reference na frameworkové assembly Microsoft.Build.Framework a Microsoft.Build.Utilities.v4.0 (pro .NET FW 4.0).

Založíme třídu úlohy. Třída musí implementovat rozhraní Microsoft.Build.Utilities.ITask. Je vhodné podědit abstraktní třídu Microsoft.Build.Utilities.Task. Překryjeme metodu Execute(), která je vyvolána MSBuildem během provádění. Provádění úlohy je konfigurovatelné přes nastavení veřejných vlastností třídy. Nezapomeňte projekt zkompilovat ;-)

using System;
 
namespace Firma.Nastroje.Build.Ulohy
{
    /// <summary>
    /// Implementace mojí úlohy sestavení.
    /// </summary>
    public class MojeUloha : Microsoft.Build.Utilities.Task
    {
        /// <summary>
        /// Povinný parametr úlohy.
        /// </summary>
        [Microsoft.Build.Framework.Required]
        public string PovinnyParametrUlohy { get; set; }
 
        /// <summary>
        /// Nepovinný parametr úlohy.
        /// </summary>
        public string NepovinnyParametrUlohy { get; set; }
 
        /// <summary>
        /// Provádění úlohy.
        /// </summary>
        /// <returns>true, pokud je provádění úspěšné.</returns>
        public override bool Execute()
        {
            throw new NotImplementedException();
        }
    }
}

Nasazení knihovny na buildovací počítač

Všechny rozšiřující knihovny, které by měl znát MSBuild, umístěte na buildovacím počítači do adresáře definovaného v proměnné $(MSBuildExtensionsPath). Obvykle se jedná o "c:\Program Files (x86)\MSBuild". Doporučuji knihovnu zařadit ještě do podadresáře podle firmy nebo projektu. Ukázková knihovna bude mít v našem příkladě absolutní cestu "c:\Program Files (x86)\MSBuild\Firma\Firma.Nastroje.Build.Ulohy.dll".

Použití v buildovacím projektu

Nejprve musíme zadeklarovat naši úlohu na začátku řídícího projektového souboru (.proj, .csproj) ...

<UsingTask 
   TaskName="MojeUloha" 
   AssemblyFile="$(MSBuildExtensionsPath)\Firma\Firma.Nastroje.Build.Ulohy.dll"/>

... a poté zadefinovat konkrétní použití buildovací úlohy:

<MojeUloha
   PovinnyParametr="HodnotaPovinnehoParametru"
   NepovinnyParametr="HodnotaNepovinnehoParametru"
   />

Poznámky

  • Pro účely ladění třídy Vaší úlohy si vytvořte jednotkové testy, viz. TDD.
  • Framework Vaší knihovny musí být na buildovacím počítači podporován. Úlohy v jednom buildovacím projektu mohou být napsány pro různé frameworky.
  • Úlohy mohou poskytovat i návratové argumenty.
  • Argumenty úloh mohou být kolekce hodnot, např. kolekce názvů souborů.
  • Alternativou k vlastním úlohám pro MSBuild je vytvoření spustitelné exe aplikace, které předáte potřebné parametry přes příkazovou řádku.

sobota 3. prosince 2011

Pravidla pro pojmenování objektů v C# - část 2

  1. Úvod, jazyk, názvy tříd
  2. Názvy vlastností (properties), polí (fields) a proměnných (variables)
  3. Názvy metod a argumentů
  4. Další pravidla, názvy balíčků, testovací třídy

V předchozím díle jsme se podívali na několik základních pravidel pro názvosloví tříd. Neméně důležité je logicky a významově pojmenovat její vlastnosti, pole a proměnné uvnitř metod.

Názvy vlastností, polí a proměnných

Chtělo by se říci, že názvy veřejných vlastností jsou důležitější než názvy neveřejných vlastností, polí a proměnných. Není to však úplně pravda. Veřejné rozhraní třídy je samozřejmě důležité pro klienty třídy. Správný název urychlí pochopení a ušetří přepínání mezi kódem a dokumentací. Neveřejné názvy jsou však významné pro znovupoužitelnost, čistotu kódu, pochopení významu a efektivní navigaci v kódu.

Na co bychom si tedy měli dát pozor?

  1. Pro názvy vlastností (properties) se používá PascalCase, např. RodneCislo.

  2. Pro názvy polí (fields) se používá camelCase, např. rodneCislo.

  3. Pro názvy konstantních polí se používá PascalCase, např.

    private const int PocetMesicu = 12;

  4. Pro názvy proměnných (variables) se používá camelCase, např. polozky.

  5. Pokud vlastnost a pole (a proměnná) odpovídají stejnému logickému významu, měli by si jejich názvy odpovídat. Např.

    private string rodneCislo;
    
    public string RodneCislo
    {
        get
        {
            return rodneCislo;
        }
    
        private set
        {
            rodneCislo = value;
        }
    }
    

  6. Pokud je vlastnost autoimplementovatelná, tzn. getter je jednoduché vrácení hodnoty pole a setter je jednoduché nastavení hodnoty pole, je vhodné použít zkrácený a přehlednější zápis:

    public string RodneCislo { get; private set; }
    
    Výhodou tohoto zápisu je mimo jiné i jednodušší refaktorizace názvu. Nemusíte refaktorovat zvlášť název vlastnosti a pole.

  7. Pravidla uváděná dále jsou společná pro názvy vlastností, polí i proměnných.

  8. Vyhněte se opakování názvu třídy v názvech jejích vlastností. Např. třída Objednavka by neměla mít vlastnost PopisObjednavky nebo ObjednavkaId. Použijte "holý" název Popis a Id.

  9. V případě odkazu na Id jiné třídy ("primární klíč"), bude název odkazované třídy předcházet názvu vlastnosti Id:

    public class Osoba
    {
        public int Id { get; set; }
    }
    
    public class Uzivatel
    {
        public int OsobaId { get; set; }
    
        public String Jmeno { get; set; }
    }
    
    V tomto případě by bylo zřejmě vhodnější, aby třída Uzivatel nabízela přístup k objektu typu Osoba
    public Osoba Osoba
    

  10. Použijte název třídy v názvech vlastností jiných tříd, které na ni odkazují nebo vlastnost odpovídá vlastnosti odkazované třídy. Všimněte si vlastnosti Kod u třídy Mena a vlastnosti KodMeny u třídy Objednavka. Obě mají v systému stejný význam.

    public class Mena 
    {
        public string Kod { get; set; }
        public string Nazev { get; set; }
    }
    
    public class Objednavka 
    {
        public string KodMeny { get; set; }
        public decimal Castka { get; set; }
    }
    

  11. Pokud je to vhodné, použijte upřesňující významovou příponu. Např. CastkaVMeneDokladu, DobaTrvaniVMilisekundach, DenVTydnu.

  12. Pro booleovské vlastnosti použijte vhodnou předponu, např. JePlatna, MaNarokNaOdmenu.

  13. U zkratek ponechejte pouze první písmeno velké, např. Html, Id, Ico, KategorieDph.

  14. Nepoužívejte v názvech datové typy. Místo PolozkaObjednavkyList použijte PolozkyObjednavky, místo VystaveniDate použijte DatumVystaveni.

  15. Pokud používáte víceslovné názvy, měly by být přiměřeně dlouhé a srozumitelné. Snažte se vyjádřit stručně. Pokud je to však nezbytné, nestyďte se použít delší název.

  16. Stejně jako u názvů tříd je vhodné používat názvy z domény problému. Vycházet byste měli z doménového slovníku, který navrhne doménový analytik.

  17. Vyhněte se používání různých synonym pro logicky stejnou vlastnost různých tříd.

Používáte pravidlo, které zde není uvedeno? Máte připomínku k některému doporučení? Neváhejte vložit komentář.

čtvrtek 24. listopadu 2011

Rhino Mocks & spol. aneb imitujte rozhraní

Frameworky plné falše, náhražek, imitací a podvrhů ...

... a proto je máme tak rádi a proto je ke svému vývojářskému životu potřebujeme :-)

Nebojte se, jsme stále ještě ve světě férového programování. Tento příspěvek je krátkým motivačním úvodem do světa mock, fake, stub a dalších typů objektů, bez kterých se neobejde žádný vývojář, který to myslí vážně s psaním jednotkových (unit) a integračních testů.

Mock objekty a k čemu jsou dobré

Mock objekt vznikne jako fiktivní instance rozhraní nebo třídy. Této objektové imitaci pak můžete přiřadit chování, které očekáváte. Můžete také stnovit pravidla použití, které mohou být prověřeny na konci testu.

Předpokládám, že nejčastěji využíváte nebo budete využívat možnost "falešné" implementace rozhraní. V tomto případě oceníte techniku programování proti rozhraní (namísto programování proti implementaci). Je bežné, že třídy mají závislosti na jiných rozhraních. Pokud takovou třídu chcete pokrýt jednotkovými nebo integračními testy, musíte umět tyto závislosti vyřešit. Níže je uveden příklad který zastupuje tisícovku slov.

Většina mockovacích frameworků nabízí také validaci pořadí a počtu volání metod nebo přístupu k property mock objektu. Touto technikou můžete prověřit volání metod, které jsou pro potřeby testu důležité.

Rhino Mocks, Moq, NMock2, Isolator, TypeMock nebo Moles

Mockovacích frameworků pro .Net je několik. Liší se možnostmi toho, které třídy lze mockovat, intuitivností zápisu, možnostmi validačních pravidel, podporovanými verzemi .Net frameworků a dalšími aspekty. Přehledné srovnání je k dispozici na webu PHP vs .Net.

Nejrošířenějším volně dostupným frameworkem je Rhino Mocks. Zápis pravidel mock objektů je natolik intuitivní a variabilní, že pokryje většinu Vašich potřeb. Já osobně používám právě Rhino Mocks. Otázkou je, zda-li autor bude i nadále funkcionalitu rozvíjet. Pokud se nepletu, tak poslední update je někdy z roku 2009.

Ještě mám osobní zkušenost s NMock2. Pro mě je nevyhovující z toho důvodu, že názvy metod a vlastností se zapisují textově. Nejen že takový zápis zdržuje, nedá se využít IntelliSense, ale navíc není bezpečný pro refaktoring.

Mockování pro začátečníky

Mějme rozhraní zadefinovaná takto:

namespace Firma.Bll
{
    /// <summary>
    /// Rozhraní pro práci s kurzy.
    /// </summary>
    public interface IKurzyBll
    {
        /// <summary>
        /// Vrátí hodnotu kurzu měny.
        /// </summary>
        /// <param name="kodMeny">Kód měny.</param>
        /// <param name="datumPlatnosti">Datum platnosti.</param>
        /// <returns>Hodnota kurzu bez omezení přesnosti.</returns>
        decimal VratitHodnotuKurzuMeny(string kodMeny, DateTime datumPlatnosti);
    }

    /// <summary>
    /// Rozhraní pro práci s měnami.
    /// </summary>
    public interface IMenyBll
    {
        /// <summary>
        /// Převede částku v měně na částku domácí měny.
        /// </summary>
        /// <param name="kodMeny">Kód měny.</param>
        /// <param name="datumPlatnosti">Datum platnosti.</param>
        /// <param name="castkaVMene">Částka v měně.</param>
        /// <returns>Částka převedená na domácí měnu s přesností na dvě desetinná místa.</returns>
        decimal PrevestCastkuNaDomaciMenu(string kodMeny, DateTime datumPlatnosti, decimal castkaVMene);
    }
}

Třída implementující rozhraní IMenyBll vyžaduje při vzniku předání implementace IKurzyBll:

namespace Firma.Bll.Impl
{
    /// <summary>
    /// Implementace práce s měnami.
    /// </summary>
    public class MenyBll : IMenyBll
    {
        private IKurzyBll KurzyBll { get; set; }
          
        /// <summary>
        /// Pomocí constructor injection je vložena závislost na IKurzyBll.
        /// </summary>
        /// <param name="kurzyBll">Práce s kurzy.</param>
        public MenyBll(IKurzyBll kurzyBll)
        {
            KurzyBll = kurzyBll;
        }
 
        public decimal PrevestCastkuNaDomaciMenu(string kodMeny, DateTime datumPlatnosti, decimal castkaVMene)
        {
            decimal hodnotaKurzu = KurzyBll.VratitHodnotuKurzuMeny(kodMeny, datumPlatnosti);
            decimal castkaVDomaciMene = Math.Round(castkaVMene * hodnotaKurzu, 2, MidpointRounding.AwayFromZero);

            return castkaVDomaciMene;
        }
    }
}

A teď přichází chvilka slávy pro Rhino Mocks. Správnost implementace IKurzyBll nás v případě testování třídy MenyBll příliš nezajímá. Ale přesto ji potřebujeme. Bez ní implementaci MenyBll neotestujeme. V produkčním běhu aplikace může být IKurzyBll implementováno nad webovou službou, databázovou tabulkou nebo jiným způsobem. Pro účely testu by však bylo náročné takovou implementaci připravit. Jednoduchým řešením je vytvoření mock objektu, který naučíme vracet kurz podle potřeby našeho testu. Celá myšlenka by měla být zřejmá z kódu testovací metody:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;

namespace Firma.Bll.Impl.Test
{
    /// <summary>
    /// Unit testy pro třídu MenyBll.
    /// </summary>
    [TestClass]
    public class MenyBllTest
    {
        private const decimal HodnotaKurzuMenaEur = 23.530m;

        [TestMethod]
        public void PrevodCastkyEurTest()
        {
            // Repozitář pro správu mock objektů.
            MockRepository mocks = new MockRepository();

            // Vytvoření mock objektu pro rozhraní IKurzyBll.
            IKurzyBll kurzyBllMock = mocks.StrictMock<IKurzyBll>();

            string kodMeny = "EUR";
            DateTime datumPlatnosti = DateTime.Today;

            // Definice očekávaného chování.
            // Při volání VratitHodnotuKurzuMeny() s parametry "EUR" a dnešní datum 
            // vrací hodnotu 23.530m. Počet volání této metody není omezen.
            Expect.Call(kurzyBllMock.VratitHodnotuKurzuMeny(kodMeny, datumPlatnosti)).
                Return(HodnotaKurzuMenaEur).Repeat.Any();

            // Realizuje definici všech mock objektů.
            mocks.ReplayAll();

            // Vytvoření instance testované třídy s podvržením mock implementace IKurzyBll.
            MenyBll menyBll = new MenyBll(kurzyBllMock);

            decimal castkaEur = 10.50m;
            decimal ocekavanaCastkaCzk = 247.07m;
            decimal vracenaCastkaCzk = menyBll.PrevestCastkuNaDomaciMenu(kodMeny, datumPlatnosti, castkaEur);

            // Pokud je očekávaná částka různá od skutečně vrácené částky, 
            // dojde k výjimce a test skončí chybou.
            Assert.AreEqual(ocekavanaCastkaCzk, vracenaCastkaCzk);
        }
    }
}

Pokud patříte k vyznavačům TDD (vývoj řízeny testy), pak byste zřejmě postupovali tak, že ještě před vlastním implementováním metody PrevestCastkuNaDomaciMenu() napíšete tento a případné další testy. Tzn. zadefinujete očekávané cílové chování metody formou unit testů. Následná korektní implementace zajistí, že všechny testy začnou procházet.

Několik odkazů pro rychlejší rozjezd

čtvrtek 17. listopadu 2011

NConfig - řešení pro lokální konfigurace

Proč se nám může NConfig hodit

Přijdete ráno do práce, zvolíte ve Visual Studiu Get Latest Version nad celým projektem (řešením) a jdete si uvařit kafe. Pokračujete v implementaci nové funkcionality a spouštíte testy nad databází. Začaly se však objevovat chyby, které jsou hodně podezřelé. Vypadá to jako by v příslušné databázi nebyly struktury, které jste si vytvořili nově v rámci vývoje. Pátráte, jak je to možné a ztrácíte drahocené minuty. Když už začínáte být trochu zoufalí, uvědomíte si, že jste si aktualizovali lokální workspace. Podíváte se do konfiguračního souboru a zjistíte, že někdo změnil směrování na databázi! V historii změn zjistíte, že to byl Peter. V duchu si zanadáváte a zároveň si uvědomíte, že už jste párkrát udělali kolegům to samé. Omylem jste dali vrácení změn na server (Check-in) ve společném konfiguračním souboru (Web.config, App.config). Pokud však máte systémový přístup k řešení problémů, pokusíte se toto neustálé přepisování nějak elegantně vyřešit.

A možná by Vám mohl pomoci NConfig!

Jak získat NConfig

NConfig je .Net knihovna, jejíž použití ve Vašich projektech není nijak licenčně omezeno. Projekt je vyvíjen na serveru GitHub na adrese https://github.com/Yegoroff/NConfig.

Já jsem postupoval tak, že jsem si přes odkaz Download stáhnul celý adresář jako zip soubor. Následně jsem jej rozbalil, otevřel solution NConfig.sln a sestavil z projektu NConfig výslednou dll knihovnu ve verzi pro framework 4.0 (k dispozici je i projekt pro framework 3.5). Dále jsem již pracoval pouze s dll knihovnou.

Co NConfig umí

NConfig umí slučovat konfigurace z více konfigračních souborů. Umí také za běhu vybrat konfigurační soubor podle názvu aktuálního počítače. Tato funkcionalita je řešením pro výše uvedený motivační případ.

// Sloučí nastavení defaultního konfiguračního souboru a 
// Configs\Custom.config, resp. Configs\{NazevPocitace}.Custom.config
NConfigurator.UsingFiles(@"Configs\Custom.config").SetAsSystemDefault();

Autor tvrdí, že NConfig lze využít v aplikacích typu ASP.Net, ASP.Net MVC, WinServies, WinForms, WPF a konzolová aplikace.

Ukázka použití

Požadujeme, aby si vývojáři Peter a Steve mohli nastavit navzájem nezávislé lokální konfigurace pro připojení k databázím tak, aby nezasahovali do společného konfiguračního souboru.

Vytvoříme si jednoduchou konzolovou aplikaci a nareferencujeme NConfig.dll. Přidáme standardní App.config. Uživatelské konfigurační soubory umístíme do složky Configs. Ve složce vytvoříme defaultní Custom.config a konfigurační soubory pro Petera a Steva - PeterComputer.Custom.config a SteveComputer.Custom.config. Viz. obrázek. Nezapomeňte nastavit pro konfigurační soubory ve složce Configs vlastnost Copy To Output Directory na true.

Soubor App.config vypadá takto:

<?xml version="1.0"?>
<configuration>
 <appSettings>
  <add key="Database" value="AppDatabase"/>
  <add key="User" value="AppUser"/>
 </appSettings>
</configuration>

Soubor Custom.config vypadá takto:

<?xml version="1.0"?>
<configuration>
 <appSettings>
  <add key="User" value="CustomUser"/>
 </appSettings>
</configuration>

A například soubor PeterComputer.Custom.config vypadá takto:

<?xml version="1.0"?>
<configuration>
 <appSettings>
  <add key="Database" value="PeterComputerDatabase"/>
  <add key="User" value="PeterComputerUser"/>
 </appSettings>
</configuration>

Třída Program konzolové aplikace využije volání metody UsingFiles() třídy NConfig.NConfigurator, která sloučí původní App.config s Configs\Custom.config, případně s konfiguračními soubory podle spuštěného počítače:

class Program
{
    static void Main(string[] args)
    {
        // SwitchOnCustomConfig();

        Console.WriteLine(String.Format("User='{0}'", ConfigurationManager.AppSettings["User"]));
        Console.WriteLine(String.Format("Database='{0}'", ConfigurationManager.AppSettings["Database"]));
    }

    static void SwitchOnCustomConfig()
    {
        NConfigurator.UsingFiles(@"Configs\Custom.config").SetAsSystemDefault();
    }
}

Přehled scénářů:

Scénář Konfigurační soubor Hodnota klíče Database Hodnota klíče User
Není zapnutá podpora volitelných konfiguračních souborů - nevolá se metoda SwitchOnCustomConfig(). App.config AppDatabase AppUser
Je zapnutá podpora volitelných konfiguračních souborů - volá se metoda SwitchOnCustomConfig() a aplikace není spuštěna ani na počítači Petera ani Steva. Custom.config AppDatabase CustomUser
Je zapnutá podpora volitelných konfiguračních souborů - volá se metoda SwitchOnCustomConfig() a aplikace je spuštěna na počítači Petera. PeterComputer.Custom.config PeterComputerDatabase PeterComputerUser