Strukturované programování - Structured programming

Strukturované programování je paradigma programování, jehož cílem je zlepšit srozumitelnost, kvalitu a dobu vývoje počítačového programu rozsáhlým využitím strukturovaných toků konstruktů výběru ( if/then/else ) a opakování ( while and for ), blokové struktury , a podprogramy .

To se objevilo na konci padesátých let s výskytem programovacích jazyků ALGOL 58 a ALGOL 60 , přičemž druhý z nich obsahoval podporu blokových struktur. Faktory přispívající k jeho popularitě a všeobecnému přijetí, nejprve na akademické půdě a později mezi praktiky, zahrnují objev toho, co je nyní známé jako strukturovaná věta o programu v roce 1966, a zveřejnění vlivného otevřeného dopisu „ Přejít na prohlášení považováno za škodlivé “ v r. 1968 holandský počítačový vědec Edsger W. Dijkstra , který vytvořil termín „strukturované programování“.

Strukturované programování se nejčastěji používá s odchylkami, které umožňují jasnější programy v některých konkrétních případech, například když je třeba provést zpracování výjimek .

Elementy

Řídicí struktury

Podle věty o strukturovaných programech jsou všechny programy považovány za složené z řídicích struktur :

  • "Sekvence"; seřazené příkazy nebo podprogramy prováděné v pořadí.
  • "Výběr"; v závislosti na stavu programu se provede jeden nebo více příkazů. To se obvykle vyjadřuje pomocí klíčových slov , jako je if..then..else..endif. Podmíněný příkaz by měl mít alespoň jednu skutečnou podmínku a každá podmínka by měla mít jeden výstupní bod na max.
  • "Opakování"; příkaz nebo blok je spuštěn, dokud program nedosáhne určitého stavu, nebo nebyly na každý prvek kolekce použity operace. To je obvykle vyjádřeno klíčovými slovy, jako whileje repeat, fornebo do..until. Často se doporučuje, aby každá smyčka měla pouze jeden vstupní bod (a v původním strukturálním programování také jen jeden výstupní bod a několik jazyků to prosazovalo).
  • "Rekurze"; příkaz se provádí opakovaným voláním, dokud nejsou splněny podmínky ukončení. I když jsou rekurzivní smyčky v praxi podobné iteračním smyčkám, mohou být výpočetně efektivnější a jsou implementovány odlišně jako kaskádový zásobník.
Grafické znázornění tří základních vzorů - posloupnosti, výběru a opakování - pomocí NS diagramů (modrý) a vývojových diagramů (zelený).

Podprogramy

Podprogramy ; volatelné jednotky, jako jsou procedury, funkce, metody nebo podprogramy, se používají k tomu, aby na sekvenci bylo možné odkazovat jediným příkazem.

Bloky

Bloky se používají k tomu, aby bylo možné se skupinami příkazů zacházet, jako by byly jedním příkazem. Jazyky strukturované do bloků mají syntaxi pro uzavření struktur nějakým formálním způsobem, například příkazem if-bracketed if..fijako v ALGOL 68 nebo sekcí kódu v závorkách BEGIN..END, jako v PL/I a Pascal , odsazení mezer jako v Pythonu -nebo složené závorky {...}z C a mnoho pozdnějších jazycích .

Strukturované programovací jazyky

Strukturované programování je možné provádět v jakémkoli programovacím jazyce, i když je vhodnější použít něco jako procedurální programovací jazyk . Mezi jazyky původně používané pro strukturované programování patří: ALGOL , Pascal , PL/I a Ada , ale většina nových procedurálních programovacích jazyků od té doby obsahuje funkce podporující strukturované programování a někdy záměrně vynechává funkce - zejména GOTO - v úsilí o ztížení nestrukturovaného programování . Strukturované programování (někdy známé jako modulární programování) vynucuje logickou strukturu psaného programu, aby byla efektivnější a snáze pochopitelná a upravitelná.

Dějiny

Teoretické základy

