La programació estructurada es pot definir com un subconjunt o una disciplina de la programació procedimental, un dels paradigmes de programació més importants. Està orientat a millorar la claredat, qualitat i temps de desenvolupament d'un programa d'ordinador recorrent únicament a subrutines i a tres estructures de control bàsiques: seqüència, selecció (if i switch) i iteració (bucles for i while); així mateix, es considera innecessari i contraproduent l'ús de la transferència incondicional (GOTO); aquesta instrucció sol acabar generant l'anomenat codi espagueti, molt més difícil de seguir i de mantenir, a més d'originar nombrosos errors de programació.

Va sorgir a la dècada de 1960, particularment del treball de Böhm i Jacopini,Böhm, Jacopini. "Flow diagrams, turing machines and languages with only two formation rules" Comm. ACM, 9(5):366-371, May 1966, doi=10.1145/355592.365646 i un famós escrit d'Edsger Dijkstrade 1968: «La sentència goto, considerada perjudicial». Els seus postulats es veurien reforçats, a nivell teòric, pel teorema del programa estructurat i, en la pràctica, per l'aparició de llenguatges com ALGOL, dotat d'estructures de control consistents i ben formades.

Elements Estructura de la programació estructurada Els programes estructurats estan formats per estructures simples organitzades de forma jeràrquica que controlen el flux d'execució del programa. Hi ha tres estructures bàsiques:

Estructures de concatenació: una seqüència de declaracions o instruccions executades en ordre. En molts llenguatges de programació l'ordre d'execució de les instruccions està marcat pels salts de línia o per altres caràcters especials (per exemple ;). Estructures de selecció: són estructures que permeten seleccionar quines declaracions del programa s'executen depenent del seu estat. Normalment s'expressen utilitzant paraules clau com if..then..else...endif, switch, case, etc. Estructures de repetició: són estructures que permeten repetir l'execució d'una declaració fins que es compleixi una determinada condició. També s'utilitzen paraules clau (p. ex. for, repeat. while, do..until, etc.) Subrutines Les subrutines són les unitats a les quals es pot anomenar, com a procediments, funcions, mètodes o subprogrames. S'utilitzen per permetre que una sola declaració faci referència a una seqüència.

Blocs Els blocs s'utilitzen per permetre que grups de declaracions es tractin com si fossin una sola declaració. Els llenguatges "estructurats en blocs" tenen una sintaxi per tancar estructures d'alguna manera formals, com ara una declaració if entre parèntesis if..fi com a ALGOL 68, o una secció de codi entre claudàtors BEGIN..END, com a PL/I i Pascal, sagnia d'espai en blanc com a Python, o les claus {...} de C i molts llenguatges posteriors.

Història Orígens de la programació estructurada A finals dels anys setanta va sorgir la programació estructurada basada en el teorema del programa estructurat, demostrat per Böhm-Jacopini, demostra que tot programa es pot escriure utilitzant únicament els tres tipus d'estructures del llenguatge estructurat (seqüència, selecció i iteració). La majoria de llenguatges de programació estructurats disposen d'un repertori més ampli d'instruccions però aquestes instruccions es poden construir a partir de les instruccions bàsiques.

Aquest teorema proporciona la teoria bàsica per a la programació estructurada. Aquest sistema és de fet l'utilitzat per les unitats centrals de processament (CPU en angles) per l'execució de les instruccions del llenguatge màquina o ensamblador en les màquines simples que segueixen el mòdel de Von Neumann. Per tant, és interessant indicar que totes les aplicacions finalment s'executen en un llenguatge estructurat de baix nivell tot i que el llenguatge d'alt nivell llegit per la CPU des de la memòria principal del sistemes estigui implementat amb un altre paradigma de disseny (com per exemple Programació Orientada a Objectes).

El teorema del programa estructura estructurat no defineix com s'han d'escriure programes amb llenguatge estructurat. Les contribucions que gent com Edsger Dijkstra, Robert W. Floyd, Tony Hoare o David Gries van fer a finals dels anys 60 van posar les bases dels llenguatges estructurats.

Desviacions habituals Tot i que ara el goto s'ha substituït en gran part per les construccions estructurades de selecció (si/llavors/els altres) i repetició (mentre i per), pocs llenguatges estan purament estructurats. La desviació més comuna, que es troba en molts idiomes, és l'ús d'una sentència de retorn per sortir anticipadament d'una subrutina. Això dona lloc a múltiples punts de sortida, en lloc del punt de sortida únic requerit per la programació estructurada. Hi ha altres construccions per gestionar casos que són incòmodes en la programació purament estructurada.

Sortida anticipada

La desviació més comuna de la programació estructurada és la sortida anticipada d'una funció o bucle. A nivell de funcions, això és una declaració return. A nivell de bucles, això és una declaració break (acabar el bucle) o una declaració continue (acabar la iteració actual, continuar amb la següent iteració). En la programació estructurada, aquests es poden replicar afegint branques o proves addicionals, però per als retorns del codi imbricat això pot afegir una complexitat important. C és un exemple primerenc i destacat d'aquestes construccions. Alguns llenguatges més nous també tenen "ruptures etiquetades", que permeten sortir de més que el bucle més intern. Les excepcions també permeten una sortida anticipada, però tenen conseqüències addicionals i, per tant, es tracten a continuació.

