it-swarm-eu.dev

Jsou nulové odkazy opravdu špatné?

Slyšel jsem, že je řečeno, že zahrnutí nulových referencí do programovacích jazyků je „miliardová chyba dolaru“. Ale proč? Jistě, mohou způsobit výjimky NullReferenceException, ale co? Při nesprávném použití může být zdrojem chyb jakýkoli prvek jazyka.

A jaká je alternativa? Předpokládám, že místo toho říkám:

Customer c = Customer.GetByLastName("Goodman"); // returns null if not found
if (c != null)
{
    Console.WriteLine(c.FirstName + " " + c.LastName + " is awesome!");
}
else { Console.WriteLine("There was no customer named Goodman.  How lame!"); }

Dalo by se to říct:

if (Customer.ExistsWithLastName("Goodman"))
{
    Customer c = Customer.GetByLastName("Goodman") // throws error if not found
    Console.WriteLine(c.FirstName + " " + c.LastName + " is awesome!"); 
}
else { Console.WriteLine("There was no customer named Goodman.  How lame!"); }

Ale jak je to lepší? V každém případě, pokud zapomenete ověřit, že zákazník existuje, získáte výjimku.

Předpokládám, že CustomerNotFoundException je trochu snazší ladit než NullReferenceException, protože je popisnější. Je to všechno?

165
Tim Goodman

null je zlé

Na InfoQ je prezentace na toto téma: Null Reference: The Billion Dollar Mistake by Tony Hoare

Typ volby

Alternativou k funkčnímu programování je použití Typ volby , který může obsahovat SOME value nebo NONE.

Dobrý článek Vzor „Option“, který diskutuje typ možnosti a poskytuje jeho implementaci pro Javu.

Našel jsem také hlášení o chybě Java o tomto problému: Přidat pěkné typy možností do Java, aby se zabránilo NullPointerExceptions . požadovaná funkce byl představen v Java 8.

93
Jonas

Problém je v tom, že protože teoreticky může být jakýkoli objekt nulový a při pokusu o jeho použití hodí výjimku, váš objektově orientovaný kód je v podstatě kolekce nevybuchlých bomb.

Máte pravdu, že půvabné zpracování chyb může být funkčně totožné s příkazy if s kontrolou nuly. Ale co se stane, když něco, co jste sami přesvědčili, nemohlo možná být null je ve skutečnosti null? Kerboom. Ať se stane cokoli, jsem ochoten vsadit, že 1) nebude to půvabné a 2) se vám nebude líbit.

A neodmítněte hodnotu „snadné ladění“. Starší výrobní kód je šílený, rozlehlý tvor; vše, co vám dává lepší přehled o tom, co se pokazilo a kde vám může ušetřit hodiny kopání.

129
BlairHippo

Existuje několik problémů s použitím nulové odkazy v kódu.

Nejprve se obvykle používá k označení zvláštního stavu . Spíše než definování nové třídy nebo konstanty pro každý stav, protože specializace se normálně provádějí, použití nulové reference používá ztrátovou ztrátu, masivně zobecněný typ/hodnotu .

Zadruhé, ladicí kód se stává obtížnějším, když se objeví nulová reference a vy se pokusíte zjistit, co ho vygenerovalo , který stav je ve skutečnosti a jeho příčina, i když můžete sledovat jeho upstream exekuční cestu .

Zatřetí, nulové odkazy zavádějí další cesty kódu pro testování .

Začtvrté, jakmile jsou nulové reference použity jako platné stavy pro parametry a návratové hodnoty, defenzivní programování (pro stavy způsobené návrhem) vyžaduje více nulových kontrol referencí, které mají být provedeny na různých místech … Jen pro případ.

Za páté, runtime jazyka již provádí kontrolu typu , když provádí vyhledávání selektoru v tabulce metod objektu. Snažíte se tedy duplikovat úsilí tím, že zkontrolujete, zda je typ objektu platný/neplatný, a poté necháte běhový modul zkontrolovat platný typ objektu a vyvolá jeho metodu.

