Подводя итог, подчеркнем, что, учитывая разнообразие существующих методов исполнения кода, выбор той или иной программной архитектуры системы важен, поскольку интеллектуальная система должна уметь формировать и модифицировать порядок и правила выполнения задач.
Однако при автоматическом создании кода мы неизменно столкнемся с типичными проблемами, связанными с корректностью кода. Согласно статистики, в среднем 60% времени по разработке программного обеспечения тратится не на программирование, а на отладку и тестирование кода. Если человек сталкивается с подобными проблемами, то с ними столкнется и автоматическая система динамической генерации кода. То есть либо код должен быть лишен ошибок (что, очевидно, невозможно), либо ошибки при исполнении кода должны порождать исключения, которые в свою очередь должны возвращать исполнимый код на уровень регенерации кода. Коррекцию или регенерацию можно сравнить с проведением эксперимента, а последовательную отладку программы – с методом проб и ошибок.
Также как программист пишет код с точки зрения собственных представлений или теории, при отладке и тестировании этого кода и при возникновении логической ошибки или некорректных результатов программа с отладочной средой указывают, что теория программиста была не идеальной. Последовательными итерациями программист корректирует код, доводя его до совершенства.
Дилемма первичности для операций и данных, операции с операциями
В отношении информационных технологий мы можем поднять вопрос первичности: что возникло раньше – данные или операции? Эта дилемма возникает не из праздного интереса, это дилемма определения главенства и выстраивания зависимостей. Должны ли обработки подстраиваться под структуры данных либо структуры данных должны строиться, исходя из особенностей обработок, в том числе языка программирования, особенностей доступа к данным?
С точки зрения агентов, информация является первичной, поскольку в окружающем мире информация не является собственностью самого агента, а потому агент существует в среде, насыщенной информацией. Кроме того, сошлемся на понятие априорной информации, описанное выше: она должна существовать до того, как первый процесс начнет «работать».
С точки зрения современных информационных систем и, в частности интеллектуальных систем, внутреннее хранилище данных также является первичным, поскольку результаты и исходные данные обычно напрямую определяются в структуре данных системы. Особенности архитектуры, поддерживаемые алгоритмы обработки данных обычно не влияют на структуру данных, поскольку все современные системы могут работать через универсальные интерфейсы с самыми разными хранилищами данных. Другими словами, при создании информационных систем сначала проектируется структура данных, и затем алгоритмы, работающие с этими данными.
Однако, если методы обработки данных предопределены заранее (например, мы вынуждены пользоваться каким-либо внешним программным модулем), то мы вырабатываем и подстраиваем под программу собственные структуры данных. В том числе эти структуры должны отвечать условиям необходимости и полноты внешнего программного модуля. Формально мы можем трансформировать данные, но не можем влиять на полноту данных, так как мы вынуждены оперировать требуемым от нас набором данных, а процедура дополнения данных до некоторого требуемого уровня – это неординарная и не всегда решаемая задача.
Возвращаясь к вопросам, освещенным в предыдущей главе, мы можем рассмотреть программный код как данные. И в этом случае дилемма первичности приводит нас к задаче структурирования кода как данных и дальнейшему управлению кодом (хотя бы даже кодом различного уровня, не обязательно кодом низкого уровня – машинным кодом). И тогда дилемма первичности превращается в несколько иную дилемму: что первично – курица или курица из яйца? Не воспринимайте этот вопрос как игру слов с целью затуманить Ваш мозг, это лишь попытка привести рассуждение к рассмотрению кода как данных.
Для рассмотрения возможностей соединения двух полярных субстанций (данных и процессов) рассмотрим эту дилемму с точки зрения аппаратных архитектур.
Код в данном случае представляет собой управляющие данные. Данные, которые обрабатываются программным кодом, называются операционными данными. Часто возникает вопрос разделения управляющих и операционных данных. Поскольку управляющие данные, то есть программы, хранятся ровно так же, как и операционные данные, возникает вопрос, могут ли смешиваться эти виды данных.
Если проанализировать историю программных и аппаратных архитектур, программных продуктов и парадигм программирования, то можно найти различия в подходах реализации хранения данных обработки и программных кодов.
Идеи, основанные на автоматном программировании, явно разделяют инструкции и память. Самые известные примеры автоматного программирования – это машина Тьюринга и машина Поста.
Аналогичная ситуация складывается и с продукционным программированием (нормальные алгоритмы Маркова). Продукции описываются одной структурой, а операционные данные рассматриваются как другая структура. Функциональное программирование (лямбда-исчисление) также разделяет описательную и операционную часть.
Ещё в 1946 году фон Нейманом при проектировании первых процессоров были сформированы несколько принципов построения ЭВМ. Одним из его принципов был принцип однородности памяти, в котором говорилось, что программы и данные хранятся в одной и той же памяти. С командами можно выполнять такие же действия, как и с данными. Альтернативой фон Неймановской архитектуре является гарвардская архитектура, которую отличает раздельное хранение команд и данных.
В практическом применении процессоры в начальной стадии развития разделяли общую область памяти на отдельные сегменты. В одном сегменте хранились управляющие данные, то есть коды команд, другой сегмент был областью памяти для хранения операционных данных. С развитием архитектуры процессоров для защиты программы от некорректных операций и, следовательно, для поддержания целостности управляющих инструкций процессора (команд), сам процессор контролировал область памяти с программным кодом и не позволял записывать в нее какие-либо значения.
В высокоуровневых языках программирования транслятор обычно ограничивает доступ к памяти, где хранится исполняемый код, а в интерпретируемых языках и вовсе отсутствует возможность не то, что скорректировать текст программы, но и даже получить этот текст. Одним из исключений является инструкция List некоторых реализаций языка программирования Basic, выводящая на экран исходный код программы. В других языках программирования для этих целей специально придумывают специальные программы, называемые «квайн» (quine). Аналогично, в скриптовых языках типа bat-файлов в dos/windows и *sh в Unix-системах код существует в текстовых файлах, а соответственно и доступ к ним может осуществляться через операции с файлами. В части языков программирования такая возможность реализуется через возможности интерпретатора или p-кода (пи-кода).
Другим исключением является операции аналогичного вида со встраиваемыми языками и скриптами. Первые – это SDK VBA, которые позволяют вызывать интерпретируемые VBA-процедуры из программного кода и скрипты обычно относятся к собственным языкам программирования либо тому же интерпретируемому языку программирование (как, например, команда exec в T-SQL и eval () в PHP).
Но фактически эти возможности остаются невостребованными с точки зрения модификации кода.
Говоря о различии между программным кодом и данными, нельзя забывать, что и программный код содержит данные.
Строгое разделение данных и программной обработки данных влияет и на целостность самих данных. В частности, программный код содержит константы, которые ссылаются на данные в хранилище данных, в том числе в СУБД. Данные со временем могут меняться, в то время как ссылки на них остаются неизменными. Часто эти ссылки невозможно отследить, что является потенциальным источником ошибок как результат несогласованности между данными внутри программного кода и данными в хранилище данных, что называется нарушением логической целостности данных.
Например, мы настраиваем финансовый отчет на основании оборотов по продажам и затратам. В программном коде отчета мы жестко привязываемся к счету плана счетов «Затраты на командировки», чтобы по этому конкретному коду счета настроить отчет, собирающий финансовые проводки из главной книги. В результате, если в дальнейшем потребуется изменить план счетов, например, изменить код для счета «затраты на командировки» либо создать дополнительный счёт с новым кодом для этих же целей, то отчет не будет работать так, как нужно – не будет работать вовсе либо будет работать частично по используемой ранее более узкой логике.
С одной стороны, вместо определения константы с кодом мы можем брать его из отдельного справочника или элемента данных, привязанного к плану счетов. Но с другой стороны, мы не можем это сделать, поскольку структура данных является фиксированной, а, кроме того, в таком случае нас ждёт сложная процедура администрирования этих структур, включая организацию ссылки на план счетов, массовых данных при необходимости (например, вместо одного счета мы должны указывать ряд счетов) и визуализации данных. Такой комплекс процедур влечет за собой существенные накладные расходы при настройке отчета, поэтому от этого пути отказываются в пользу отказа от контроля над целостностью данных.
В этой главе мы определили необходимые требования к реализации агента: это были требования сверху. То есть требования, которые помогут достичь критерия необходимости для достижения универсальности структур информации и данных.
Однако сам процесс структурирования и обработки информации невозможно начать, не обратившись к началам теории информации. Этому будут посвящены следующие главы.
Информатика структур
Определения
В предыдущих главах мы подходили к рассмотрению интеллектуальных систем сверху вниз. Теперь же настало время подойти к проектированию системы в обратном направлении, «снизу вверх», который обычно определяет ограничения и общепринятые стандарты к построению систем. Как и прежде, мы будем основываться на требовании универсальности при проектировании интеллектуальной информационной системы. И в этом случае нам понадобится рассмотреть базовые структуры данных и процессов, а также подходы к управлению данными и процессами, которые должны быть частью универсальной модели данных.
Информатика известна как наука о способах получения, накоплении, преобразовании и использовании информации. В упрощенном понимании эта наука рассматривает информацию как последовательность битов, а операции – как различные логические преобразования.
Нам необходимо определиться с основополагающими вопросами, связанными с определением информации. Это следует сделать, поскольку в большинстве случаев происходит смешение понятия информации и данных. Так что давайте начнем с определений.
Информация – это сведения о некоторых объектах и процессах, которые могут храниться и передаваться между агентами информации. Например, годовые кольца на спиле дерева отражают информацию о его возрасте. Сами кольца являются данными, их носителем и, следовательно, агентом – дерево. Мы расшифровали эти данные о возрасте – это наша информация, мы ее носители. Также информация может трактоваться не только как сведения, но и как знания о некоторых объектах и процессах. Информация располагается на некотором носителе и является неотделимой от носителя, то есть информация не существует без носителя, а при разрушении носителя, разрушается и информация.
При этом информация может отражать некоторые факты или быть самостоятельной. Например, в поле мы можем увидеть некоторый механизм неизвестного нам назначения. С помощью зрения мы «сняли» этот механизм, следовательно, информация о существующем объекте отразилась в нашей памяти. Теперь мы знаем, что существует такой объект определенной формы, но непонятного назначения. С помощью умозаключений мы можем интерпретировать наличие и назначение этого объекта. Например, то, что он стоит в поле, означает, что это объект сельскохозяйственного назначения. Такие выводы являются интерпретацией, которая позволяет восстановить смысл вещей, не определенный явным образом.
Информация не является лишь отражением некоторого физического факта, поскольку она также описывает умозрительные объекты. Например, понятие конкатенации как операции «склеивания» объектов данных линейной структуры не имеет отражения в материальном смысле. Эта операция может быть спроецирована на некоторые физические объекты в качестве примера, но в оригинальном своем значении она является умозрительной операцией.
Данные – это представление фактов и идей в формализованном виде, пригодном для передачи и обработки в некотором информационном процессе. Другими словами, данные – это формализованная или закодированная информация. При этом данные сами по себе являются информацией, поскольку они являются своего рода физическим объектом. В нашей реализации интеллектуальной системы мы стремимся к тому, чтобы закодировать любую информацию в данных, однако это не является самим собой разумеющимся процессом.
Данные являются некоторым кодом, который может храниться, транслироваться, копироваться и, в свою очередь, являться основой для хранения информации как, например, строковые данные. В таком случае информация и данные являются идентичными, при этом данные являются информацией. Но не наоборот, поскольку информация не является формализованной, как данные.
Слово «данные» происходит от латинского «datum», буквально означающего «факт», однако в настоящее время «данные» не определяются как факт. Данные не трактуются как некоторая данность, определенные свершившиеся или заданная информация, их современная трактовка связана с определенностью – типизированностью, упорядоченностью, формализованностью.
В контексте этих двух определений мы можем понять, что предметом исследований информатики обычно являются именно данные, а не информация. То есть основным объектом изучения информатики является «очищенная», типизированная или подготовленная информация в виде данных. Однако постановка задач, их выработка и анализ производится именно на менее формализованном уровне – на уровне информации. В частности, далее мы рассмотрим семантическую модель данных, описывающую данные, но с помощью информации.
С учетом вышесказанного прямо сейчас мы находимся на очень неявном водоразделе, где перемешиваются информация и данные. С одной стороны, мы не можем поставить знак тождественности между информацией и данными, а с другой стороны, все технологии, связанные с данными, называются информационными технологиями. И ведь действительно, данные непосредственно связаны с информацией. Таким образом, пока мы не погрузились в пучины одного и другого, давайте на берегу договоримся о том, как разделять эти понятия.