Strukturovaný program teorém poskytuje teoretický základ strukturovaného programování. Uvádí, že tři způsoby kombinování programů - sekvenování, výběr a iterace - jsou dostatečné k vyjádření jakékoli vyčíslitelné funkce . Toto pozorování nepochází z hnutí strukturovaného programování; Tyto struktury jsou dostatečné k popisu instrukční cyklus o centrální procesorové jednotky , jakož i provoz Turing stroj . Proto procesor vždy provádí „strukturovaný program“ v tomto smyslu, i když pokyny, které čte z paměti, nejsou součástí strukturovaného programu. Autoři však obvykle připisují výsledek příspěvku Böhma a Jacopiniho z roku 1966, možná proto, že Dijkstra citoval tento dokument sám. Věta o strukturovaném programu neřeší, jak napsat a analyzovat užitečně strukturovaný program. Tyto problémy byly řešeny na přelomu šedesátých a na začátku sedmdesátých let minulého století, s velkým přispěním Dijkstra , Robert W. Floyd , Tony Hoare , Ole-Johan Dahl a David Gries .

Rozprava

PJ Plauger , raný osvojitel strukturovaného programování, popsal svou reakci na větu o strukturovaném programu:

My konvertité mávali touto zajímavou novinkou pod nosem nerekonstruovaných programátorů v montážním jazyce, kteří neustále klusali zakroucenými kousky logiky a říkali: ‚Vsadím se, že tohle nedokážu strukturovat. ' Ani důkaz od Böhma a Jacopiniho, ani naše opakované úspěchy při psaní strukturovaného kódu je nepřinesly o jeden den dříve, než byli připraveni sami sebe přesvědčit.

Donald Knuth přijal zásadu, že programy musí být psány s ohledem na prokazatelnost, ale nesouhlasil (a stále nesouhlasí) se zrušením prohlášení GOTO. Ve svém příspěvku z roku 1974 s názvem „Structured Programming with Goto Statements“ uvedl příklady, kdy věřil, že přímý skok vede k jasnějšímu a efektivnějšímu kódu, aniž by byla obětována prokazatelnost. Knuth navrhl volnější strukturální omezení: Mělo by být možné nakreslit vývojový diagram programu se všemi dopřednými větvemi vlevo, všemi zpětnými větvemi vpravo a žádnými větvemi, které se navzájem kříží. Mnoho z těch znalých kompilátorů a teorie grafů prosazovalo umožnění pouze redukovatelných tokových grafů .

Teoretici strukturovaného programování získali významného spojence v 70. letech poté, co výzkumník IBM Harlan Mills aplikoval svou interpretaci teorie strukturovaného programování na vývoj indexovacího systému pro výzkumný soubor The New York Times . Projekt byl velkým inženýrským úspěchem a manažeři v jiných společnostech jej citovali na podporu přijetí strukturovaného programování, ačkoli Dijkstra kritizoval způsoby, kterými se interpretace Mills liší od publikované práce.

Ještě v roce 1987 bylo stále možné nastolit otázku strukturovaného programování v časopise počítačové vědy. Frank Rubin tak učinil v tomto roce otevřeným dopisem s názvem „GOTO považováno za škodlivé, považováno za škodlivé“. Následovaly četné námitky, včetně reakce od Dijkstra, která ostře kritizovala jak Rubina, tak ústupky, které ostatní spisovatelé učinili, když na něj reagovali.

Výsledek

Na konci 20. století byli téměř všichni počítačoví vědci přesvědčeni, že je užitečné naučit se a používat koncepty strukturovaného programování. Programovací jazyky na vysoké úrovni, které původně postrádaly programovací struktury, jako jsou FORTRAN , COBOL a BASIC , je nyní mají.

Běžné odchylky

Zatímco goto je nyní do značné míry nahrazeno strukturovanými konstrukty výběru (if/then/else) a opakování (while and for), několik jazyků je čistě strukturovaných. Nejběžnější odchylkou, která se vyskytuje v mnoha jazycích, je použití příkazu return pro předčasné ukončení podprogramu. Výsledkem je více výstupních bodů namísto jediného výstupního bodu požadovaného strukturovaným programováním. Existují i ​​jiné konstrukce pro zpracování případů, které jsou v čistě strukturovaném programování nepříjemné.

Předčasný odchod

