Африканец

Заметки про Жабу.


Часть 2. Околожабство

2.1. Техническое околожабство.

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

1) Самое очевидное техническое околожабство в том, что жаба компилятор, и с самыми лучшими виртуальными машинами все же существенно отстает от С++ (при этом речь идет о ОО-программе на С++, то есть программе со всеми этими красотами вроде динамической памяти и виртуальных методов). От нормальной программы на С жаба отстанет еще больше.

2) Далее, из-за переносимости жаба не позволяет нормально использовать возможности машины и ОС. Кто видел интерфейсы, писанные на жабе, даже с новомодным Swing, тот согласится, что по сравнению с виндами (а также по сравнению с Х-виндами) это просто убожество. Аналогично, Win32 имеет богатый набор примитивов синхронизации. Юникс тоже имеет (хотя и не столь богатый). На жабе все это недоступно по определению (если только не использовать native методы, интерфейс для которых разработан так, чтобы никто их не использовал).

3) Стандартная форма программы на жабе - россыпь java-файлов. Стандартная форма ее поставки - россыпь class-файлов. При этом никогда неясно, какие конкретно классы будут использоваться - на то есть переменная classpath, которая вечно стоит не куда надо. Почему-то пользоваться несколькими компиляторами С одновременно гораздо проще, чем несколькими жабами. И часто случаются очень трудно уловимые ошибки - ишещь ее час, а выясняется, что class- файл взялся из другого места (переменная неправильно стояла).

Кроме того, невозможно перетранслировать все, какие надо, файлы (но я об этом уже писал). Добавлю только вчерашний случай. Я взял чужую библиотеку в виде исходных файлов. Поставил вызов в свою программу и надеялся, что из-за этого все, что надо, перекомпилируется. Щас! Программа, оказалось, использовала RTTI, в изощренной форме - а именно формировала имя класса динамически, после чего этот коасс загружала. Причем все это было сделано без нужды, лишь бы выпендриться, а в итоге при работе программы в самый неподходящий момент вылетала исключительная ситуация NoClassDefException.

4) Ни в одном языке, кроме Жабы, не пытались еще ввести обязательный формат записи - где и как скобки ставить. Считается, что это унифицирует запись и сделает программы понятнее. Фигу. Программы будут понятнее, если их будут писать разумные люди, и только тогда. Мое мнение такое - программист должен иметь свой стиль записи, в котором ему работать удобно. Он должен также уметь читать любой другой стиль записи. Скажем, я пишу с пробелами и короткие процедуры, а Толик - без пробелов и длинные, но я могу его тексты читать и иногда понимать, а он - иногда мои. И нет проблем.

5) Жаба также вводит идиотские правила именования - классы с большой буквы с промежуточными большими буквами (ИмяКакогоТоКласса), методы - тоже с маленькой (вотКакПоДурацкиСмотрится), поля (данные) - тоже. Константы - целиком большими буквами через подчерк (ПОЛУЧАЕТСЯ_ВОТ_ТАК). Да, кстати, имена методов должны быть глаголами (getNextElement () вместо nextElement ()). И конечно, сам Sun это не соблюдает - у него методы называются как что попало.

В общем, все эти схемы раскладки и именования отвлекают внимание от собственно программирования и приводят к плохо читаемым программам.

6) Способ именования пакетов в жабе - отдельная песня. Они называются по адресу компании в обратном порядке. Скажем, мы зарегистрировали домен dvsoft.com - вот наши классы и называются com.dvsoft.... Это все хорошо, когда апплеты по сети приезжают, и совершенно бессмысленно при написании нормальных программ. Ведь кроме всего прочего единство имени не означает единства версии. Подход Микрософта с его COM мне нравится больше - не имя определяет интерфейс, а Глобальный Идентификатор.

7) Обзор технического околожабства будет явно неполон без такого чуда, как javadoc. Это, кто не знает, когда перед процедурами, переменными и классами делаются офигенного размера вставки, написанные на диковинной смеси HTML и специальных тегов. Потом программа подается на вход специальной утилите, которая делает по этому делу красивый HTML с описанием интерфейса. Как правило, выглядит он по идиотски, например:

 int getNextNumber ()
 - returns the nest number.
 Parameters: none
 Result: next number

Читать это - одно удовольствие. Читать исходный текст - одно мучение, Вы хотели бы иметь HTML-теги у себя в программе?

Мое мнение однозначно - комментарии это для человека. Или должен быть definition-модуль, в котором в красивом и понятном виде написано, что делает процедура. Если уж такого модуля нет, можно, конечно, и в основном тексте написать. Но - красиво и понятно, для человека, а не для машины. Хотите отдельный документ - пишите свои комментарии хотите в HTML, хотите в ворде - но отдельно. Не в исходном тексте. Этот текст еще людям читать.