Les sortides múltiples poden sorgir per diversos motius, la majoria de vegades perquè la subrutina no té més feina a fer (si retorna un valor, s'ha completat el càlcul), o s'ha trobat amb circumstàncies "excepcionals" que impedeixen que continuï, per tant, cal maneig d'excepcions.

El problema més comú a la sortida primerenca és que les instruccions de neteja o finals no s'executen; per exemple, la memòria assignada no es desassigna o els fitxers oberts no es tanquen, provocant fuites de memòria o fuites de recursos. S'han de fer a cada lloc de retorn, que és fràgil i pot provocar errors fàcilment. Per exemple, en un desenvolupament posterior, un desenvolupador podria passar per alt una instrucció de retorn, i una acció que s'hauria de realitzar al final d'una subrutina (per exemple, una sentència trace) pot no ser realitzada. en tots els casos. Els idiomes sense declaració de retorn, com ara Pascal estàndard i Seed7, no tenen aquest problema.

La majoria dels idiomes moderns ofereixen suport a nivell d'idioma per evitar aquestes filtracions; vegeu la discussió detallada a gestió de recursos. Normalment, això es fa mitjançant la protecció de desenrotllament, que garanteix que cert codi s'executa quan l'execució surt d'un bloc; aquesta és una alternativa estructurada a tenir un bloc de neteja i a goto. Això es coneix més sovint com a try...finally, i es considera una part del maneig d'excepcions. En cas de múltiples declaracions return introduint try...finally, sense excepcions pot semblar estrany. Existeixen diverses tècniques per encapsular la gestió de recursos. Un enfocament alternatiu, que es troba principalment en C++, és l'adquisició de recursos és la inicialització (Resource Acquisition Is Initialization o RAII), que utilitza el desenrotllament normal de la pila (desassignació de variables) a la sortida de la funció per cridar destructors en variables locals per desassignar recursos.

Kent Beck, Martin Fowler i els seus coautors han argumentat en els seus llibres sobre refacció que els condicionals imbricats poden ser més difícils d'entendre que un determinat tipus d'estructura més plana utilitzant múltiples sortides predicades per clàusula de guarda. El seu llibre de 2009 afirma que "un punt de sortida no és realment una regla útil. La claredat és el principi clau: si el mètode és més clar amb un punt de sortida, utilitzeu un punt de sortida; en cas contrari, no". Ofereixen una solució de llibre de cuina per transformar una funció que consisteix només en condicionals imbricats en una seqüència de declaracions de retorn (o llançament) vigilades, seguides d'un únic bloc sense protecció, que pretén contenir el codi per al cas comú, mentre que les declaracions guardades són suposadament tractar amb els menys comuns (o amb errors). Herb Sutter i Andrei Alexandrescu també argumenten al seu llibre de consells C++ de 2004 que el punt de sortida únic és un requisit obsolet.

En el seu llibre de text de 2004, David Watt escriu que "els fluxos de control de múltiples sortides d'una sola entrada són sovint desitjables". Utilitzant la noció de marc de Tennent de seqüenciador, Watt descriu uniformement les construccions de flux de control que es troben en els llenguatges de programació contemporanis i intenta explicar per què determinats tipus de seqüenciadors són preferibles a altres en el context de fluxos de control de múltiples sortides. Watt escriu que els gotos sense restriccions (seqüenciadors de salt) són dolents perquè la destinació del salt no s'explica per si mateixa per al lector d'un programa fins que el lector troba i examina l'etiqueta o l'adreça real que és l'objectiu del salt. En canvi, Watt argumenta que la intenció conceptual d'un seqüenciador de retorn és clara des del seu propi context, sense haver d'examinar la seva destinació. Watt escriu que una classe de seqüenciadors coneguda com a "seqüenciadors d'escapament", definit com un "seqüenciador que acaba l'execució d'una ordre o procediment que inclou textualment", inclou tant ruptures de bucles (incloses interrupcions de diversos nivells) com declaracions de retorn. Watt també assenyala que, mentre que els seqüenciadors de salts (gotos) s'han restringit una mica en idiomes com C, on l'objectiu ha de ser un bloc dins del local o un bloc exterior que engloba, aquesta restricció per si sola no és suficient per fer que la intenció dels gotos en C sigui pròpia. -descrivint i així encara poden produir "codi d'espaguetis". Watt també examina com es diferencien els seqüenciadors d'excepció dels seqüenciadors d'escapament i salt; això s'explica a la següent secció d'aquest article.

En contrast amb l'anterior, Bertrand Meyer va escriure al seu llibre de text de 2009 que instruccions com break i continue "són només els vells goto amb pell d'ovella" i es desaconsella el seu ús.

Gestió d'excepcions Basant-se en l'error de codificació de l'incident de l'Ariane 501, el desenvolupador de programari Jim Bonang argumenta que qualsevol excepció llançada des d'una funció infringeix el paradigma de sortida única i proposa que totes les excepcions entre procediments s'haurien de prohibir. Bonang proposa que tot C++ conforme a una única sortida s'hauria d'escriure seguint la línia de:

bool MyCheck1() throw() { bool success = false; try { // Fer alguna cosa que pugui generar excepcions. if (!MyCheck2()) { throw SomeInternalException(); } // Un altre codi semblant a l'anterior. success = true; } catch (...) { // Totes les excepcions capturades i registrades. } return success; }

Peter Ritchie també assenyala que, en principi, fins i tot un sol throw just abans del return en una funció constitueix una violació del principi de sortida única, però argumenta que les regles de Dijkstra es van escriure en un temps abans que el maneig d'excepcions es convertís en un paradigma en llenguatges de programació, per la qual cosa proposa permetre qualsevol nombre de punts de llançament a més d'un únic punt de retorn. . Assenyala que les solucions que inclouen excepcions pel bé de crear una única sortida tenen una profunditat de nidificació més alta i, per tant, són més difícils d'entendre, i fins i tot acusa els que proposen aplicar aquestes solucions als llenguatges de programació que admeten excepcions de participar en el pensament del culte de Cargo.