IT FAQ
Разные очевидные вещи, которые все равно никто не понимает.
Чем плохи ruby и python?
Тем, что в их нынешнем состоянии они совершенно не годятся:
- для системных скриптов;
- для написания мультитредовых приложений и GUI;
- для чего-то вообще, что не будет выброшено после первого использования.
Во-певрых, у скриптовых языков беда с зависимостями. Если системный скрипт написан для 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
. Вы уверены, что не забудете внести необходимые изменения во всех местах, где идет обработка текста?
О тестах
Если вы используете язык с сильной типизацией, то компилятор укажет вам все места, где имеет место быть некорректная обработка типов. Если нет, то вам придется покрыть все тестами. И даже в коде с гигантским количеством тестов может закрасться ошибка.
Естественно, сильная типизация не исключает всех ошибок, а тесты — это хорошо в любом случае. Но дело в том, что она исключает целый класс ошибок, и по сути работает как те же юнит-тесты, только на уровне компилятора.
Как именно писать код — решать вам. Но как по мне, рефакторинг без сильной типизации, алгебраических типов и паттерн-матчинга — это пытка. И после нее код все равно оказывается полным ошибок.
Так какие же инструменты — правильные? Что нужно использовать?
Не знаю.