8) Еще одно техническое околожабство - так называемые методы доступа. Написав любую структуру. любой жабовский программист всегда первым делом начинает писать методы доступа. Например, если ему надо описать запись из двух полей, х и y, он, не задумываясь, на полном автомате напишет следующее:

 class Point {
   private int x, y;

   public Point (int x, int y) {
     this.x = x;
     this.y = y;
   }

   public int getX () {
     return x;
   }

   public int getY () {
     return y;
   }

   public void setX (int x) {
     this.x = x;
   }

   public void setY (int y) {
     this.y = y;
   }
 }

Я спрашиваю - ЗАЧЕМ? Я бы еще понял, если бы эти переменные хранились в какой-то извращенной форме. А они хранятся как есть, и с большой вероятностью никогда не будут храниться по другому. Так зачем обращаться к ним через функции? Ну что этим достигается? Это явный идеологический бзик.

Я убежден - методы, высовываемые из класса, должны делать какое-то сложное действие. Иногда, для data consistency, поля полезно скрыть. Скажем, если бы мы разрешали менять x и y только оба вместе, я был бы обеими руками за то, чтобы делать это через методы. Был бы метод

 void setXY (int x, int y)

и все отлично. Хотя лично я в этом случае ввел бы в язык поля, доступные снаружи только на чтение, и избежал бы вызовов процедур для чтения переменных, оставив только для записи. А скрывать поля и тут же давать методы для доступа к этим полям ПООДИНОЧКЕ - это явный маразм.

Апологеты этого способа дошли до того, что класс не только наружу не должен высовывать поля - внутри их не должен использовать! То есть должен сам пользоваться этими функциями доступа. Для этого рекомендуется начинать имена полей с подчерка, чтобы их противный внешний вид отвращал от их использования.

9) Некоторым развитием этого служат так называемые "свойства" (properties). Это когда, считается, что у класса как бы есть поле (на самом деле нету), а мы как будто присваиваем этому полю, а при этом происходит какое-то действие. Например, есть свойство "FontSize", и мы пишем

  setFontSize (10);

И при этом все перерисовывается и размер фонта меняется. В Дельфях так вообще синтаксис присваивания для этого используется. Так вот, мне это очень не нравится. Название должно отражать суть процесса. Если метод только выставляет переменную, пусть называется set-что-нибудь. А если делает что-то - то do-что-нибудь. Какой-нибудь осмысленный глагол. В нашем случае - какое-нибудь changeFontSize или enlargeFont, а еще лучше вообще такого не иметь, а иметь что-нибудь вроде

  changeTextFont (String type_face, int font_size);

или

  changeTextFont (Font font);

А то некрасиво - одним вызовом мы меняем фонт, другим - его размер, а в итоге все жутко моргает. Это, конечно, никого не волнует - когда что-то моргает.

10) Жабцы очень любят "шаблоны разработки" (design pattern). Иногда дело доходит до смешного - например, они хотят запретить оператор switch, а всюду, где он нужен, использовать классы. Делается это так.

Пусть у нас есть переменная x, принимающая числовые значения A, B, C, и мы хотели бы написать
 switch (x)
 {
   case A: a (); break;
   case B: b (); break;
   case C: c (); break;
 }

Так вот, вместо этого мы определяем классы A, B, C, их базовый класс ABCConst, а в нем - метод

acceptVisitor (ABCVisitor v);

где ABCVisitor - интерфейс с тремя методами

 void visitA (A a);
 void visitB (B b);
 void visitC (C b);

Так вот, класс A определяет acceptVisitor так:

 acceptVisitor (ABCVisitor v)
 {
   v.visitA (this);
 }

После этого класс, в котором находится switch, определяется как реализующий этот самый visitor.

Далее, оператор switch заменяется на вызов

  x.acceptVisitor (x)*;

и к тому же в класс добавляются три метода такого вот вида:

 void void visitA (A x)
 {
   a ();
 }

и так далее. В итоге путем введения всего навсего двух интерфейсов и трех классов, то есть всего-то пяти файлов, от оператора switch мы избавились. Что делать, если в классе есть два оператора switch, оставлю читателю в качестве легкого упражнения.

Замечу, что, если эти самые a(), b(), c() должны вернуть результат, он должен быть либо заранее предусмотрен при изготовлении интервейса ABCVisitor, либо записан в какое-нибудь поле объемлющего класса. А о том, чтобы в этих процедурах бросить ексепцию, вообще лучше забыть. Еще замечу, что экземпляр объемлющего класса нам теперь нужен (со свитчем можно было и статический метод иметь), поскольку в процедуру accept передается this.

Все описанное называется "visitor design pattern". Меня хотели заставить с помощью него делать state machine. Там как раз два свитча - по текущему состоянию и по типу сообщения. Я сопротивился, в результате у меня один класс там, где могло быть пятьдесят. На самом деле я написал обе программы (а вернее нарисовал программу на С, которая сгенерировала обе программы, что почему-то удивило всех вплоть до директора фирмы), и всем продемонстрировал оба варианта. Вариант со свитчем еще и работал быстрее.

