Minulý týden jsme si udělali s kolegou @bajtosem, jeho ženou a novým kamarádem @mictechem príma výlet do Berlína. Hlavním cílem bylo zúčastnit se akce Code Retreat Berlin 2011. Samozřejmě došlo i na networking, socializing, hangouting, gaststätting, beer-evaluating a sightseeing (neboli sezení v hospodě a motání se s kocovinou po městě druhý den), o tom ale třeba někdy příště. Dnes bych se chtěl s vámi podělit, o čem je Code Retreat a co mi to dalo.
Přednáška o ASP.NET MVC 2
| 1 comments | MVC
Innovator of the Year
| 1 comments |
Připojte se k nám
| 4 comments | jobs
Spike aneb ověření, jestli to vůbec půjde
Jak jsem přešel na Linux a MonoDevelop
| 3 comments | Blog Engine, Linux
...a jeden navrch
| 2 comments |
Čtyři smartfouni
| 2 comments |
Co by měl každý programátor vědět
| 18 comments |
Podle mého jsou určité základy, které musí každý programátor o svém jazyce vědět. Priorita operátorů podle mně patří mezi ně. Argument, že v jazyce XX nebo YY to bylo jinak, je podle mně zcestný. Programovací jazyky jsou natolik jednoduché, že programátor nemůže mít problém si těch pár věcí zapamatovat. Netvrdím, že musíte z hlavy vědět vše o nějakém obskurním jazyku, který používáte jednou za uherský rok, ale pokud se někdo už několik let živí psaním kódu v C#, musí takové věci znát bez zaváhání.
Co všechno by jste tedy měli vědět o svém hlavním programovacím jazyku?
- Priorita operátorů (!, ++, ||, &&, ?:)
- Jak zapsat hodnotu různých datových typů (0xAF, 123 a 123L, 0.12M a 0.12D)
- Základní konverze na string a zpět (například donedávna jsem považoval za samozřejmost, že každý ví jak konvertovat "FFEEDD" na int, ale byl jsem vyveden z omylu)
- Speciální jazykové konstrukce jako anonymní delegáti a lambda funkce
Tento seznam určitě není kompletní, pokud vás napadne něco dalšího, napište to do komentářů.
Pokud tyto základní věci neovládáte, riskujete dva velké problémy: Budete se pomalu orientovat v kódu ("jakého typu je var a = new[] { 1, 10, 100, 1000 };?"), a při psaní budete používat zbytečné ornamenty (if(((age>60)||(disabled==true))&&(balance>limit))). Druhý problém je o dost horší než první, protože při čtení zpomalujete jen sami sebe. Pokud ale kvůli své neznalosti použijete o 8 závorek navíc, ztěžujete práci ostatním, protože znepřehledňujete kód. Je sice pravda, že ostatní pak nemusí používat svn blame, protože už znají váš styl:-) Být poznat podle stylu kódu ale není nic o co by jste měli stát. A taky budete hodně nadávat na StyleCop:-)))
Pokud neovládáte ani naprosto základní věci, jak chcete přesvědčit ostatní o tom, že jste dobří programátoři?
Co všechno musíte vyřešit při psaní WPF aplikace
| 0 comments |
- INotifyPropertyChanged
- Validace
- Lokalizace
- Undo/Redo
INotifyPropertyChanged
Aby View vědělo kdy se má updatovat, je nutné u všech ViewModel objektů implementovat rozhraní INotifyPropertyChanged. Naštěstí je velmi jednoduché, ale budete muset psát spoustu opakovaného kódu:
string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged("Name);
}
}
Vyhnout se mu můžete buď generováním kostry ViewModelu pomocí DSL jazyka, nebo pomocí AOP (kolegové používají PostSharp), kde stejná property může vypadat takto:
[Notify]
public string Name { get; set; }
Lokalizace
Existuje několik přístupů k lokalizaci WPF aplikace, které se liší způsobem uložení resource stringů, možností výběru lokalizovaných vlastností a možností přepínat jazyk "za běhu", bez nutnosti restartu aplikace. Řešení které doporučuje Microsoft (přes binární XAML, neboli BAML) potřebuje externí nástroj LocBaml.exe, editovat jazykové verze musíte v CSV a při přepnutí jazyka za běhu se nelokalizují již otevřená okna. Které vlastnosti budou lokalizované se dá určit až při lokalizaci, takže překladatel se může rozhodnout, že např. sloupec v tabulce bude mít jinou velikost nebo label se zarovná na jinou stranu. To může být výhoda i problém, záleží na vašich potřebách. Další dva způsoby naleznete v článku Localizing WPF Applications using Locbaml, oba ale neumožňují přepínat jazyk za běhu.
Zajímavé řešení je popsáno v WPF Localization - On-the-fly Language Selection. To už umožňuje skutečné přepnutí jazyka bez nutnosti restartu aplikace. Je založené na vlastním Converteru, který provádí lokalizaci, díky čemuž lze používat poziční parametry v resource stringu ("{0}") a jejich hodnoty dokonce bindovat. Trik umožňující okamžité přepnutí jazyka spočívá v nahrazení lokalizovaných hodnot MultiBinding objektem, kde první vazba je na LanguageContext.Instance.Dictionary, která při změně jazyka posílá událost PropertyChanged. To způsobí znovunačtení všech hodnot. Tomuto řešení bych vytknul pouze způsob uložení resourců (vlastní XML), ale velmi lehce si můžete napsat vlastní LanguageDictionary a číst hodnoty např. z resx souborů.
Validace
Při prvním pohledu na WPF se zdá, že validace je vyřešená věc, ale pokud chcete použít vzor MVVM, není to tak jednoduché. Ve ViewModelu tedy implementujeme IDataErrorInfo a projdeme všechny deklarace Binding v XAMLu a přidáme ValidatesOnDataErrors=true.
Jenže kromě business validací je nutné také validovat vstup od uživatele. To jsou opravdu dvě různé věci: Mějme třídu Person s property Age typu int. "Business" validace je, že Age nesmí být záporné a musí být menší než 150. Když je hodnota mimo tento rozsah, vrátíme přes IDataErrorInfo chybovou hlášku. Jenže co když uživatel zadá "qweqweqwr"? Výchozí chování Bindingu je výjimku prostě spolknout. Můžeme nastavit ValidatesOnExceptions na true, ale jednak nemůžeme změnit validační hlášku, a také nechceme žádné výjimky. Výjimky jsou pro výjimečné případy, např. když je vyhlášen výjimečný stav. Spoléhání na výjimky může aplikaci znatelně přibrzdit.
WPF Binding zpracovává vstup přes řetěz validátor - konvertér - property setter. Možným řešením by bylo vkládat vlastní validátory do deklarace Bindingů. To ale odporuje našemu cíli, dostat všechnu logiku do ViewModelu. Navíc až budeme objekt ukládat (uživatel zmáčkne Ctrl+S), nedozvěděli bychom se, že na formuláři jsou nevalidní data. Informaci o validitě si přece chceme přečíst z ViewModelu. Nejen kvůli tomu odpadá i další možnost: generovat validátory podle metadat ViewModelu. Ani to nezkoušejte, nejde to. Jak zjistil Miro, Binding je jen MarkupExtension, který vytvoří BindingExpression, který se teprve stará o update hodnot, jenže většina jeho důležitých vlastností je internal.
Jediným mně známým řešením je proto deklarovat ve ViewModelu property Age jako string a provádět konverzi až tam. Když se konverze povede, zapíšete property do Modelu, kde už je typu int a kde se provede business validace. Je to víc práce ale zase má ViewModel informaci o tom, jestli je formulář validní. Implementace je popsaná v článku Using a ViewModel to Provide Meaningful Validation Error Messages.
Aby to nebylo tak lehké, představte si že chcete z ViewModelu vrátit hlášku "Věk musí být mezi {0} a {1}". Obstarožní interface IDataErrorInfo umožňuje vracet pouze string, takže ve ViewModelu provedeme String.Format a vrátíme už hotový text. Jenže to komplikuje lokalizaci. Kvůli přepnutí jazyka za běhu bychom potřebovali vracet klíč do resourců a pole parametrů, aby lokalizátor mohl aktualizovat hlášku. Ideální by tedy bylo napsat si vlastní interface, lepší a hezčí než IDataErrorInfo (to by věru nebylo těžké), protože do ValidationError objektu můžeme ukládat daleko více informací než jen string. Pomocí Reflectoru kolega Miro zjistil, že Binding při nastavení ValidatesOnDataErrors=true vkládá do pole validátorů objekt DataErrorValidationRule. Kdybychom tedy napsali vlastní ValidationRule, mohli bychom přečíst errory pomocí vlastního interface a vytvořit takový ValidationError objekt, který by byl lokalizátor schopen za běhu překládat. Jenže opět narážíme na to, že property BindingExpression.ItemSource, která obsahuje zdroj data bindingu (ViewModel), je internal! Zbývá nám tedy buď oželit okamžitou lokalizaci validačních hlášek, přinutit všechny BindingExpression objekty provést refresh, nebo si do stringu serializovat template s parametry a v lokalizátoru je deserializovat, vše mi přijde ošklivé.
Undo/Redo
WPF má sice vestavěnou podporu pro undo/redo v TextBoxu, ale to nám samozřejmě nestačí, potřebujeme undo/redo v celé aplikaci (nebo lépe, v celém editovaném projektu, který tvoří undo scope - projektů můžeme mít otevřených víc naráz). Zde se nabízí klasické řešení pomocí UndoItem objektu a undo a redo stacku, popsané třeba zde. Je ovšem nutné vyřešit otázku jak nalézt undo scope (projekt), když naše ViewModel objekty tvoří košatě rozvětvený strom.
Také musíme implementovat undo transakce. Kvůli tomu, aby bylo uživatelské rozhraní živější, jsme totiž ve všech Binding deklaracích nastavili UpdateSourceTrigger=PropertyChanged. Díky tomu je uživatelův vstup okamžitě validován, ale protože se přes ViewModel posílá každý jednotlivý znak který uživatel zadá do TextBoxu, bylo by undo dost nepoužitelné. Potřebujeme tedy zahájit undo transakci při vstupu do TextBoxu a ukončit ji při jeho opuštění (nebo stisku enter). To nás nejen odsuzuje k handlování událostí nebo vlastnímu TextBoxu, ale má to i jeden háček: Při kliknutí myší do menu nebo na toolbar TextBox neztratí focus. Tím pádem se při Save/Load neukončí undo transakce a nezahájí se nová, na což je potřeba myslet a modelovat root undo scope (projekt) tak, aby ho bylo možné při Load celý zahodit a vytvořit nový (i pak si ale TextBox drží focus a nezahájí novou transakci).
Závěr
Jak je vidět, komplexitu dobré aplikace není radno podceňovat ani s tak vyspělým frameworkem, jako je WPF. Pokud narazíte na další problémy nebo na jiná řešení, dejte vědět.
Architektura Ginger
| 2 comments |
Ginger je náš framework pro webové aplikace. Tvoří ho knihovny s infrastrukturním kódem a sada doporučení (nebo spíš přikázání:-))), jak rozdělit aplikaci na vrstvy a které projekty umístit do které vrstvy. Je určen pro webovou vícevrstvou škálovatelnou aplikaci, která ukládá data do databáze.
Trochu teorie kolem DSL
| 1 comments | DSL Tools
Doufám, že vás v mém posledním postu moc nevystrašilo slovní spojení "Domain-Specific Language". Je to jen další buzzword: zní to sofistikovaně, ale ve skutečnosti to není nic nového. Laskavý čtenář, kterému rostou víc vousy než vlasy, si možná vzpomene na minijazyky v unixu, což není nic jiného než DSL - malý jazyk vymyšlený pro konkrétní účel.
Model Driven Development v praxi
| 3 comments | DSL Tools
Kolem modelování v software už byla napsána a řečena spousta vznešených slov (třeba zde). Podívejme se proto na jednoduchý způsob, jak ho implementovat v praxi.
O čem bych chtěl psát ale nemám na to čas
| 0 comments |
Od mého posledního ublognutí uplynulo mnoho LOC. Není to tím že bych neměl o čem psát, ale nějak se mi nedostává času. Tak alespoň ve stručnosti, na čem pracuju a o čem bych si v budoucnu chtěl ublognout:
- Codename Ginger: Aplikační framework pro tvorbu distribuovaných (nejen) webových aplikací. Řeší architektonický základ takové aplikace: rozdělení do vrstev a vrstev (v češtině se dost špatně rozlišuje layer a tier), jazyk pro modelování domény vytvořený pomocí DSL Tools, generování různých artefaktů jako skriptů pro vytvoření databáze, mapovacích souborů, doménových a DTO objektů přímo z modelu pomocí T4. Není to žádná chiméra, máme reálně fungující a solidně protestovanou verzi a vyvíjíme v tom komerční aplikace. Na webové vrstvě používáme ASP.NET MVC, na datové NHibernate a trochu jsme to okořenili Spring.Net (ale jen s citem). Velkou inspirací pro nás je NServiceBus a pak samozřejmě bible enterprise aplikací Patterns of EAA od Martina Fowlera.
- WPF: Celkem dlouho jsem tuto technologii ignoroval, protože jsem někde četl že v ní není DataGrid. Hrozná chyba! Příliš mnoho času jsem strávil ve Windows Forms, takže jsem si nedokázal představit, jak flexibilní může být UI framework. Teď si to vynahrazuju. Jsem nadšen ze stylování, data bindingu a content modelu. Kromě toho, že v tom nejdou kloudně zobrazovat bitmapy, je to naprosté programátorské blaho.
- Scrum: Snažím se v práci prosadit, abychom v příští verzi našeho produktu nasadili tuto metodologii. Máme trochu problém s plánováním, termíny a komunikací, a od Scrumu si slibuju, že budeme mít přesnější představu jak na tom jsme, zpřesníme plánování, díky projektovým tymům usnadníme komunikaci, vývojáři se budou moct lépe soustředit na výsledek a díky tomu také zvedneme kvalitu našeho kódu. Nehledě na to, že nás to bude víc bavit:-) Teorie je na webu dost, ale našel jsem super knížku, která se věnuje praktické realizaci. Je zdarma, tak neváhejte a stahujte, je opravdu dobrá. Doufám že to vyjde a že budu moct časem ublognout jak nám to jde.
Tak to je ve zkratce všechno, mám v hlavě sice daleko víc nápadů, ale den má jen 24 hodin:-)
Jak programovat bez ega
| 5 comments |
Na rozdíl od spisovatelů jsou však programátoři nuceni pracovat v týmech. Mají tak problémy, kteří spisovatelé vůbec neznají. Některé jsou technického rázu a jdou celkem uspokojivě vyřešit, např. jak spojovat kusy napsané různými autory do jednoho celku (VCS). Horší vznikají tím, že programátoři jsou lidi. Lidská interakce je nesmírně složitá a ke strojové přesnosti a neutrálnosti má na hony daleko. Představte si to, kvůli mezilidským vztahům dokonce vzniklo několik vědních oborů (sociologie, psychologie, psychiatrie, politologie, ekonomie atd.)! Manažeři programátorů se navíc často domnívají, že se pohybují ve výhradně technické oblasti, a tak mohou problémy druhého typu v klidu nepovšimnuty bujet a stávat se patologickými. Ale to je jiná kapitola.
Dnes se chci věnovat jedné vlastnosti, kterou mají programátoři se spisovateli společnou. Každý autor, ať už píše cokoliv, se se svým dílkem ztotožňuje. Je to naprosto přirozené: Trávíte s ním spoustu času, stojí vás mnoho úsilí a chcete aby se mu dařilo co nejlépe. Když pak přijde kritika, ať už oprávněná nebo ne, je těžké ji přijmout s chladnou hlavou. U spisovatelů to vede k úsměvným historkám ve společenských časopisech, u programátorů k frustraci a nepřátelství. A protože se programátoři potkávají v práci každý den, je to pro ně daleko horší problém než pro spisovatele. Pak je ale těžké napsat dobrý program.
Jak tedy programovat bez ega? V první řadě musí člověk přijmout fakt, že se může mýlit. Vždy se najde někdo, kdo o daném problému ví víc než vy. Zvlášť když strávíte se svým produktem delší dobu, je těžké najít odstup a snadno pak přehlédnete i očividné chyby. Pravdu naopak mohou mít i lidé, od nichž by to člověk vůbec nečekal. A tak nezbývá než věnovat pozornost každé výtce, ať už pochází z jakéhokoliv zdroje.
A opačně, pokud kritizujeme, snažme se nedotknout se osobnosti autora kódu. Kritizujte kód, ne jeho autora. Snažte se navrhovat, jakým způsobem lze kód vylepšit. Pokud je to možné, opřete se o fakta (standardy, měření, literatura, články na webu, dohodnuté konvence atd.). Destruktivní kritika typu "seš snad úplně blbej" nebo "všechno stojí za hovno" nikam nevede, jen šíří pocity zoufalství. Zkuste odhadnout, kolik toho ten druhý "skousne" a buďte hodní na kolegy, kteří nemají takové sebevědomí. To, že má někdo méně zkušeností nebo znalostí neznamená, že je horší než vy. Navíc za rok může být situace klidně opačná. Pokud tým funguje, jeho členové jsou schopni se navzájem učit a mají ze spolupráce dobrý pocit.
Aby se programátoři nestyděli zeptat se kolegy o radu, musí v týmu panovat přesvědčení, že mýlit se je lidské a že víc hlav víc ví. Každý má občas špatný den a jediné co se s tím dá dělat, je umožnit, aby se na chyby přišlo co nejdříve. Dobrou pomůckou mohou být techniky z extrémního programování, jako párové programování, code review, kolektivní vlastnictví kódu a stand-up meetingy (také známé jako scrum). Mám ale obavu, že prvotní je dobrý výběr lidí; nehledět při náboru pouze na technické znalosti, ale i na to, zda je přijímaný člověk týmový hráč. Pokud máte tým složený ze samých "hyper-senzitivních code-machines", žádné metodologie vám asi nepomůžou.
Já sám osobně mám pocit, že už dokážu obstojně snášet kritiku kódu, který jsem napsal. Kritizovat kód kolegů mně ale stále nejde tak, jak bych si představoval. Je těžké vybrat správná slova, aby druhý pochopil, že ho nechci urazit ani snížit jeho zásluhy. Někdy mě zradí jazyk, někdy se moc rozohním, někdy toho mám prostě dost a někdy zafunguje ponorková nemoc, protože pracuju ve firmě, kde jsou trvalé týmy - roky sedíte v kanceláři se stejnými lidmi. Tímto se proto omlouvám každému, koho jsem kdy mohl urazit a chci aby jste věděli, že kašlu na to kdo je autorem, zajímá mě pouze kód a aby byl dobrý.
Ještě poznámka na závěr: Zajímavá je souvislost s jiným principem efektivního programování: Ukazuje se totiž, že programovat bez ega znamená napsat pouze tolik, kolik situace vyžaduje - ne méně a ne více. Nemá prostě cenu vymýšlet všechny varianty, které by po nás mohl uživatel teoreticky chtít, a potom napsat nějaké úžasně univerzální über-řešení; lepší je napsat program, který řeší pouze aktuální problém, a pokud bude potřeba, bude se průběžně doplňovat a zesložiťovat. Je to staré pravidlo YAGNI (You Ain't Gonna Need It), které jinými slovy říká, že i když jste bůhvíjak dobří programátoři, nesmíte se bát obyčejných jednoduchých řešení - není to ostuda.
Egoless Programming
Ten Commandments of Egoless Programming