Nejběžnější odchylkou od strukturovaného programování je předčasné ukončení funkce nebo smyčky. Na úrovni funkcí je to returnprohlášení. Na úrovni smyček se jedná o breakpříkaz (ukončete smyčku) nebo continuepříkaz (ukončete aktuální iteraci, pokračujte další iterací). Ve strukturovaném programování je lze replikovat přidáním dalších větví nebo testů, ale pro návraty z vnořeného kódu to může přidat značnou složitost. C je raný a prominentní příklad těchto konstruktů. Některé novější jazyky mají také „označené přestávky“, které umožňují vymanit se z více než jen nejvnitřnější smyčky. Výjimky také umožňují předčasný odchod, ale mají další důsledky, a proto jsou popsány níže.

Vícenásobné opuštění může nastat z různých důvodů, nejčastěji buď, že podprogram již nemá co dělat (pokud vrací hodnotu, dokončil výpočet), nebo se setkal s „výjimečnými“ okolnostmi, které mu brání pokračovat, a proto potřebuje zpracování výjimek.

Nejčastějším problémem při předčasném ukončení je, že nejsou prováděny vyčištění nebo závěrečné příkazy - například přidělená paměť není uvolněna nebo otevřené soubory nejsou zavřeny, což způsobuje úniky paměti nebo úniky prostředků . To je třeba provést na každém místě vrácení, které je křehké a může snadno vést k chybám. Například v pozdějším vývoji mohl vývojář přehlédnout příkaz return a akce, která by měla být provedena na konci podprogramu (např. Příkaz trace ), nemusela být provedena ve všech případech. Jazyky bez prohlášení o návratu, jako jsou standardní Pascal a Seed7 , tento problém nemají.

Většina moderních jazyků poskytuje podporu na úrovni jazyků, aby se zabránilo takovým únikům; viz podrobná diskuse o správě zdrojů . Nejčastěji se to provádí pomocí ochrany proti odvíjení, která zajišťuje, že se jistý kód zaručeně spustí, když provádění ukončí blok; toto je strukturovaná alternativa k vyčištění bloku a goto. Toto je nejčastěji známé jako try...finally,součást zpracování výjimek . V případě více returnprohlášení může zavedení try...finally,bez výjimek vypadat divně. K zapouzdření správy zdrojů existují různé techniky. Alternativní přístup, nalezený primárně v C ++, je Resource Acquisition Is Initialization , který používá normální odvíjení zásobníku (variabilní deallocation) při ukončení funkce k volání destruktorů na lokálních proměnných k uvolnění zdrojů.

Kent Beck , Martin Fowler a spoluautoři ve svých knihách o refaktorování tvrdili, že vnořené podmíněnosti mohou být hůře srozumitelné než určitý typ plošší struktury využívající více východů předvídaných ochrannými doložkami . Jejich kniha z roku 2009 jasně říká, že „jeden výstupní bod opravdu není užitečné pravidlo. Klíčovým principem je jasnost: Pokud je metoda jasnější s jedním výstupním bodem, použijte jeden výstupní bod; jinak ne“. Nabízejí řešení kuchařky pro transformaci funkce sestávající pouze z vnořených podmíněných podmínek do sekvence hlídaných návratových (nebo vyhozených) příkazů, následovaných jedním nestřeženým blokem, který má obsahovat kód běžného případu, zatímco hlídané příkazy jsou údajně řešit ty méně obvyklé (nebo s chybami). Herb Sutter a Andrei Alexandrescu také ve své knize tipů C ++ z roku 2004 tvrdí, že bod s jedním výstupem je zastaralý požadavek.