Proč nepoužít vzor NullObject na využít kontrolu runtime k vyvolání NOP metody specifické pro tento stav (v souladu s rozhraním normálního stavu) a zároveň vylučují všechny další kontroly nulových odkazů v celé vaší kódové základně?

vyžaduje více práce vytvořením třídy NullObject pro každé rozhraní, se kterým chcete reprezentovat zvláštní stav. Ale alespoň specializace je izolovaná pro každý zvláštní stav, spíše než kód, ve kterém by se mohl stát vyskytovat. IOW, počet testů je snížen, protože máte méně alternativních cest provádění ve svých metodách.

50
Huperniketes

Null nejsou tak špatní, pokud je neočekáváte. Musíte měli byste v kódu výslovně určit, že očekáváte null, což je problém s návrhem jazyka. Zvaž toto:

Customer? c = Customer.GetByLastName("Goodman");
// note the question mark -- 'c' is either a Customer or null
if (c != null)
{
    // c is not null, therefore its type in this block is
    // now 'Customer' instead of 'Customer?'
    Console.WriteLine(c.FirstName + " " + c.LastName + " is awesome!");
}
else { Console.WriteLine("There was no customer named Goodman.  How lame!"); }

Pokud se pokusíte vyvolat metody na Customer?, měli byste dostat chybu kompilace. Důvod, proč to více jazyků neučiní (IMO), je ten, že nezajišťují změnu typu proměnné v závislosti na tom, v jakém rozsahu je. Pokud to jazyk dokáže zvládnout, problém lze vyřešit zcela v rámci typ systému.

Existuje také funkční způsob, jak tento problém vyřešit, pomocí typů variant a Maybe, ale nejsem tak dobře obeznámen. Tímto způsobem dávám přednost, protože správný kód by měl teoreticky potřebovat pouze jeden znak, aby byl správně kompilován.

Existuje spousta vynikajících odpovědí, které pokrývají nešťastné příznaky null, takže bych rád představil alternativní argument: Null je chyba v typovém systému.

Účelem systému typu je zajistit, aby různé součásti programu „správně zapadaly“; dobře napsaný program nemůže „z Rails“ do nedefinovaného chování.

Vezměme si hypotetický dialekt Java nebo jakýkoli preferovaný staticky psaný jazyk, kde můžete řetězec "Hello, world!" Přiřadit libovolné proměnné jakéhokoli typu:

Foo foo1 = new Foo();  // Legal
Foo foo2 = "Hello, world!"; // Also legal
Foo foo3 = "Bonjour!"; // Not legal - only "Hello, world!" is allowed

A můžete zkontrolovat proměnné takto:

if (foo1 != "Hello, world!") {
    bar(foo1);
} else {
    baz();
}

Na tom není nic nemožného - někdo by mohl takový jazyk navrhnout, kdyby chtěl. Zvláštní hodnota nemusí být "Hello, world!" - mohlo to být číslo 42, Tuple (1, 4, 9) Nebo, řekněme, null. Ale proč byste to dělali? Proměnná typu Foo by měla obsahovat pouze Foos - to je celý bod systému typu! null není Foo o nic víc než "Hello, world!" je. Horší je, že null není hodnota jakéhokoli typu, a není s tím nic společného!

Programátor si nikdy nemůže být jistý, že proměnná skutečně obsahuje Foo, a ani program nemůže; Aby se předešlo nedefinovanému chování, musí před použitím proměnných Foos zkontrolovat proměnné pro "Hello, world!". Všimněte si, že provedení kontroly řetězce v předchozím fragmentu nešíří skutečnost, že foo1 je opravdu Foo - bar bude pravděpodobně mít také vlastní kontrolu, jen aby byla bezpečná.

Porovnejte to s použitím typu Maybe/Option s přizpůsobením vzoru:

case maybeFoo of
 |  Just foo => bar(foo)
 |  Nothing => baz()

