Tomáš Herceg Microsoft Student Partner Microsoft Most Valuable Professional http://www.vbnet.cz
Neznalost, nepochopení základních principů používané technologie Neznalost vnitřního fungování používaných funkcí, neznalost užitých algoritmů Nepoužívání mozku při psaní kódu Nedostatek zkušeností, neznalost základních návrhových vzorů Absence smyslu pro pořádek a přehlednost Všechny demonstrované příklady jsou skutečné a ze života!
Špatně! // datov struktura pro uložení List<Dvojice> cisla = new List<Dvojice>(); struct Dvojice public string Klic get; set; public string Hodnota get; set; // najít hodnotu s daným klíčem for (int i = 0; i < cisla.count; i++) if (cisla[i].klic == i.tostring()) return cisla[i].hodnota;
Správně // datov struktura pro uložení Dictionary<int, string> cisla = new Dictionary<int, string>(); // najít hodnotu s daným klíčem return cisla[hledana]; Rychlejší (Dictionary je hashovací tabulka) Jednodušší (nemusíme definovat vlastní strukturu a psát si hledání podle klíče sami)
Špatně! // datov struktura Dictionary<string, bool> stringy = new Dictionary<string, bool>(); // přid ní stringu do seznamu stringy.add(retezec, true); // je string v seznamu? return stringy.containskey(retezec);
Správně // datov struktura HashSet<string> stringy = new HashSet<string>(); // přid ní stringu do seznamu stringy.add(retezec); // je string v seznamu return stringy.contains(retezec); Stejně rychlé (ale rychlejší než List) HashSet si pamatuje jen klíče, ne i zbytečné hodnoty HashSet umí navíc i množinové operace
Špatně! // copak tento kód asi děl? List<int> tmp = new List<int>(); for (int i = 0; i < pole.length; i++) tmp.insert(0, pole[i]); pole = tmp.toarray();
Správně // otočit pole Array.Reverse(pole); Původní pole stejně zahazujeme, nové je ale stejně velké Nevytváříme nový List a nové pole
Špatně! // projdeme všechny prvky pole a // pro každý se podív me, jestli // v poli není nějaký větší for (int i = 0; i < pole.length; i++) bool existujevetsi = false; for (int j = 0; j < pole.length; j++) if (pole[j] > pole[i]) existujevetsi = true; // pokud větší číslo než toto neexistuje, // m me maximum if (!existujevetsi) return pole[i];
Správně // najít maximum return pole.max(); Je zbytečné hledat maximum v O(N 2 ), jde to v O(N) Navíc máme extension metodu Max
// zjistit velikost souboru v bajtech string filename = "c:\\soubor.txt"; return System.IO.File.ReadAllBytes(filename).Length; Špatně!
Správně // zjistit velikost souboru v bajtech string filename = "c:\\soubor.txt"; var info = new FileInfo(filename); return info.length; Je zbytečné kvůli zjištění velikosti číst celý soubor, který navíc může mít stovky MB! Pomocí FileInfo získáme i další informace o souboru!
Špatně! // skl d ní cesty string basepath = "C:\\data"; string filename = "files\\soubor.txt"; string fullpath = basepath.endswith("\\")? basepath : basepath + "\\"; fullpath += filename;
Správně string fullpath = System.IO.Path.Combine( "C:\\data", "files\\soubor.txt" ); Pro skládání cest máme funkci, proč ji nepoužít?
if ((retezec == null) (retezec == "")) //... Špatně!
Správně if (string.isnullorempty(retezec)) //... Pro tento účel máme funkci, proč ji nepoužít? Místo je lepší použít String.Empty.
Dim a As Boolean = "True" Dim d As Double = "15.6" Dim c = "4" Špatně!
Správně Dim a As Boolean = True Dim b As Single = Math.Sqrt(15.6) Automatické konverze využíváme, ale nezneužíváme! Mnohdy nám ušetří oproti C# přetypování.
string xml = @"<root><child>hello</child></root>"; var match = Regex.Match(xml, "<child>([^<]*)</child>"); string childvalue = match.groups[1].value; Špatně!
Správně string xml = @"<root><child>hello</child></root>"; var childs = XElement.Parse(xml).Descendants("child"); string childvalue = childs.first().value; Proč psát složité regexpy, když máme LINQ2XML? Regexpy se špatně luští, používat opatrně! Co když v XML bude komentář, CDATA sekce atd.?
Špatně! try object i = GetOurObject(); i.method(15); catch (NullReferenceException) // v pohodě, v objektu nic nebylo catch (Exception) MessageBox.Show("Nastala nezn m chyba.");
Správně try object i = GetOurObject(); if (i!= null) i.method(15); catch (Exception) MessageBox.Show("Nastala nezn m chyba."); Výjimky obecně jsou pomalé! Používat jen v opravdu výjimečných situacích. Ošetření hodnoty null podmínkou je asi 10000x rychlejší!
private static object lazyobject = null; /// <summary> /// Objekt, který se při prvním použití zinicializuje /// </summary> public static object LazyObject get if (lazyobject == null) lock (lockobject) lazyobject = Initialize(); return lazyobject; Špatně!
private static object lazyobject = null; /// <summary> /// Objekt, který se při prvním použití zinicializuje /// </summary> public static object LazyObject get lock (lockobject) if (lazyobject == null) lazyobject = Initialize(); return lazyobject; Špatně!
Správně private static object lazyobject = null; public static object LazyObject get if (lazyobject == null) lock (lockobject) if (lazyobject == null) lazyobject = Initialize(); return lazyobject; Není vhodné pokaždé lockovat, lock je pomalý! Bude fungovat korektně, inicializace se provede jednou.
Špatně! <script runat="server"> Protected Sub Button1_Click(ByVal sender...) If String.IsNullOrEmpty(TextBox1.Text) Then MsgBox("Musíte zadat hodnotu!") End If End Sub </script>... <asp:textbox ID="TextBox1" runat="server" /> <asp:button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />...
Správně If String.IsNullOrEmpty(TextBox1.Text) Then Dim script = "alert('musíte zadat hodnotu!');" Page.ClientScript.RegisterClientScriptBlock( _ Me.GetType(), "alert", script, True) End If Obsluhy událostí probíhají na serveru, ne v prohlížeči!!! Aby se hláška zobrazila v prohlížeči, je nutné použít javascript, konkrétně jeho metodu alert!
/// <summary> /// Ověří spr vnost form tu data /// </summary> public bool IsCorrectDate(string date) return Regex.IsMatch(date, @"^[0-9]1,2\.[0-9]1,2\.[0-9]4$"); Špatně!
Správně /// <summary> /// Ověří spr vnost form tu data /// </summary> public bool IsCorrectDate(string date) DateTime datevalue; return DateTime.TryParse(date, out datevalue); Regexpem projde i 35.16.9547, pokud je hloupý. Pro parsování a práci s daty používáme třídu DateTime! Pokud lpíme na přesném formátu, máme TryParseExact.
string text = string.empty; int i = 0; foreach (var line in GetLines()) text += "Ř dek " + (i++) + ": " + line; Špatně!
Správně StringBuilder sb = new StringBuilder(); int i = 0; foreach (var line in GetLines()) sb.appendformat("ř dek 0: 1", i++, line); sb.appendline(); Slučování stringů je pomalé, vše se kopíruje! Lepší než spojování fragmentů je použití formátování! StringBuilder je na skládání dlouhých textů určen!
/// <summary> ///A test for Main ///</summary> [TestMethod()] [DeploymentItem("EngineApplication.exe")] public void CalculateTest() int expected = 15; int actual = MyClass.Calculate(14, 16, 8); Assert.AreEqual<int>(expected, 15); Špatně!
Správně /// <summary> ///A test for Main ///</summary> [TestMethod()] [DeploymentItem("EngineApplication.exe")] public void CalculateTest() int expected = 15; int actual = MyClass.Calculate(14, 16, 8); Assert.AreEqual<int>(expected, actual); Pozor na hloupé překlepy, aby byl test k něčemu! Je potřeba porovnávat actual a expected!
public int[] Calculate(int a, int b) return new int[] a + b, a - b, a * b, a / b ; Špatně!
Správně public CalculateResult Calculate(int a, int b) return new CalculateResult() Added = a + b, Subtracted = a - b, Multiplied = a * b, Divided = a / b ; Při vracení více hodnot různého charakteru používejte strukturu, aby bylo jasné, co která hodnota znamená. Není vhodné ani z metod vracet Tuple, hodnoty nejsou pojmenované!
$in = $in.replace('á',' ') $in = $in.replace('á','á') $in = $in.replace('à','') $in = $in.replace('à','à') $in = $in.replace('â','') $in = $in.replace('â','â') $in = $in.replace('å','å') $in = $in.replace('å','å') $in = $in.replace('ã','~') $in = $in.replace('ã','ã') $in = $in.replace('ä','') $in = $in.replace('ä','ä')... Špatně!
Správně $in = [System.Web.HttpUtility]::HtmlDecode($in) Entit je obrovské množství, některé mají více variant! Je třeba je nahrazovat ve správném pořadí! má zobrazit text
SELECT * FROM [t] WHERE [t].[number] IN (SELECT TOP 4 [Number] FROM [t] WHERE [CategoryId] = [t].[categoryid] ORDER BY [Number] ) ORDER BY [t].[categoryid], [t].[number] Špatně!
Správně SELECT [t].[categoryid], [t].[number] FROM (SELECT ROW_NUMBER() OVER (PARTITION BY [CategoryId] ORDER BY [Number]) AS [RowNumber], [CategoryId], [Number] FROM @t) [t] WHERE [t].[rownumber] <= 4 Subselect se spouští pro každý řádek neefektivní! Ranking functions umí očíslovat řádky dle nějakého pořadí, pomocí PARTITION BY se číslování dělá v rámci skupin.
Špatně! // počet je nula int count = 0; // projít všechna čísla od 1 do n včetně for (int i = 1; i <= n; i++) // pokud je n dělitelné i if (n % i == 0) // přičíst k počtu jedničku count++;
Správně // zjistit počet čísel, kterými je dělitelné n int count = 0; for (int i = 1; i <= n; i++) if (n % i == 0) count++; Komentářů by nemělo být moc, ani málo Komentáře by měly obsahovat to, co z kódu není na první pohled patrné; jinak jen duplikují informaci v kódu
Špatně! // pole před v me referencí, aby se zbytečně nekopírovalo private int SectiPole(ref int[] pole) int soucet = 0; for (int i = 0; i < pole.length; i++) soucet += pole[i]; return soucet;
Správně // před v ní referencí je zbytečné, pole se nekopíruje private int SectiPole(int[] pole) int soucet = 0; for (int i = 0; i < pole.length; i++) soucet += pole[i]; return soucet; Pole, objekty a vůbec všechny referenční typy sídlí na haldě a v proměnných se uchovávají jen reference. Předáním proměnné do metody nebo přiřazením se kopíruje hodnota proměnné (reference), ne objekt na haldě.
public List<int> Filtruj(List<int> seznam) // vybrat ze seznamu seznam prvky větší než 10 List<int> vetsinez10 = new List<int>(); for (int i = 0; i < seznam.count; i++) if (seznam[i] > 10) vetsinez10.add(seznam[i]); return vetsinez10; Špatně!
Správně // vybrat ze seznamu seznam prvky větší než 10 List<int> vetsinez10 = seznam.where(i => i > 10).ToList(); Linq přinesl mnoho velmi užitečných metod, jak pracovat s kolekcemi a seznamy. Můžeme filtrovat, třídit, seskupovat, vytvářet projekce atd. Where funguje pomocí konstrukce yield return, kolekce se nemusí ukládat celá do paměti.
public List<int> DruheMocniny(List<int> seznam) // spočítat druhé mocniny prvků v seznamu List<int> mocniny = new List<int>(seznam.Count); for (int i = 0; i < seznam.count; i++) mocniny.add(seznam[i] * seznam[i]); return mocniny; Špatně!
Správně // spočítat druhé mocniny prvků v seznamu List<int> mocniny = seznam.select(i => i * i).tolist(); Select převede IEnumerable<A> na IEnumerable<B> s možností definice vlastní funkce převodu A -> B. Typy A i B mohou být klidně stejné.
public int? Prvni(List<int> seznam) // najít první číslo větší než 10 for (int i = 0; i < seznam.count; i++) if (seznam[i] > 10) return seznam[i]; return null; Špatně!
Správně List<int> sez = new List<int>(); int p1 = sez.firstordefault(i => i > 10); int? p2 = sez.cast<int?>().firstordefault(i => i > 10); FirstOrDefault vrátí první nalezenou vyhovující hodnotu nebo výchozí hodnotu datového typu. First vrátí první vyhovující hodnotu nebo vyhodí výjimku Single vyhodí výjimku, pokud vyhovující není právě jedna.
public bool Existuje(List<int> seznam) // zjistit, jestli existuje číslo větší než 10 for (int i = 0; i < seznam.count; i++) if (seznam[i] > 10) return true; return false; Špatně!
Správně bool ex = sez.any(i => i > 10); Any vrátí True, pokud nějaká hodnota vyhovuje podmínce. All vrátí True, pokud vyhovují všechny hodnoty v kolekci. Count vrátí počet hodnot, které podmínce vyhovují.
Špatně! public class Zamestnanec public virtual void Vizitka() Console.WriteLine("Jméno, příjmení"); public class Uklizecka : Zamestnanec public override void Vizitka() Console.WriteLine("Jméno, příjmení"); Console.WriteLine("Dělka koštěte, objem kýblu");
Správně public override void Vizitka() base.vizitka(); Console.WriteLine("Dělka koštěte, objem kýblu"); Když něco používáme, je vhodné znát to celé. Snažíme se zbavit se opakujícího se kódu, i když to někdy dá trochu víc práce.
Špatně! Dim a() As Integer '... If a IsNot Nothing Then If a.length >= 3 Then ' pr ce s polem End If End If 'If a IsNot Nothing And a.length >= 3 Then nefunguje
Správně If a IsNot Nothing AndAlso a.length >= 3 Then ' pr ce s polem End If And a Or ve Visual Basicu dělají normální bitové operace. AndAlso a OrElse dělají zkrácené vyhodnocování. V C#: &... And,... Or, &&... AndAlso,... OrElse
Špatně! public class Employee public TaskCollection Tasks get; set; public Employee() Tasks = new TaskCollection(); Tasks.OnTaskAdded +=...... Employee e = new Employee(); e.tasks = new TaskCollection();
Správně public TaskCollection Tasks get; private set; Setter se dá i u automatické property udělat private. Často není vhodné publikovat ven celou kolekci, ale třeba jen IEnumerable<T>.
public object getvybranaitem() int Index = getindexpolozky();... Špatně!
Správně public object GetSelectedItem() int index = GetItemIndex();... Kombinace angličtiny a češtiny v jednom názvu vypadá divně, navíc spolu s nekonzistencí (item vs polozka). V jistých specifických případech to jinak nejde... Je vhodné dodržovat konvence pojmenovávání http://msdn.microsoft.com/en-us/library/ms229002.aspx
Špatně! public class Test List<int> items; int selectedindex; public int GetSelectedItem() return items[selectedindex]; public int FirstPositiveValue get return items.first(i => i > 0);...
Správně // víceméně atomick operace => vlastnost public int SelectedItem get return items[selectedindex]; // prohled ní seznamu může chvíli trvat => metoda public int GetFirstPositiveValue() return items.first(i => i > 0); Vlastnost má mít naprosto jednoduchou logiku, většinou po ní chceme jen vrátit hodnotu. Při volání metody se předpokládá složitější operace.
Špatně!
Špatně! public bool ValidateUser(string user, string pass) bool isvalid = false; // připojit se k DB a ověřit uživatele using (var con = new SqlConnection(ConnectionString)) var sql = "SELECT COUNT(*) FROM [Users] " + "WHERE [User] = '" + user + "' " + "AND [Pass] = '" + pass + "'"; using (var com = new SqlCommand(sql, con)) con.open(); isvalid = (com.executescalar() > 0); con.close(); return isvalid;
Správně var sql = "SELECT COUNT(*) FROM [Users] " + "WHERE [User] = @User AND [Pass] = @Pass"; using (var com = new SqlCommand(sql, con)) // použitím parametrů se zbavíme potíží com.parameters.addwithvalue("user", user); com.parameters.addwithvalue("pass", pass); con.open(); isvalid = (com.executescalar() == 1); con.close(); Hodnoty vkládané do SQL se musí zaescapovat!!! Lepší je striktně všude používat parametry, nezapomenete.
public long MagicFn(int n, int k) int c = j = 1; for (; k > 0; c *= n--, j *= k--) ; return c / j; Špatně!
public long KombinacniCislo(int n, int k) int citatel = jmenovatel = 1; for (int i = 0; i < k; i++) citatel *= n - i; jmenovatel *= k - i; return citatel / jmenovatel; Správně
Databáze Tabulky bez primárních klíčů Tabulky s primárními klíči typu VARCHAR Chybějící vazby mezi tabulkami Vazby mezi tabulkami na sloupcích VARCHAR Nepoužívání transakcí tam, kde mají být Subselecty, které se spouští pro každý řádek Neznalost JOINu Nenormalizovaná schémata bez opodstatnění Někdy nutné kvůli výkonu, ušetří se tím JOINy Indexy tam, kde nemají být Chybějící indexy tam, kde mají být
Aplikace Neoddělování vrstev Nekonzistence formátování kódu Nekonzistence názvů proměnných Opakující se kód Dotazy v aplikaci místo pohledů a procedur v databázi Někdy to má své opodstatnění Vlastní skiny a vzhled na úkor funkčnosti a ergonomie aplikace Používání angličtiny se zásadními chybami Nepoužívání XML komentářů (a komentářů obecně) Commitování nezkompilovatelného kódu
Kurzy zaměřené na vývoj software a administraci systémů únor květen 2010 FEL ČVUT, Dejvice Předregistrace sleva 5% na studentské kurzovné www.csp.cvut.cz/msita Kontakt msita@csp.cvut.cz Visual Studio 2008 Základy programování Práce s daty ASP.NET Windows Aplikace SharePoint Services 3.0 Windows Server 2008 Základy operačních systémů Struktura a návrh síťových služeb Rozšířené služby a role Bezpečnost
2008 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.