Еще один пример - singleton design pattern. Это значит, если мы имеем дело с модулем - то есть с классом с одними статическими функциями - то все же сделать их нестатическими, и иметь ровно один экземпляр этого объекта, и все делать через него. Без всякой цели - просто так, чтобы служба медом не казалось.

Разумеется, большая часть перечисленного - не есть свойство жабы. Я потому это и назвал околожабством. Просто наибольшее количество людей с вот таким образом испорченными мозгами тусуется около Жабы. Они есть и около С++, но все же их там поменьше. А около С и вовсе собрались разумные люди.

2.2. Политическое околожабство

Это околожабство заключается в великом шухере, поднятом вокруг жабы. Никогда еще ни вокруг какого языка такого шухера поднято не было. Посмотреть на это - так прямо серебряную пулю нашли, язык, который все проблемы человечества решит. Думаю, мой предыдущий текст показал, что это утверждение, мягко говоря, неверно.

Все соревнуются - не только и не столько в том, кто сделает интерпретатор или компилятор с жабы получше, сколько в том, кто поизощреннее эту жабу применит. Скажем, наша фирма решила написать на жабе телефонный софт не в последнюю очередь из-за того, чтобы не оказаться в последних рядах - среди тех, кто еще ничего на жабе не написал. И, конечно, хвастаться можно заказчику - вот мы какие! На жабе написали! И он, которому по идее не должно быть дела, клюет и радуется. Вот странно - на Фортране написано было, на Сноболе 4 или на Симуле-67 - это всегда было всем пофиг. Лишь бы работало. А на жабе - всем интересно. Как будто оно лучше от того, что на жабе.

Наше начальство поставило небольшой эксперимент и заявило, что разработка программы на жабе занимает в два раза меньше времени, чем такой же на С++. С С они не сравнивали. Так вот, я в это не верю. Я вижу, сколько времени пишут тут программы на жабе. Конечно, этих людей я бы к С++ вообще близко не подпускал, и к С тоже. Но ведь не только такие люди есть. Я уж точно на С быстрее напишу, особенно если никто над душой стоять не будет со своими паттернами.

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

Давайте зададим самый главный вопрос. Зачем жаба? Вообще, первый вопрос, который должен задать себе разработчик нового языка - зачем этот язык. Что с помощью него можно сделать, чего раньше было нельзя, и чего легко сделать, чего раньше было сложно. В случае жабы ответов три.

1) Для писания апплетов, которые ездят по сети и работают на машине клиента. Я полностью согласен, что для этого необходим абсолютно надежный интерпретируемый язык. Возможно, жаба для этого и годится, хотя она для этой цели слишком велика. Для нормальных целей достаточно какого-нибудь скриптового языка (вроде того же жабаскрипта, имеющего к жабе отношения не больше, чем c-shell к С).

Так вот, жаба нужна для апплетов. А для чего нужны апплеты? Где они, апплеты?

90% апплетов, которые я до сих пор видел - это были красивые счетчики. Или иной оживляж - всякие мигалки, скроллящиеся строки и прочий маразм. Единственный раз, когда апплет был по делу - это во время матча Deep Blue с Каспаровым. Я помню, в первом матче после каждого хода закачивалась доска в виде GIF, а во втором - только ходы, а показывались они на клиенте с помощью апплета.

Все! Больше путевых апплетов я не видел. Да что там - самый лучшей и полезный в мире сайт (угадайте какой) сделан с помощью чистого CGI. Так же устроены Amazon, сайты авиакомпаний, выдающие рекомендации по составлению маршрутов, сайты новостей - словом, все, что применяется по делу.

Итак, апплеты - это большой мыльный пузырь, никому это не надо.

2) Для писания переносимых программ. Мэнеджеры придумади термин - WORA, write once, run anywhere. Я бы лучше назвал это WOABNR - write once and better never run. Так вот, налицо технология, созданная для удобства програмимистов, а вернее, их мэнеджеров, а не пользователей. Представьте себе автомобиль, который умеет ездить по рельсам и дороге, на бензине и ацетоне, с левым рулем, который легко переставляется направо, но ездит только со скоростью до 5 км/ч. Купите вы такой? Так и с программами. Пользователю до большой балды, на чем написана программа и работает ли она на какой-либо еще платформе, кроме его собственной. Пользователю надо, чтобы программа хорошо работала на одной-единственной платформе - на его. Хорошо работала - это понятие многогранное. Оно включает в себя:

 - быстро работала на ней

 - имела бы внешний вид, принятый на этой платформе (например, Motif, Macintosh, Windows 95)

 - имела бы управляющие сигналы, принятые на данной платформе (например, на виндах - закрывалась бы по Alt-F4 и показывала бы хелп по F1)

 - сопрягалась бы с другими программами на данной платформе (скажем, понимала бы clipboard и drag & drop в виндах)

 - использовала бы на полную катушку возможности ОС в области многопоточности, многопроцессности, межпроцессного взаимодействия, файлового обмена и т.д. и с помощью этого добивалась максимальной эффективности и надежности. Например, не мещало бы, чтобы БД сбрасывала дисковый кэш по закрытию транзакции - как этого добиться на жабе?

 - использовала бы и юзерские возможности ОС тоже. Например, в виндах чтобы писала свои настройки в Registry, а не в странные файлы двоичного вида, получаемые при использовании жабовского механизма Serializable.

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

