|
|
Почему именно Clipper, а не что-нибудь другое
Давайте рассмотрим Clipper, как язык и средство разработки, не обращая внимания
на его конкретную реализацию под названием CA-Clipper 5.x, с точки зрения
"на чем писать информационные системы".
Рассмотрим основные характеристики и требования к ИС:
- Надежность хранения данных
- Производительность обработки данных
- Функциональная расширяемость
- Масштабируемость по железу и ОС
- Другие, специфические (зависимые от тематики конкретной ИС) требования.
В данном случае, мы не претендуем на полноту списка требований, нам просто
хочется показать, насколько тесно связаны требования к ИС и к языку.
Любой из перечисленных параметров напрямую зависит от способностей системы
разработки, на основе которой была создана ИС. Так или иначе, достоинства и
недостатки средства разработки будут унаследованы в готовом конечном продукте.
Хотелось бы отдельно прояснить вопрос о "надежности". У многих программистов
и пользователей существует предвзятое мнение, что DBF - это очень ненадежно,
что системы, построенные на xBase, подвержены разрушениям данных и индексов.
Извините, но это совсем не так. DBF тут совсем ни при чем. Разрушения
происходят по вине технологии файл-сервер, в которой надежность всей системы
зависит от каждой единицы "железа", используемого в обработке данных.
Если же использовать технологию терминал-сервер
(например, в связке Linux+DosEmu),
то разрушения данных просто не возникают, так как вся обработка
данных производится на сервере и никак не зависит от пропаданий 220В на
клиентских станциях.
Соответственно требования к средству разработки:
- Производительность компилятора
- Производительность во время выполнения
- Препроцессор, способный подстраиваться под нужды программистов
- Легкость понимания для начинающих и мощь для профессионалов
- Легкое наращивание возможностей внешними библиотеками и/или через API
- Поддержка различных источников данных
- Масштабируемость по размерам кода, платформам, ОС, процессорам, кластерам и т.п.
- Поддержка различных стилей программирования - командный, процедурный, ОО, ...
Можно сказать, что это общие параметры, которые собственно ничего не дают
при выборе системы разработки. И Clipper как язык вполне удовлетворяет этим
требованиям - более мощного препроцессора, чем у Clipper я не видел (разве что
fort?), RDD, OO, C-API это все имеется в наличии и очень даже хорошего
качества.
С точки зрения языка более интересны параметры:
- байт код или машинный
- жесткая типизация или run-time проверки
- ОО или процедуры
- модель ОО
- клиент сервер, файл-сервер или терминал-сервер
- а может CORBA, Active-X
- текстовый или GUI
- поддерживаемые платформы
Байт код (псевдокод) или машинный
Как показывает история развития популярных ИС, практически все они имеют
в том или ином виде интерпретаторы "бухязыка" для расширения ИС без изменения
некоторого ядра ИС. И причем новые версии выходят со все большим использованием
"бухязыков", т.е. большая часть работы ИС перекладывается на скриптовые,
интерпретирующие или виртуальные машины. В качестве ярких примеров можно
привести 1C, perl, rexx, php, Java, VB. Т.е. как сказал бы чукча -
"тенденция, однако". К чему бы проявляется такая тенденция ?
Все очень просто - на интерпретируемых языках гораздо легче
выполнить требования по функциональной расширяемости и обеспечить
простоту сопровождения ИС в отличие от ИС,
построенных на машинных языках С/С++, ASM, Pascal и т.п.
Разумеется, в рамках интерпретатора тяжело организовать алгоритмы по
обработке больших массивов данных или быстродействующих программ. И для такого
рода алгоритмов должна быть предусмотрена возможность подключать код, написанный
на "системных" языках. Как это реализовано в том или ином языке, обсуждать не будем,
только упомянем, что C-API у Clipper достаточно продвинутое для подключения
практически всего, что можно написать на Си.
Типизация
В результате переписки и споров с Maxim.Friedental at f105.n5010.z2.fidonet dot org ( maxim@polyot.ru )
получился вот такой текст, добавлять и править не буду, приведу "как есть".
Тест полностью написан Максимом и в большей части мы с ним согласны.
Для начала определимся с терминами. Имеем сложную предметную область.
Для снижения сложности мы моделируем ее путем разбиения на
взаимодействующие сущности.
Сущность имеет свойства. Свойство может быть
либо информацией в определенном формате, либо операцией, определенной
над этой информацией.
Тип - это совокупность _всех_ свойств сущности.
Типизация - это явное указание в тексте программы типа каждой сущности.
При этом используется имя типа - идентификатор, который однозначно
определяет собственно тип. При этом обычно компилятор берет на себя
работу по проверке типов, т.к. типы переменных ему известны уже на этапе
компиляции.
Недостатки типизации таковы:
1. Недостаточная гранулированность. Например, функция на С
int foo (int a, int b) {
return a + b;
}
может принимать только аргументы типа int и приводящиеся к ним. Тем
самым она накладывает ИЗБЫТОЧНЫЕ ограничения на свои аргументы.
Действительно, int означает, что для a и b должны быть определены
операции -, /, *, %, <, ==, >, >>, << и уйма других. Но ведь они не
используются в теле функции! Сравним с той же функцией на
нетипизированном Smalltalk:
foo: a and: b
^ a + b.
У объекта a будет вызван метод '+' и ему передан аргумент b. Функция
правильно работает при ЛЮБЫХ объектах a, для которых определена операция
'+' и любых объектах b. Никаких других ограничений на объекты не
накладывается. Однако при этом не производится статическая проверка, и
все возможные проблемы вылезают во время выполнения. Единственным на
сегодняшний день решением для типизированных языков (C++, Java) является
определение большого количества интерфейсов, состоящих из одного/двух
методов и формирование типа каждой сущности путем множественного
наследования. Это неприемлемо.
2. Статичность типизации.
Весь смысл типизации заключается в статической проверке ДО выполнения
программы. Если по тем или иным соображениям переменная должна менять
свой тип, возникают определенные проблемы - либо язык вообще не
позволяет делать такое (и такие языки уже мертвы), либо позволяет, но
при этом выключаются все механизмы статической проверки типа! А учитывая
то, что в типизированных языках традиционно не развита run-time
поддержка информации о типах, возникает вопрос о целесообразности
применения типизированного языка в данном конкретном случае.
3. Смех и грех - эквивалентность типов определяется по эквивалентности
их идентификаторов, а не свойств. Например, C++ в ситуации
class A {
public:
int var;
};
class B {
public:
int var;
};
считает классы A и B - идентификаторами разных типов, хотя тип-то один и
тот же. Это тоже самое, как если бы автомастерская бралась ремонтировать
только желтые Жигули, и отказывалась от Жигулей всех других цветов :-)
4. Необоснованное увеличение количества ручной писанины для
программиста.
Это скорее проблемы неразвитости конкретных IDE, нежели
типизированных языков. Например, OCAML способен догадаться из записи
let x = 10, что тип x - int.
Но это скорее счастливое исключение из правил.
В большинстве языков тип приходится указывать вручную, более того,
приходится указывать его многократно.
Рассмотрим пример:
int max (int a, int b) {
return (a > b) ? a : b;
}
Здесь тип указан трижды, хотя ДОЛЖЕН был быть указан только один раз - и
так понятно из назначения функции, что тип второго аргумента и
возвращаемое значение будут такими же, что и тип первого аргумента. В
некоторых языках (Eiffel) есть специальные конструкции для этого, но
особой экономии при этом не получается. Синтаксический мусор,
возникающий при типизации, существенно сказывается в основном не на
затратах на написание программы, а на времени ее модификации. Это не
дает полноценно применить некоторые современные методики разработки
программ, например Extreme Programming (www.extremeprogramming.org).
5. Существует ряд мифов, связанных с типизацией.
Например, что
существенный процент ошибок в программе связан с ошибками, которые можно
отловить типизацией. Или что отлаживать run-time-овые ошибки типов очень
сложно. Любой пользователь Clipper-а знает, что это не так (при
нормальных средствах написания и отладки).
Некоторые считают, что типы
помогают документировать программу. Этот аргумент также выглядит
смешным, т.к.:
во-первых, кому нужна палочная дисциплина (а попробуйте пописать на С без типов ;-),
во-вторых, любое использование встроенных
типов вроде int, сразу перечеркивает все потуги документировать
программу. Int-ом может быть все, что угодно, от температуры на Аляске до
состояния конечного автомата,
в-третьих, есть более удобные средства документирования программы.
Говорят, что типизация стимулирует создание
системы типов, а, следовательно, и вдумчивого анализа предметной области.
Ну... все, наверное, видели программы, опровергающие это высказывание. ;-)
В настоящее время единственный аргумент ЗА статические проверки, который
я нахожу разумным - это невозможность оттестировать все возможные
варианты вызова всех ветвей кода. Грубо говоря, ветвь аварийного гашения
реактора может в реальности никогда не быть вызванной и не
протестированной, а статические проверки все-таки хоть что-то, да
проверят.
Максим закончил. Мне бы хотелось еще добавить один фактор - о какой типизации
может идти речь при обработке данных из БД (хоть DBF, хоть результатов
SQL-запроса)! Что можно проверить на этапе компиляции, если типы получаемых
данных заранее неизвестны?
Ну, если кому-то хочется иметь побольше проблем, то пусть обрабатывает
БД на Си, до тех пор пока не надоест.
Процедурная или объектная ориентация
А почему, собственно, вообще возникает такой вопрос? Почему язык не может
быть одновременно и тем и другим, а может еще и чем-то третьим?
Я еще понимаю, что "типизация" это принципиально. Потому, как создать
типизированный run-time язык - это просто нонсенс (описание чуть выше),
как и нетипизированный без run-time - что-то из области сумасшедших идей.
Вопрос должен звучать несколько иначе - какой синтаксис и модель лучше
использовать, чтобы не было конфликтов в компиляторе и тормозов при выполнении ?
А политический выбор "ОО или неОО" пусть остается на совести писателей.
Особо интересующиеся могут прочитать сравнение
ОО-моделей нескольких популярных языков программирования.
Собственно говоря, этот анализ прямого отношения к Clipper не имеет,
но зато проясняет недостатки некоторых подходов к ОО-программированию.
А вот ОО-модель Clipper даже назвать таковой стыдно. Тем более что как такого
ОО и не существует, если не считать недокументированные возможности, на которые
накручены через C-API несколько разных библиотек поддержки ОО. В данном
случае важно только одно - компилятор Clipper поддерживает ОО-синтаксис и
позволяет за счет средств расширения формировать и управлять объектами.
И еще один интересный вопрос - какая ОО-модель лучше подходит для
управления объектами, хранящимися в БД? Особенно, если хранилище неОО, а
обычные таблицы или результаты SQL-запросов.
Получается, что объекты должны наследовать структуру таблицы, а она неизвестна
до ее использования, я даже не упоминаю про этап компиляции, структура становится
известной лишь после открытия_БД/получения_ответа_от_SQL_сервера.
Вот и получается, что структура объекта должна генерироваться в run-time,
причем структура не является постоянной за время жизни объекта.
И много языков таких существует ? ..... И все они скриптовые!
Файл-сервер, клиент-сервер, терминал-сервер, CORBA, Active-X, GUI...
Собственно говоря, никаких языковых проблем для использования всех этих
технологий у Clipper не существует, есть проблемы с наличием/отсутствием
нужных библиотек или Clipper-совместимых компиляторов под нужные платформы.
Заключение
Так почему собственно Clipper, а не что-нибудь другое ?
Потому что мы не знаем другого языка, который умеет столько же, сколько
и clipper.
|