Pull to refresh

Концепция жизни программы

Reading time4 min
Views12K

Как можно определить понятие жизни программы? Жизнь программы можно описать повторяющейся последовательностью конечных процессов в компьютере выполненных в контексте выбранной предметной области. Обязательно конечных, в каком-то разумном временном отрезке.


design


Когда появляется программа? Скорее всего, программа появляется в голове у проектировщика/разработчика, можно назвать это design-time. Но так как этот момент не поддаётся контролю компьютера (пока), то предположим, что моментом появления программы является момент создания минимального запускаемого (о подробном смысле этого термина стоит поговорить отдельно) исходного кода.


В контексте модульных языков или языков с ООП — программа рождается, когда появляется минимальный модуль/класс. Дальнейшее рассмотрение будем проводить для модульных систем, так как в немодульных/скриптовых системах те или иные этапы обычно редуцированы/слеплены в единый этап.


Можно обоснованно выделить design-time в отдельную категорию, но не как процесс в голове разработчика, а чисто утилитарно, опираясь на процесс кодирования. Здесь можно описать автокомплит, автоподсветку (как уже реализованные программы), программирование макросов ide, генерацию схем БД и ДРАКОН-схем, и так далее.


compile


Затем, после этапа написания некоторого программного кода, программа передается компилятору. Компилятор обеспечивает т.н. compile-timeвремя компиляции. В результате выполнения процесса компиляции мы получаем компилят (то есть непосредственный результат обработки нашего исходного кода).


Во время компиляции наш исходный код влияет на работу компилятора по определенным законам, которые выражены в коде компилятора.


В то же самое время, никто не мешает уже на этапе компиляции управлять действиями компилятора (точнее, исполнителя в целом) не опосредованно, через написание текста нашей программы, а непосредственно, через написание кода общего назначения, который будет выполнен компилятором.


То есть такого кода, который хоть и относится к задуманной программе, но не переводится компилятором в компилят непосредственно. Так называемый CTFE, но в более общем смысле. Понятно, что нахождение в контексте процесса работы компилятора может накладывать некоторые ограничения на код времени компиляции, однако может и не накладывать.


Здесь мы можем заметить, что выполнение любого процесса жизненного цикла предполагает наличие результата, в явном или неявном виде.


load


После получения компилята, над ним, сразу или отложенно должен быть исполнен процесс связывания или линковки. Так как компилят обычно хранится в файле, то возникает время загрузкиload-time.


В это время над компилятом могут быть произведены дополнительные преобразования в код целевой платформы, и в это время может быть выполнен код времени загрузки, например, обработка компилята оптимизирующим компилятором.


На данный момент известна только одна технология, WebAssembly (slim-binaries), поздняя кодогенерация на целевой платформе, которая хоть как-то описывает время загрузки.



Обычно, линковка необходима, так как компилятор всегда производит компилят для одного модуля для непосредственного исполнения на целевой машине. Однако в реальной модульной системе на машине одновременно будут исполнены несколько модулей.


Эта ситуация в многомодульной системе приводит к необходимости связывания. В старых системах связывание могло производиться непосредственно после компиляции, но этот вырожденный случай мы не рассматриваем. Итак, возникает время связывания, или link-time.


Мало что известно про выполнение кода во время связывания, однако понятно, что в момент связывания возможно выполнение кода, например, Dependency Injection и динамического наследования/проксирования, как это может быть реализовано в рамках работы внутри jvm.


Такой контроль над еще не запущенным в действие, но уже готовым к исполнению кодом программы позволяет реализовывать автоматизированную настройку и так далее. После связывания и настройки код непосредственно готов к запуску.


init, run, close


Запуск и дальнейшая работа. Наиболее известные широкой публике этапы. Представлены временем инициализации (init-time) и временем исполнения (run-time). В сущности, результат работы этого этапа жизненного цикла и является обычно непосредственной целью написания программы.


Можно дополнительно выделить время завершения работы программы (close-time). Однако сейчас все три времени работы обычно принято называть run-time, а логическое деление на три этапа реализовывать уже в рамках клиентского программного кода.


Такой подход снижает требования к среде исполнения (run-time environment) но не дает гарантий исполнения того или иного этапа в нужной последовательности из-за возможных ошибок исполнения (run-time error) после которых исполнение, обычно, должно завершиться аварийно.


death


Отдельным важным временем жизни программы является посмертное время (death-time), в которое, вопреки распространенным представлениям тоже является частью жизненного цикла программы. Объяснение тут простое, так как целью работы программы обычно является некий результат, обычно зависящий от входных данных, которых может быть очень много, программы строятся с применением методов, позволяющих итеративно обрабатывать входные данные и производить выходные данные, которые могут быть поданы на вход следующей итерации.


Обычно такие данные структурированы (БД), версионны (результат взаимодействия со сторонним API) и их содержимое и интерпретация зависит от реализации работающей программы. То есть, программа это алгоритмы и данные, в том числе внешние и степень связанности этих внешних данных с программой никак не влияет на сам факт наличия такой связанности на любом этапе жизненного цикла.


Проще говоря, программа запущенная вновь будет работать по разному, в зависимости от результата, который был ею же получен на прошлом этапе жизненного цикла. И если внести в эти данные изменения во время, которое программа не запущена, программа тоже будет работать иначе, то есть, внося изменения в данные мы программируем программу работать иначе. Что есть этап жизненного цикла программы.


Итоги


Итак, рассмотрены этапы жизни программы: design-time -> compile-time -> load-time -> link-time -> init-time -> run-time -> close-time -> death-time. Как можно заметить, все этапы присутствует в цикле разработки и использования любой программы, а значит в любой из этих этапов может быть выполнен пользовательский код, который позволит получить результат, наиболее соответствующий целям разработчика. На сегодняшний день нет такого языка, фреймворка или экосистемы, в котором данные этапы были бы реализованы во всей полноте. Науке, бизнесу и сообществу есть куда стремиться.

Only registered users can participate in poll. Log in, please.
В каком из этапов вам не хватает возможности исполнения пользовательского кода?
46.67% design-time14
23.33% compile-time7
10% load-time3
3.33% link-time1
3.33% init-time1
20% run-time6
3.33% close-time1
16.67% death-time5
30 users voted. 53 users abstained.
Tags:
Hubs:
+5
Comments10

Articles