Кіріспе
Басқару ағынына негізделген бағдарламалау парадигмасы. Құрылымдық бағдарламалау – компьютерлік бағдарламаның түсініктілігін, сапасын және жасалу уақытын жақсартуға бағытталған бағдарламалау парадигмасы. Ол, таңдау (егер/сол болса/әйтпесе) және қайталау (while және for), блок құрылымдары мен кіші бағдарламаларды қолдану арқылы құрылымдық басқару ағыны құралдарын кеңінен пайдаланады. Бұл парадигма 1950-ші жылдардың соңында ALGOL 58 және ALGOL 60 бағдарламалау тілдерінің пайда болуымен қатар пайда болды, соның ішінде ALGOL 60 блок құрылымдарын қолдауды қамтыды. Оның танымалдылығының және кеңінен қабылдануының себептері, біріншіден академиялық ортада, кейіннен тәжірибеде, 1966 жылы құрылымдық бағдарлама теоремасының ашылуы және 1968 жылы голланд ғалымы Эдсгер В. Дикстраның "Жаман деп саналатын Go To операторы" деген ашық хатының жариялануы болды. Дикстра осы хатта "құрылымдық бағдарламалау" терминін енгізді. Құрылымдық бағдарламалау көбінесе, кейбір жағдайларда, мысалы, қателерді өңдеу қажет болғанда, бағдарламаны түсінікті етуге мүмкіндік беретін өзгерістермен қолданылады.
Ішкі бағдарламалар
Субпрограммалар; процедуралар, функциялар, әдістер немесе кіші бағдарламалар сияқты шақырылатын бөліктер, код тізбегін бір ғана оператор арқылы атауға мүмкіндік береді.
Блоктар
Блоктар бірнеше операторларды бір оператор ретінде қарастыруға мүмкіндік береді. Блоктық құрылымды тілдер операторларды белгілі бір ресми тәсілмен қоршау үшін синтаксиспен жабдықталған, мысалы, ALGOL 68-де if операторы if fi жақшаларымен, PL/I және Pascal-да BEGIN END бөлімдерімен, Python-да кеңістіктермен белгіленген кірігулермен немесе C және көптеген кейінгі тілдердегі фигуралық жақшалармен { }.
Нәтиже
ХХ ғасырдың соңына қарай дерлік барлық компьютер ғалымдары құрылымдық бағдарламалау ұғымдарын үйрену мен қолданудың пайдалы екеніне көз жеткізді. FORTRAN, COBOL және BASIC сияқты бастапқыда бағдарламалау құрылымдары болмаған жоғары деңгейдегі бағдарламалау тілдері қазір оларды қамтиды.
Жалпы ауытқулар
Бір кезде goto операторы қазір таңдау (if/then/else) және қайталау (while және for) құрылымдық конструкцияларымен көбінесе алмастырылғанмен, көптеген тілдер толығымен құрылымдық емес. Көптеген тілдерде кездесетін ең көп таралған қателік – бұл кіші бағдарламадан ерте шығу үшін return операторын қолдану. Бұл құрылымдық бағдарламалауда қажетті бір ғана шығу нүктесінің орнына, бірнеше шығу нүктелерін тудырады. Таза құрылымдық бағдарламалауда қиындық тудыратын жағдайларды шешу үшін басқа да конструкциялар бар.
Ертерек шығу
Құрылымдық бағдарламалаудан ең көп таралған ауытқу – функциядан немесе циклден ерте шығу. Функция деңгейінде бұл return операторы, ал цикл деңгейінде break (циклды тоқтату) немесе continue (ағымдағы итерацияны тоқтату, келесі итерацияға өту) операторлары болып табылады. Құрылымдық бағдарламалауда бұлар қосымша тармақтар немесе тексерулер арқылы көшіріле алады, бірақ ішкі кодтан шығу кезінде бұл айтарлықтай күрделілікке әкелуі мүмкін. C осы конструкциялардың ерте және маңызды мысалы болып табылады. Кейбір жаңа тілдерде «белгіленген break» операторлары да бар, олар тек ең ішкі циклдан ғана емес, одан да көп деңгейден шығуға мүмкіндік береді. Ерекшеліктер де ерте шығуға мүмкіндік береді, бірақ олардың қосымша салдары бар, сондықтан олар төменде қарастырылады. Бірнеше шығу нүктесінің пайда болуының әртүрлі себептері болуы мүмкін, көбінесе субпрограммада орындалатын жұмыс қалмағандықтан (мәнді қайтарса, есептеу аяқталған) немесе оны жалғастыруға кедергі келтіретін «көзге көрінбейтін» жағдайларға тап болғандықтан, сондықтан ерекшеліктерді өңдеу қажет. Ерте шығудың ең көп кездесетін мәселесі – тазалау немесе соңғы операторлардың орындалмауы, мысалы, бөлінген жад босатылмайды немесе ашық файлдар жабылмайды, бұл жад немесе ресурстардың ағып кетуіне әкеледі. Бұл әрбір шығу нүктесінде жасалуы керек, бұл қателерге бейім және оңай қателерге әкелуі мүмкін. Мысалы, дамыту кезінде әзірлеуші return операторын жіберіп алуы мүмкін, ал субпрограмманың соңында орындалуы тиіс болған әрекет (мысалы, іздеу операторы) барлық жағдайларда орындалмауы мүмкін. Стандартты Pascal және Seed7 сияқты return операторы жоқ тілдерде бұл мәселе жоқ. Көптеген қазіргі заманғы тілдер мұндай ағып кетулерді болдырмау үшін тілдік деңгейде қолдау көрсетеді; ресурстарды басқару туралы толыққанды талқылауды қараңыз. Көбінесе бұл unwind protection арқылы жүзеге асырылады, ол орындалу блогынан шыққан кезде белгілі бір кодтың орындалуына кепілдік береді; бұл тазалау блогы мен goto операторына құрылымдық балама. Бұл көбінесе try…finally түрінде белгілі және ерекшеліктерді өңдеудің бір бөлігі болып саналады. Ерекшеліктерсіз try…finally операторларын пайдалану, бірнеше return операторлары бар жағдайда, таңғаларлық көрінуі мүмкін. Ресурстарды басқаруды капсулалау үшін әртүрлі техникалар бар. Бастысы C++-да қолданылатын баламалы тәсіл – Ресурсты алу – инициализациялау, ол функциядан шығу кезінде жергілікті айнымалылардағы деструкторларды шақыру үшін қалыпты стек айналуын (өзгермелілерді босату) пайдаланады, ресурстарды босату үшін. Кент Бек, Мартин Фаулер және авторлары өздерінің қайта құру кітаптарында ұялы шарттылықтарды қорғаушы шарттармен алдын ала айтылған бірнеше шығу нүктелерін пайдаланатын жазық құрылымның белгілі бір түрінен түсіну қиын болуы мүмкін деп мәлімдейді. Олардың 2009 жылғы кітабында «бір шығу нүктесі шын мәнінде пайдалы ереже емес. Анықтық – басты қағида: егер әдіс бір шығу нүктесімен анық болса, бір шығу нүктесін пайдаланыңыз; әйтпесе пайдаланбаңыз» делінген. Олар тек ұялы шарттылықтардан тұратын функцияны қорғалған return (немесе throw) операторларының тізбегіне, содан кейін бір ғана қорғалмаған блокқа түрлендіру үшін аспаздық шешім ұсынады, онда жалпы жағдайдың коды болады, ал қорғалған операторлар аз таралған жағдайларды (немесе қателерді) өңдеуі керек. Герб Саттер мен Андрей Александерску 2004 жылғы C++ кеңестер кітабында жалғыз шығу нүктесі ескірген талап деп мәлімдейді. 2004 жылғы оқулығында Дэвид Уотт «бір кіруді, бірнеше шығуды басқару ағыны жиі қажет» деп жазады. Тенненттің секвенсерлік шеңберін пайдаланып, Уотт қазіргі заманғы бағдарламалау тілдерінде кездесетін басқару ағыны конструкцияларын біркелкі сипаттайды және бірнеше шығуды басқару ағыны жағдайында секвенсерлердің кейбір түрлерінің басқаларына қарағанда неге артық екендігін түсіндіруге тырысады. Уотт шектеусіз goto операторларының (салу секвенсерлері) жаман екенін жазады, өйткені салынған жердің мақсаты бағдарламаның оқырманына өзін-өзі түсіндірмейді, өйткені оқырман салынған жер болып табылатын нақты белгіні немесе мекенжайды тауып, зерттеуі керек. Керісінше, Уотт return секвенсерінің тұжырымдамалық мағынасы оның мақсатын қарастырмай, өзінің мәнмәтінінен анық екенін айтады. Уотт «мәтіндік түрде қоршау командасы немесе процедурасының орындалуын тоқтататын секвенсер» деп анықталатын құтылу секвенсерлері деп аталатын секвенсерлер класы циклдерден шығуларды (көп деңгейлі шығуларды қоса алғанда) және return операторларын қамтиды деп жазады. Уотт сонымен қатар секіру секвенсерлері (goto) C сияқты тілдерде біршама шектелген болса да, онда мақсатты жергілікті блок ішінде немесе қамтитын сыртқы блокта болуы керек, бұл шектеу ғана goto операторларының C-дегі мақсатын өзін-өзі сипаттау үшін жеткіліксіз етеді және олар әлі де «спагетти кодты» тудыруы мүмкін. Уотт сонымен қатар ерекшелік секвенсерлерінің құтылу және секіру секвенсерлерінен қалай ерекшеленетінін қарастырады; бұл осы мақаланың келесі бөлімінде түсіндірілген. Бұған қарамастан, Бертранд Мейер 2009 жылғы оқулығында break және continue сияқты операторлардың «ешқандай өзгеріссіз ескі goto операторының жаңа киімі ғана» екенін жазды және оларды пайдалануға қатысты қатты кеңес берді.
Бірнеше жазу
Кейде, кіші бағдарламалар бірнеше кіріс нүктесіне ие болуы мүмкін. Бұл көбінесе тек корутинаға (немесе генераторға/жартылай корутинаға) қайта кіру ретінде кездеседі, онда кіші бағдарлама басқаруды (және мүмкін мәнді) уақытша тоқтатады, бірақ содан кейін тоқтаған жерінен жалғастыруы мүмкін. Мұндай бағдарламалаудың көптеген қолданыстары бар, атап айтқанда, ағындар (әсіресе кіріс/шығыс), күй машиналары және параллелизм. Код орындалуы тұрғысынан алғанда, корутинадан уақытша тоқтау, кіші бағдарламадан қайтудан гөрі құрылымдық бағдарламалауға жақын, себебі кіші бағдарлама іс жүзінде аяқталмайды және қайта шақырғанда жалғасады – бұл ерте шығу емес. Дегенмен, корутиналар бірнеше кіші бағдарламалардың орындалу күйінде болуын білдіреді – кіші бағдарламалардың жалғыз шақыру стегінің орнына – және осылайша күрделіліктің басқа түрін енгізеді. Кіші бағдарламалардың кездейсоқ жерінен кіруге рұқсат беру өте сирек, себебі мұндай жағдайда бағдарламаның күйі (мысалы, айнымалылардың мәндері) белгіленбеген немесе екіұшты болады, бұл goto операторына өте ұқсас.
Мемлекеттік машиналар
Кейбір бағдарламаларда, әсіресе анализаторлар мен байланыс протоколдарында, бір-бірін оңай негізгі құрылымдарға келтірілмейтін күйлер тізбегі болады, ал кейбір бағдарламашылар күйді өзгерту үшін жаңа күйге тікелей секіруді қолданады. Мұндай күй ауыстыру Linux ядросында жиі қолданылады. Дегенмен, осы жүйелерді құрылымдауға болады, әр күй өзгерісін жеке тармақшаға айналдырып, белсенді күйді көрсету үшін айнымалыны пайдалану арқылы (трамплинді қараңыз). Балама ретінде, бұл корутиналар арқылы іске асырылуы мүмкін, оларға трамплин қажет емес.