V klauzuli Just foo Vy i program víte, že naše proměnná Maybe Foo Skutečně obsahuje hodnotu Foo - tyto informace jsou šířeny po řetězci hovorů a bar nemusí provádět žádné kontroly. Protože Maybe Foo Je odlišný typ od Foo, jste nuceni zvládnout možnost, že by mohl obsahovat Nothing, takže nikdy nemůžete zavřít pomocí NullPointerException. O svém programu můžete mnohem snadněji uvažovat a kompilátor může vynechat nulové kontroly s vědomím, že všechny proměnné typu Foo skutečně obsahují Foos. Každý vyhraje.

20
Doval

Ukazatel null je nástroj

ne nepřítel. Prostě byste je měli používat správně.

Přemýšlejte jen minutu o tom, jak dlouho trvá nalezení a oprava typické chyby neplatný ukazatel ve srovnání s lokalizací a opravou chyby nulového ukazatele. Je snadné zkontrolovat ukazatel proti null. Je to PITA, aby ověřil, zda nenulový ukazatel ukazuje na platná data.

Pokud stále nejste přesvědčeni, přidejte do svého scénáře dobrou dávku multithreadingu a pak znovu promyslete.

Morálka příběhu: Nevyhazujte děti vodou. A neobviňujte nástroje z nehody. Muž, který vynalezl číslo nula dávno, byl docela chytrý, od toho dne byste mohli pojmenovat „nic“. Ukazatel null není od toho tak daleko.


EDIT: Ačkoli se zdá, že vzor NullObject je lepším řešením než odkazy, které mohou být nulové, ale sám o sobě představuje problémy:

  • Odkaz, který drží NullObject, by (podle teorie) neměl při vyvolání metody nic dělat. Jemné chyby tak mohou být způsobeny chybně nepřidělenými odkazy, které jsou nyní zaručeny jako null (yehaa!), Ale provádějí nežádoucí akci: nic. U NPE je téměř zřejmé, kde problém leží. S NullObject, který se chová nějak (ale špatně), představujeme riziko, že chyby budou detekovány (příliš) pozdě. Toto není náhodou podobné problému s neplatným ukazatelem a má podobné důsledky: Odkaz odkazuje na něco, co vypadá jako platná data, ale není, zavádí datové chyby a může být obtížné dohledat je. Upřímně řečeno, v těchto případech bych bez mrknutí upřednostňoval NPE, který selže okamžitě, nyní, před logickou/datovou chybou, která mě náhle zasáhne později po silnici. Vzpomínáte si na studii IBM o nákladech na chyby, které jsou funkcí, v jaké fázi jsou detekovány?

  • Představa, že nedělá nic, když je metoda vyvolána na NullObject, se nedrží, když je vyvolán getter nebo funkce, nebo když metoda vrací hodnoty přes out. Řekněme, že návratová hodnota je int a my se rozhodneme, že „nedělat nic“ znamená „návrat 0“. Ale jak si můžeme být jisti, že 0 je správné „nic“, aby se (ne) vrátilo? Koneckonců, NullObject by neměl dělat nic, ale když je požádán o hodnotu, musí nějakým způsobem reagovat. Selhání není možnost: Používáme NullObject, abychom zabránili NPE, a určitě nebudeme obchodovat proti jiné výjimce (není implementováno, děleno nula, ...), že? Jak tedy správně nic nevrátíte, když musíte něco vrátit?

Nemohu si pomoci, ale když se někdo pokusí aplikovat vzor NullObject na každý problém, vypadá to spíše jako pokus o opravu jedné chyby provedením další. Je to bezpochyby dobré a užitečné řešení v některých případech, ale rozhodně to není kouzelná kulka pro všechny případy.

15
JensG

(Házení klobouku do kruhu za starou otázku;)

Specifický problém s nulovou hodnotou je, že to narušuje statické psaní.

Pokud mám Thing t, Kompilátor může zaručit, že mohu zavolat t.doSomething(). NELZE t je za běhu null. Nyní jsou všechny sázky vypnuté. Kompilátor řekl, že to bylo v pořádku, ale zjistím mnohem později, že t ve skutečnosti NENÍ doSomething(). Takže místo toho, aby kompilátor mohl důvěřovat, že zachytí chyby typu, musím čekat, až je runtime zachytí. Mohl bych také použít Python!

