IT FAQ

Разные очевидные вещи, которые все равно никто не понимает.

  1. IT FAQ
    1. Чем плохи ruby и python?
      1. См. также
    2. Плох ли XML?
    3. Для чего нужна сильная типизация?
      1. О тестах
    4. Так какие же инструменты — правильные? Что нужно использовать?

Чем плохи ruby и python?

Тем, что в их нынешнем состоянии они совершенно не годятся:

Во-певрых, у скриптовых языков беда с зависимостями. Если системный скрипт написан для python версии 2.4, то это автоматически означает, что в дистрибутиве будет python 2.4, не новее и не старее. До тех пор, пока скрипт не перепишут под новую версию питона. Потому что если python обновить, то сломается системный скрипт. И вся система перестанет работать. Dependency hell во всей красе.

Сейчас в дистрибутивах эту проблему решают добавлением номера версий в имена файлов. Типа, /usr/bin/python2.6 и /usr/lib/python2.5/. Еще один способ выкрутится — пихать интерпретатор и библиотеки языка вместе со скриптом. Идеально решили проблему в дистрибутиве nixos: там каждый пакет тащит за собой нужные ему версии зависимостей и работает только с ними.

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

В-третих, в реализациях обоих языков есть GIL, из-за которого нормальная работа с тредами почти невозможна. Программы на этих языках будут блокировать взаимодействие с пользователем и не отвечать на ctrl+c, если в тредах выполняется какая-либо фоновая операция. GUI при этом будет висеть и не отвечать на действия пользователя, а вычисления будут всегда производиться в один поток, сколько бы процессоров не было на машине.

Единственное, для чего можно использовать ruby и python — это мелкие скрипты, которые уже тяжело написать на sh/grep/sed/awk, и которые кроме автора никто не увидит. Потому что когда reportbug в дебиане падает с бектрейсом — это пиздец. Когда reportbug-ng падает вслед за ним — это ёбаный стыд. Когда irc-бот сжирает 130 мегабайтов оперативной памяти — это что-то нереальное.

Ребят, написали скриптик на питоне — никому его не показывайте. Написали сайтик на руби — сидите и радуйтесь, пока трафик не пришел. И не вздумайте никуда ничего коммитить. Я не хочу имел дел с вашими поделками.

См. также

Плох ли XML?

Я перенес это в отдельную статью.

Для чего нужна сильная типизация?

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

Вот игрушечный пример на окамле. Допустим, мы решили изобрести булевский тип:

type bool = True | False

И теперь напишем функцию, которая будет выводить его на экран:

let print_bool = function
  | True  -> printf "true"
  | False -> printf "false"

А теперь чуть изменим определение нашего «булева», но функцию для вывода на экран менять не будем:

type bool = True | False | Maybe

В этом случае функция уже не будет корректно работать на всех диапазонах значений, поскольку не обрабатывает случай с Maybe. И компилятор укажет нам на это:

let print_bool = function
  | True  -> printf "true"
  | False -> printf "false"
Warning P: this pattern-matching is not exhaustive.
Here is an example of a value that is not matched:
Maybe
val print_bool : bool -> unit = <fun>

Вот и все. Ошибка обнаруживается на этапе компиляции.

Теперь по прежнему простой, но уже боевой пример. Вот это декларация типа из кода xmlfuzzer’а, который разбирает XML-схемы:

type term =
  | Elt of element_declaration
  | Model of model_group (* Missing: annotation *)
  | Wildcard of wildcard
and model_group =
  | All      of particle list
  | Choice   of particle list
  | Sequence of particle list

Как видите, я выбросил annotation’ы из типа, потому что для данной задачи они не нужны. Если же я захочу ввести их в декларацию, к примеру, как Model of (model_group * string), то старый код, который не обрабатывает annotation’ы, будет выдавать ошибки при компиляции. Например, для этого участка:

match part_term with
  | Elt e               -> ...
  | Model (Choice   pl) -> ...
  | Model (All      pl) -> ...
  | Model (Sequence pl) -> ...
  | Wildcard wc         -> ...

для строк 3-5 будет выдано что-либо вроде:

Error: This pattern matches values of type model_group
       but a pattern was expected which matches values of type (model_group * string)

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

type attr =
  | Class    of string (* p(myclass).   *)
  | Id       of string (* p(#myid).     *)
  | Style    of string (* p{color:red}. *)
  | Language of string (* p[fr-fr].     *)
type phrase =
  | CData       of string
  | Emphasis    of (attr list * phrase list) (* _ *)
  | Strong      of (attr list * phrase list) (* * *)
  | Italic      of (attr list * phrase list) (* __ *)
  | Bold        of (attr list * phrase list) (* ** *)
  | Citation    of (attr list * phrase list) (* ?? *)
  | Deleted     of (attr list * phrase list) (* - *)
  | Inserted    of (attr list * phrase list) (* + *)
  | Superscript of (attr list * phrase list) (* ^ *)
  | Subscript   of (attr list * phrase list) (* ~ *)
  | Span        of (attr list * phrase list) (* % *)
  | Code        of (attr list * phrase list) (* @ *)
  | Acronym of string * string               (* ABC(Always Be Closing) *)
  | Image of attr list * string * string option (* !imgsrc(alt)! *)
  | Link of (attr list * phrase list) *
      string option * string (* "linktext(title)":url *)
type line =
  phrase list

Повторюсь, это только декларация типа для строки. Такая строка затем идет к функциям-принтерам, например, xhtml_of_textile или pdf_of_textile. Вы уверены, что сможете обработать все возможные случаи, ни один не упустив? А теперь представьте, что будет, если вы решите внести изменение в дерево — например, заменить CData of string на CData of char list. Вы уверены, что не забудете внести необходимые изменения во всех местах, где идет обработка текста?

О тестах

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

Естественно, сильная типизация не исключает всех ошибок, а тесты — это хорошо в любом случае. Но дело в том, что она исключает целый класс ошибок, и по сути работает как те же юнит-тесты, только на уровне компилятора.

Как именно писать код — решать вам. Но как по мне, рефакторинг без сильной типизации, алгебраических типов и паттерн-матчинга — это пытка. И после нее код все равно оказывается полным ошибок.

Так какие же инструменты — правильные? Что нужно использовать?

Не знаю.