David Watt ve své učebnici z roku 2004 píše, že „řídicí toky s jedním vstupem a s více výstupy jsou často žádoucí“. Watt pomocí rámcového pojmu sekvenceru společnosti Tennent jednotně popisuje konstrukty řídicího toku, které se nacházejí v současných programovacích jazycích, a pokouší se vysvětlit, proč jsou určité typy sekvencerů upřednostňovány před jinými v kontextu toků řízení s více výstupy. Watt píše, že neomezené gotos (sekvencery skoků) jsou špatné, protože cíl skoku není pro čtenáře programu samozřejmostí, dokud čtenář nenajde a nezkoumá skutečný štítek nebo adresu, která je cílem skoku. Naproti tomu Watt tvrdí, že koncepční záměr sekvenceru návratu je jasný z jeho vlastního kontextu, aniž by musel zkoumat jeho cíl. Watt píše, že třída sekvencerů známá jako únikové sekvencery , definovaná jako „sekvencer, který ukončí provádění textově uzavírajícího příkazu nebo procedury“, zahrnuje jak přestávky ze smyček (včetně víceúrovňových přestávek), tak příkazy return. Watt také poznamenává, že zatímco skokové sekvencery (gotos) byly poněkud omezeny v jazycích jako C, kde cíl musí být uvnitř lokálního bloku nebo obklopující vnější blok, toto omezení samo o sobě nestačí k tomu, aby byl záměr gotos v C self -popis a tak mohou stále vyrábět „ špagetový kód “. Watt také zkoumá, jak se liší sekvencery výjimek od sekvencerů pro únik a skok; toto je vysvětleno v další části tohoto článku.

Na rozdíl od výše uvedeného napsal Bertrand Meyer ve své učebnici 2009, že pokyny jako breaka continue„jsou jen staří gotov ovčím rouchu“, a důrazně nedoporučoval jejich používání.

Zpracování výjimek

Na základě chyby v kódování způsobené katastrofou Ariane 501 vývojář softwaru Jim Bonang tvrdí, že jakékoli výjimky vyvolané funkcí narušují paradigma jednoho výstupu, a navrhuje, aby byly zakázány všechny výjimky mezi procedurami. Bonang navrhuje, aby všechny C ++ vyhovující jednomu východu byly zapsány podle:

bool MyCheck1() throw() {
  bool success = false;
  try {
    // Do something that may throw exceptions.
    if (!MyCheck2()) {
      throw SomeInternalException();
    }
    // Other code similar to the above.
    success = true;
  } catch (...) {
    // All exceptions caught and logged.
  }
  return success;
}

Peter Ritchie také poznamenává, že v zásadě i jediné throwprávo před returnfunkcí představuje porušení principu jednoho výstupu, ale tvrdí, že Dijkstraova pravidla byla napsána v době, kdy se manipulace s výjimkami stala paradigmatem v programovacích jazycích, takže navrhuje povolit libovolný počet bodů hodu kromě jediného bodu návratu. Poznamenává, že řešení, které zábal výjimky pro zájmu vytvoření jednotného-východ mají vyšší hnízdění hloubku, a proto je obtížnější pochopit, a dokonce obvinil ty, kteří navrhují, aby taková řešení, programovací jazyky, které podporují výjimkami zapojení do cargo kultu myšlení .

David Watt také analyzuje zpracování výjimek v rámci sekvencerů (představených v tomto článku v předchozí části o předčasných ukončeních.) Watt poznamenává, že neobvyklá situace (obvykle ilustrovaná aritmetickým přetečením nebo selháním vstupu/výstupu jako soubor nebyl nalezen) je druh chyby, která „je detekována v nějaké nízkoúrovňové programové jednotce, ale [pro kterou] je obsluha přirozeněji umístěna v programové jednotce vysoké úrovně“. Program může například obsahovat několik volání ke čtení souborů, ale akce, kterou je třeba provést, když soubor není nalezen, závisí na smyslu (účelu) příslušného souboru v programu, a proto nelze rutinu zpracování této neobvyklé situace provést. umístěný v systémovém kódu nízké úrovně. Watts dále poznamenává, že zavedení testování stavových příznaků ve volajícím, jak by to zahrnovalo strukturované programování s jedním výstupem nebo dokonce (vícevýstupové) sekvencery návratu, vede k situaci, kdy „kód aplikace má tendenci být přeplněn testy stavových příznaků“ a že "programátor může zapomenout nebo líně vynechat testování stavového příznaku. Ve skutečnosti jsou abnormální situace reprezentované stavovými příznaky ve výchozím nastavení ignorovány!" Poznamenává, že na rozdíl od testování stavových příznaků mají výjimky opačné výchozí chování , což způsobí ukončení programu, pokud se programátor výjimku výslovně nějakým způsobem nezabývá, případně přidáním kódu, který ji záměrně ignoruje. Na základě těchto argumentů Watt dochází k závěru, že skokové sekvencery nebo únikové sekvencery (popsané v předchozí části) nejsou tak vhodné jako vyhrazený sekvencer výjimek se sémantikou diskutovanou výše.