V jistém smyslu tedy null zavádí dynamické psaní do staticky typizovaného systému s očekávanými výsledky.

Rozdíl mezi tímto dělením nulou nebo logem negativu atd. Je ten, že když i = 0, je to stále int. Kompilátor může stále garantovat jeho typ. Problém je v tom, že logika nesprávně aplikuje tuto hodnotu způsobem, který logika nepovoluje ... ale pokud to logika udělá, je to do značné míry definice chyby.

(Kompilátor dokáže zachytit některé z těchto problémů, BTW. Stejně jako označení výrazů jako i = 1 / 0 V době kompilace. očekávejte, že kompilátor bude sledovat funkci a zajistit, aby všechny parametry byly v souladu s logikou funkce)

Praktickým problémem je, že děláte spoustu práce navíc a přidáváte nulové kontroly, abyste se za běhu chránili, ale co když na to zapomenete? Kompilátor vám přestane přiřazovat:

String s = new Integer (1234);

Proč by tedy mělo umožňovat přiřazení k hodnotě (null), která přeruší odkazy na s?

Smícháním „žádné hodnoty“ s „zadanými“ odkazy v kódu způsobíte programátorům další zátěž. A když dojde k výjimkám NullPointerExceptions, jejich sledování může být ještě časově náročnější. Spíše než se spoléhat na statické psaní na vyslovení „this is odkaz na něco, co se očekává,“ necháte jazyk říkat „this může být odkaz na něco, co se očekává. "

14
Rob

A jaká je alternativa?

Volitelné typy a přizpůsobení vzorů. Protože neznám C #, je zde kus kódu ve smyšleném jazyce Scala # :-)

Customer.GetByLastName("Goodman")    // returns Option[Customer]
match
{
    case Some(customer) =>
    Console.WriteLine(customer.FirstName + " " + customer.LastName + " is awesome!");

    case None =>
    Console.WriteLine("There was no customer named Goodman.  How lame!");
}
8
fredoverflow

Nulové odkazy jsou chybou, protože umožňují nesmyslový kód:

foo = null
foo.bar()

Existují alternativy, pokud využíváte typový systém:

Maybe<Foo> foo = null
foo.bar() // error{Maybe<Foo> does not have any bar method}

Obecně je myšlenka vložit proměnnou do pole a jediné, co můžete udělat, je rozbalit ji, nejlépe získat pomoc kompilátoru, jak je navrženo pro Eiffel.

Haskell to má od nuly (Maybe), v C++ můžete využít boost::optional<T> ale stále můžete získat nedefinované chování ...

8
Matthieu M.

Problém s nulovými hodnotami spočívá v tom, že jazyky, které jim umožňují, do velké míry nutí vás k programování defenzivně proti němu. To vyžaduje hodně úsilí (mnohem více než pokus o použití defenzivních if-bloků)

  1. objekty, které od nich očekáváte ne, budou ve skutečnosti nikdy nulové, a
  2. že vaše obranné mechanismy skutečně jednají se všemi potenciálními NPE efektivně.

Takže nulové hodnoty jsou skutečně nákladné.

6
luis.espinal

Problém, do jaké míry se váš programovací jazyk pokusí prokázat správnost programu před jeho spuštěním. Ve staticky psaném jazyce dokazujete, že máte správné typy. Přechodem na výchozí nullovací odkazy (s volitelnými nullovatelnými odkazy) můžete eliminovat mnoho případů, kdy je předán null a nemělo by to být. Otázkou je, zda zvláštní úsilí při nakládání s nullovatelnými odkazy stojí za to z hlediska správnosti programu.

4
Winston Ewert

Problém není tak null, je to, že v mnoha moderních jazycích nemůžete určit nenulový referenční typ.

Váš kód může například vypadat