Косвенное доказательство этому - ГДЕ ЭТИ ПРОГРАММЫ? Ну где эти продукты, написанные на жабе? Единственное, что мы имеем - это сановские инструменты из JDK. Скорость их работы позволяет подозревать, что они написаны на жабе. Также легко видно, что микрософтный компилятор написан не на жабе - работает со свистом.

Corel предпринял попытку переписать свой офис на жабу. Я имел счастье лицезреть первую версию этого. WordPerfect и Quattro Pro, работающие в броузере! Со скоростью раз в пять меньше той, с которой аналогичные программы работали на Apple ][. Интересная была игрушка, но не более того. И известно, что Corel прикрыл эту работу, признав ее бесперспективнойю.

Нечто подобное случилось в Микрософте. Микрософт с самого начала считал идею с апплетами неинтересной - вместо них они проталкивали свои ActiveX. Но они рассматривали вариант писания на жабе своих собственных программ - мол, хороший, красиыйя язычок, что ж не пописать? Я боюсь ошибиться, но, мне кажется, они очень скоро осознали, что идея бредовая, и пишут в основном, как и раньше - на С и С++. А Жабу только продают лохам, вроде нас, сами же не используют.

Между прочим, количество переносимых программ, написанных на С, поражает воображение.

3) Для обучения. Здесь язык уже смотрится неплохо. Производительность и качество программ тут неважны, а объектно-ориентированное программирование вообще - полезная (хотя и не абсолютная) концепция. Жаль только, что вокруг жабы собрались фанатики, и они же с большой вероятностью будут учителями. Так что может получиться хуже. Иными словами, если бы не шухер вокруг жабы, она была бы почти идеальным языком для обучения. Шухер прибивает к ней толпу придурков - для обучения это опасно.

Наконец, хотелось бы заметить, что Жаба - отнюдь не первый объектно-ориентированный язык. До нее было немало симпатичных объектно-ориентированных языков, которые, однако, такого шухера не вызвали - взять ту же Симулу 67. Из современных можно посмотреть на Оберон, Актор и Модулу-3. Мне особенно понравилась Модула-3 - объектно-ориентированный язык на базе синтаксиса Модулы, с сохранением концепции definition-implementation, не претворяющийся проще, чем он есть, но и без лишней придури. Был разработан без участия Вирта фирмой DEC лет десять назад, но распространения не получил - видимо, у людей из фирмы DEC есть совесть.

2.3. Личное околожабство.

Каждый язык вызывает кучу ощущений и ассоциаций у пишущего на нем. Он как будто имеет психо-моторные и органо-лептические свойства. Писание на одном языке может отличаться от писание на другом, как поедание мяса от рыбы, или питье молока от вина, или езда на разных видах велосипедов. Некоторые языки вызывают приятное ощущение, некоторые - неприятное. Некоторые языки по ощущениям близки, некоторые - далеки. Скажем, для меня Модула далека от С, но не настолько, как Жаба. А наиболее близкий к жабе язык (для меня) - это Visual Basic. Почему-то ощущения почти один к одному совпадают. А Visual Basic мне глубоко противен. В первую очередь своим высоченным уровнем, из-за которого простые вещи приходится моделировать с помощью сложных.


3. Прогноз.

Мой личный прогноз - максимум через пять лет Жаба тихо помрет, или вернее сойдет с переднего плана, заняв подобающее ей место где-то возле Лого, Лиспа, Схемы, Снобола 4, Смолтока и Форта.

4. Выводы.

1) Когда вокруг шухер - сохраняйте ясную голову

2) Не будьте тем, кто расшибает голову, когда молится

3) Применяйте игрушки для игры, а серьезные вещи - для работы. Например, не пытайтесь делать себе серьезную аппаратуру из радиоконструктора.

4) Не торопитесь запрыгивать в поезд - убедитесь, не отцепленный ли это вагон.


Поправка:
В про техническое околожабство, строчку
x.acceptVisitor (x);
следует читать
x.acceptVisitor (this);
Приношу свои извинения.
Африканец