Učebnice Loudena a Lamberta zdůrazňuje, že manipulace s výjimkami se liší od strukturovaných programovacích konstrukcí, jako jsou whilesmyčky, protože přenos kontroly "je nastaven v jiném bodě programu, než ve kterém probíhá skutečný přenos. V místě, kde k přenosu skutečně dochází "nemusí existovat žádný syntaktický náznak, že kontrola bude ve skutečnosti přenesena." Profesor počítačových věd Arvind Kumar Bansal také poznamenává, že v jazycích, které implementují zpracování výjimek, dokonce i řídicí struktury, jako forjsou vlastnosti s jediným východem při neexistenci výjimek, ji již nemají za přítomnosti výjimek, protože výjimka může předčasně způsobit výstup v jakékoli části řídicí struktury; například pokud init()vyvolá výjimku for (init(); check(); increm()), pak není dosažen obvyklý výstupní bod po check (). Westley Weimer a George Necula s odvoláním na několik předchozích studií ostatních (1999-2004) a jejich vlastních výsledků napsali, že významným problémem s výjimkami je, že „vytvářejí skryté cesty toku řízení, o nichž je pro programátory obtížné uvažovat“.

V některých současných programovacích prostředích zaměřených na paralelní výpočty, jako je OpenMP, se objevuje nutnost omezit kód na body s jedním výstupem . Různé paralelní konstrukty z OpenMP, podobně parallel do, neumožňují předčasné východy zevnitř ven z paralelního konstruktu; toto omezení zahrnuje všechny způsoby ukončení, od breakvýjimek po C ++, ale všechny jsou povoleny uvnitř paralelního konstruktu, pokud je v něm také cíl skoku.

Vícenásobný vstup

Vzácněji podprogramy umožňují více vstupů. Nejčastěji se jedná pouze o opětovný vstup do korutinu (nebo generátoru /semikorutiny), kde podprogram poskytuje kontrolu (a případně hodnotu), ale lze jej poté obnovit tam, kde skončil. Existuje řada běžných použití takového programování, zejména pro toky (zejména vstup/výstup), stavové stroje a souběžnost. Z hlediska provádění kódu je výnos z korutiny blíže strukturovanému programování než návrat z podprogramu, protože podprogram ve skutečnosti neskončil a bude pokračovat, když bude znovu vyvolán - nejedná se o předčasné ukončení. Korutiny však znamenají, že více podprogramů má stav provedení - spíše než jeden zásobník podprogramů volání - a tím zavádí jinou formu složitosti.

Je velmi vzácné, že podprogramy umožňují vstup na libovolnou pozici v podprogramu, protože v tomto případě je stav programu (například hodnoty proměnných) neinicializovaný nebo nejednoznačný, a to je velmi podobné goto.

Státní stroje

Některé programy, zejména analyzátory a komunikační protokoly , mají řadu stavů, které na sebe navazují způsobem, který nelze snadno redukovat na základní struktury, a někteří programátoři implementují změny stavu skokem do nového stavu. Tento typ přepínání stavu se často používá v jádře Linuxu.

Je však možné tyto systémy strukturovat tak, že každý stav změní samostatný podprogram a pomocí proměnné označí aktivní stav (viz trampolína ). Alternativně je lze implementovat prostřednictvím doprovodných programů, které se obejdou bez trampolíny.

Viz také

Reference

Citace

Prameny

externí odkazy

  • BPStruct - Nástroj pro strukturování souběžných systémů (programy, procesní modely)
  • J. Darlinton; M. Ghanem; HW To (1993), „Structured Parallel Programming“, In Programming Models for Massually Parallel Computers. IEEE Computer Society Press. 1993 : 160–169, CiteSeerX  10.1.1.37.4610