public void MakeCake(Egg egg, Flour flour, Milk milk)
{
    if (Egg == null) { throw ... }
    if (flour == null) { throw ... }
    if (milk == null) { throw ... }

    Egg.Crack();
    MixingBowl.Mix(Egg, flour, milk);
    // etc
}

// inside Mixing bowl class
public void Mix(Egg egg, Flour flour, Milk milk)
{
    if (Egg == null) { throw ... }
    if (flour == null) { throw ... }
    if (milk == null) { throw ... }

    //... etc
}

Když se odkazy na třídy dostanou kolem, defenzivní programování vás vyzývá, abyste znovu zkontrolovali všechny parametry na null, i když jste je právě zkontrolovali na null přímo, zejména při vytváření testovaných opakovaně použitelných jednotek. Stejný odkaz by mohl být snadno zkontrolován 10krát napříč kódovací základnou!

Nebylo by lepší, kdybyste mohli mít normální nulovatelný typ, když dostanete věc, pak se vypořádat s nulovou hodnotou a pak ji předat jako nulovatelný typ všem vašim pomocným funkcím a třídám, aniž byste zkontrolovali nulovou hodnotu všech čas?

To je smysl řešení Option - nikoli umožnit zapnutí chybových stavů, ale povolit návrh funkcí, které implicitně nemohou akceptovat nulové argumenty. To, zda je „implicitní“ implementace typů nulovatelná nebo nullovatelná, je méně důležité než flexibilita dostupnosti obou nástrojů.

http://twistedoakstudios.com/blog/Post330_non-nullable-types-vs-c-fixing- the-billion-dollar-mistake

Toto je také uvedeno jako # 2 nejvíce hlasovaná funkce pro C # -> https://visualstudio.uservoice.com/forums/121579-visual-studio/category/30931-languages-c

4
Michael Parker

Nulová je zlá. Avšak nedostatek nuly může být větší zlo.

Problém je v tom, že ve skutečném světě máte často situaci, kdy nemáte data. Váš příklad verze bez null může stále vyhodit do povětří - buď jste udělali logickou chybu a zapomněli jste zkontrolovat Goodmana, nebo se možná Goodman oženil, když jste zkontrolovali, a když jste ji vyhledali. (Pomáhá při hodnocení logiky, pokud zjistíte, že Moriarty sleduje každý kousek vašeho kódu a pokouší se vás zakopnout.)

Co dělá vyhledávání Goodmana, když tam není? Bez nuly musíte vrátit nějaký výchozí zákazník - a nyní prodáváte věci tomuto výchozímu nastavení.

V zásadě jde o to, zda je důležitější, aby kód fungoval bez ohledu na to, zda funguje správně. Pokud je nesprávné chování lepší než žádné chování, pak nechcete nulové hodnoty. (Jako příklad, jak by to mohla být správná volba, zvažte první spuštění Ariane V. Neúspěšná chyba/0 způsobila, že raketa udělala tvrdý obrat a sebezničení vystřelilo, když se tím rozpadlo. Hodnota v okamžiku, kdy byl posilovač zapálen, se snažil vypočítat, že by už nesloužil žádnému účelu - i přes rutinní vracení odpadu by to udělalo oběžnou dráhu.)

Alespoň 99krát ze 100 bych se rozhodl použít nuly. Ale já bych skočil radostí na vědomí jejich vlastní verzi, ačkoli.

3
Loren Pechtel

Optimalizujte pro nejběžnější případ.

Nutnost neustále kontrolovat nulovou hodnotu je zdlouhavá - chcete mít možnost pouze zachytit objekt zákazníka a pracovat s ním.

V normálním případě by to mělo fungovat dobře - uděláte pohled, dostanete objekt a použijete ho.

V výjimečný případ, kde (náhodně) vyhledáváte zákazníka podle jména, aniž byste věděli, zda tento záznam/objekt existuje, budete potřebovat nějaký náznak, že se to nepodařilo. V této situaci je odpovědí zahodit výjimku RecordNotFound (nebo nechat poskytovatele SQL pod tím udělat za vás).

Pokud jste v situaci, kdy nevíte, zda můžete důvěřovat datům přicházejícím (parametr), například proto, že byla zadána uživatelem, můžete také zadat „TryGetCustomer (jméno, ze zákazníka)“ vzor. Křížový odkaz s int.Parse a int.TryParse.

1
JBRWilkinson

Výjimky nejsou eval!

Jsou tam z nějakého důvodu. Pokud váš kód běží špatně, existuje geniální vzorec nazvaný výjimka a říká vám, že něco není v pořádku.

Tím, že se vyhnete použití nulových objektů, skrýváte část těchto výjimek. Nejsem spike o příklad OP, kde převádí výjimku nulového ukazatele na dobře napsanou výjimku, to by ve skutečnosti mohlo být dobré, protože to zvyšuje čitelnost. Nicméně, jakmile vezmete řešení Type Option, jak zdůraznil @ Jonas, skrýváte výjimky.

Než ve vaší produkční aplikaci, namísto výjimky, která má být vyvolána, když kliknete na tlačítko pro výběr prázdné možnosti, nic se neděje. Namísto nulového ukazatele by byla vyvolána výjimka a pravděpodobně bychom dostali zprávu o této výjimce (jako v mnoha produkčních aplikacích máme takový mechanismus), a potom bychom ji mohli skutečně opravit.

Udělat si kód neprůstřelný tím, že se vyhnete výjimce, je špatný nápad, takže vás kód neprůstřelný opravou výjimky, dobře to je cesta, kterou bych si vybral.

0
Ilya Gazman

Ne.

Neschopnost jazyka účtovat zvláštní hodnotu, jako je null, je problémem jazyka. Pokud se podíváte na jazyky jako Kotlin nebo Swift , které nutí autora, aby se při každém setkání výslovně vypořádalo s nulovou hodnotou, pak nehrozí žádné nebezpečí

V jazycích, jako je ten, o který jde, jazyk umožňuje, aby null byla jakákoli-ish typu, ale neposkytuje žádné konstrukty pro potvrzení toho, že později, což vede k tomu, že věci jsou null neočekávaně (zejména když jsou předávány jinam), a tím pádem dojde k selhání. To je zlo: umožňuje vám použít null, aniž byste se s tím museli vypořádat.

0
Ben Leggiero

Nulls jsou problematické, protože je nutné je explicitně zkontrolovat, kompilátor vás však nemůže varovat, že jste je zapomněli zkontrolovat. To vám může říct jen časově náročná statická analýza. Naštěstí existuje několik dobrých alternativ.

Vyjměte proměnnou z rozsahu. Až příliš často se null používá jako držák místa, když programátor deklaruje proměnnou příliš brzy nebo ji udržuje příliš dlouho. Nejlepší přístup je jednoduše zbavit se proměnné. Neoznámte to, dokud nemáte platnou hodnotu, kterou tam můžete vložit. Toto není tak obtížné omezení, jak si možná myslíte, a váš kód je mnohem čistší.

Použijte vzor nulového objektu. Někdy je chybějící hodnota platným stavem pro váš systém. Nulový vzor objektu je zde dobrým řešením. Vyhýbá se potřebě neustálých explicitních kontrol, ale stále vám umožňuje reprezentovat nulový stav. Nejedná se o „překonávání chybového stavu“, jak někteří tvrdí, protože v tomto případě je nulový stav platným sémantickým stavem. Jak již bylo řečeno, neměli byste použít tento vzorec, když nulový stav není platným sémantickým stavem. Měli byste prostě vyjmout vaši proměnnou z rozsahu.

Použijte možná/Option. Zaprvé, kompilátor vás upozorní, že musíte zkontrolovat chybějící hodnotu, ale provede víc než jen nahrazení jednoho typu explicitní kontroly jiným. Pomocí Options můžete zřetězit svůj kód a pokračovat, jako kdyby vaše hodnota existuje, aniž byste museli ve skutečnosti kontrolovat až do absolutní poslední minuty. Ve Scale by váš příklad vypadal takto:

val customer = customerDb getByLastName "Goodman"
val awesomeMessage =
  customer map (c => s"${c.firstName} ${c.lastName} is awesome!")
val notFoundMessage = "There was no customer named Goodman.  How lame!"
println(awesomeMessage getOrElse notFoundMessage)

Na druhém řádku, kde vytváříme úžasnou zprávu, neprovádíme výslovnou kontrolu, zda byl zákazník nalezen, a krása je , kterou nemusíme . Teprve v poslední řadě, která může být o mnoho řádků později, nebo dokonce v jiném modulu, se výslovně zabýváme tím, co se stane, pokud Option je None. Nejen to, že kdybychom na to zapomněli, nebyl by typ zkontrolován. Dokonce i tehdy se to dělá velmi přirozeným způsobem, bez výslovného příkazu if.

V kontrastu s tím, že s null, kde typ kontroluje dobře, ale kde musíte provést explicitní kontrolu na každém kroku cesty nebo celá vaše aplikace vybuchne za běhu, pokud máte štěstí během použití v případě, že vaše jednotkové testy cvičení. Je to prostě nestojí za zmatek.

0
Karl Bielefeldt

Ústředním problémem NULL je to, že činí systém nespolehlivým. V roce 1980 napsal Tony Hoare v příspěvku věnovaném Turingovy ceně:

To nejlepší z mé rady původcům a designérům ADA bylo ignorováno. …. Nedovolte použití tohoto jazyka v jeho současném stavu v aplikacích, kde je kritická spolehlivost, tj. Jaderné elektrárny, řízené střely, systémy včasného varování, protibalistické systémy protiraketové obrany. Další raketa, která by se mohla vyhnout v důsledku chyby programovacího jazyka, nemusí být průzkumnou vesmírnou raketou na neškodné cestě do Venuše: Může to být jaderná hlavice explodující nad jedním z našich měst. Nespolehlivý programovací jazyk vytvářející nespolehlivé programy představuje mnohem větší riziko pro naše životní prostředí a pro naši společnost než nebezpečná auta, toxické pesticidy nebo nehody v jaderných elektrárnách. Buďte opatrní, abyste snížili riziko, nikoli jej zvyšovali.

Jazyk ADA se od té doby hodně změnil, tyto problémy však stále existují v Javě, C # a mnoha dalších populárních jazycích.

Je povinností vývojáře vytvářet smlouvy mezi klientem a dodavatelem. Například v C #, stejně jako v Javě, můžete použít Generics k minimalizaci dopadu reference Null vytvořením readonly NullableClass<T> (dvě možnosti):

class NullableClass<T>
{
     public HasValue {get;}
     public T Value {get;}
}

a poté použít jako

NullableClass<Customer> customer = dbRepository.GetCustomer('Mr. Smith');
if(customer.HasValue){
  // one logic with customer.Value
}else{
  // another logic
} 

nebo použijte dvě možnosti stylu s metodami rozšíření C #:

customer.Do(
      // code with normal behaviour
      ,
      // what to do in case of null
) 

Rozdíl je významný. Jako klient metody víte, co můžete očekávat. Tým může mít pravidlo:

Pokud třída není typu NullableClass, pak její instance nesmí být null .

Tým může tuto myšlenku posílit pomocí Design by Contract a statickou kontrolou v době kompilace, např. S ​​podmínkou:

function SaveCustomer([NotNullAttribute]Customer customer){
     // there is no need to check whether customer is null 
     // it is a client problem, not this supplier
}

nebo pro řetězec

function GetCustomer([NotNullAndNotEmptyAttribute]String customerName){
     // there is no need to check whether customerName is null or empty 
     // it is a client problem, not this supplier
}

Tento přístup může drasticky zvýšit aplikační spolehlivost a kvalitu softwaru. Design by Contract je případ Hoare logic , který byl osídlen Bertrandem Meyerem v jeho slavné Object-Oriented Software Construction book a Eiffel language v roce 1988, ale není používán neplatně v moderních softwarových řemeslech.

0
Artru