Архив метки: erlang

Erlang rebar: как провести только определенный тест

Всегда это забываю, потом долго ищу.)
Итак, у нас модуль в src/et_http.erl, есть его тест test/et_http_tests.erl, тогда из консоли запустить только этот тест можно с помощью такой команды:

./rebar eunit skip_deps=true suites=et_http_tests

Erlang: быстрое получение времени от начала эпохи Unix в миллисекундах

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

-spec get_timestamp() -> integer().
get_timestamp() ->
  {Mega, Sec, Micro} = os:timestamp(),
  (Mega*1000000 + Sec)*1000 + round(Micro/1000).

Использование os:timestamp() вместо erlang:now() обуславливается более высокой скоростью работы первого.

Erlang: аналогии для понимания циклов

Пришел в голову интересный способ объяснения циклов на Erlang:

Пусть А – массив:

A = [1, 2, 3, 4, 5].

Надо пройтись по каждому элементу массива и увеличить его на 1. На обычных языках программирования это делается примерно так (python):

for i in range(len(A)):
   A[i] += 1

PHP

foreach ($A as $i=>$value)
    $A[i]++;

А теперь эквивалент на Erlang:

A2 = lists:map(
   fun(Elem) ->
      Elem + 1
   end, A).

На Erlang мы использовали анонимную функцию, которая в качестве аргумента принимает одно значение и возвращает его, увеличенным на 1. Также мы ввели новый массив A2, т.к. на Erlang нельзя переопределять единожды присвоенное значение переменной. Да, по сути в Erlang переменных нет =), потому и нет классических циклов. Поэтому для реализации циклов используют или рекурсию, или проход по элементам списка с помощью функций lists:map/2, lists:foldl/3 и др.

Erlang -> Rebar: Release xxx uses non existing application xxx

Для сборки и экспорта на практически любую платформу erlang-приложения очень удобно использовать утилиту rebar. Раньше я уже использовал этот инструмент и захотел его использовать вновь для одной своей программы и, делая всё точно также, тем не менее при финальной сборке проекта натыкался на одну и ту же ошибку:

Release xxx uses non existing application xxx

Оказалось, что корневую папку необходимо называть так же, как и само приложение, т.е. в моем примере структура проекта должна была быть такая:

xxx/
   /src/
   /ebin/
   /rel/
   rebar.config

Я же назвал корнвую папку («xxx») по-другому (скажем, «yyyyy») и поэтому сборщик не находил приложение с таким именем.

Потратил на это более получаса, поэтому вопрос стоит записи.

UP.: встретил статью, в которой подробно описывается, почему так всё происходит. Рекомендуют посмотреть в сторону другого сборщика erlang-проектов – sinan.

Для каждого языка программирования свои задачи, или выводы «9 лет спустя»

Окидывая взглядом последние 9 лет практики программирования, я пришел к ряду интересных и, думаю, полезных выводов. Свою историю изучения языков программирования (далее «ЯП») проиллюстрировал ниже. Где-то отметил фреймворки на этих ЯП. Отмеченные фреймворки, как правило, давали новую мотивацию и открывали новые горизонты в изучении и использовании этих ЯП.

Языки программирования по жизни

Языки программирования по жизни

Вывод 1: для разных классов задач – разные языки программирования

В действительности, достаточно хорошо изучив какой-либо язык, кажется, что на нём надо писать не только профильные приложения. Но будьте осторожны! На этом пути вы можете впасть в состояние «вбивания гвоздей микроскопом». Так рождаются демоны (постоянно висящие процессы, типа серверов) на PHP, веб-сервера на JavaScript, веб-приложения на C++ и прочее. В качестве эксперимента – это прекрасно, но всё становится гораздо ужасней, когда что-то в силу своей популярности в другой области становится частым решением в других.

Хорошим примером иллюстрирующим первый вывод является node.js и Erlang. На node.js с радостью накинулось большое число веб-разработчиков, ведь все знают JavaScript! Попробовав домашние проекты на этой платформе, многие начали использовать node.js в реальных проектах и в итоге столкнулись с большими проблемами, решение которых затрачивало всё больше сил. Например, отказоустойчивость таких приложений. Стоит вылезть ошибке в одном из потоков выполнения, и весь сервер падает, если только вы не оградились везде, где только можно try-catch блоками. Или горизонтальное масштабирование. Тут вообще беда. И рождаются костыли-костыли-костыли.

Другое дело Erlang, который изначально «by-design» создавался для больших телекоммуникационных систем. Писать на нём серверное приложение — сплошное удовольствие. Хотите постоянно работающий сервер, которым можно управлять по telnet? Да легко! Держите встроенный пакет gen_tcp. Горизонтальное масштабирование существующего приложения? Вам скорей всего придется поменять пару строчек, где описывается передача сообщений другим функциям, — добавить в них отправку сообщений на другие ноды. Тоже и с отказоустойчивостью (привет супервизорам), обработкой бинарных данных и пр. пр.

Вывод 2 – не упускайте возможности изучать новые ЯП и/или их популярные фреймворки

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

Существует две основные когорты ЯП:

  1. Си-подобные: С++, С#, Java, PHP, JavaScript, ActionScript и др.
  2. LISP-подобные: Erlang, Python, Ruby, Perl и др.

Если вы знаете хотя бы один язык из каждого класса, то считайте, что вы знаете и все остальные ЯП.) Исключениями можно считать Assembler и языки-приколы, типа Brainfuck. Кстати, часто различить эти классы ЯП можно по наличию/отсутствию кортежей и обрамлению условных операций и циклов в фигурные скобки.

Я не стал разбивать на группы ООП, функциональные и процедурные парадигмы программирования, т.к. по большому счету почти любой подход можно использовать почти в любом языке (например, функциональный подход в Java). Другое дело, что язык изначально для этого не создавался (см. вывод 1;-) и такие извороты выглядят крайне противоестественно. Исключение Python. Он изначально разрабатывался мульти-парадигмальным.

Мой топ-рейтинг открытий типа: «А-а-а! Так вот с помощью чего это надо было делать!»:

1.  Zend Framework (на PHP)

Ну нафига я писал свою глючную библиотеку для работы с БД? О боги, а зачем я каждый раз придумывал новую архитектуру для каждого нового веб-приложения? MVC, Zend_Db, Zend_Action даруют возможность писать веб-приложения быстрее, а код делать надежным!

2.  Erlang

Боже! Ну почему я потратил кучу времени на написание этого простого демона на Java, если в Эрланге это можно было сделать парой десятков строчек, да и работало бы безотказно, да и масштабировать было бы проще!

3.  Octave

Так, надо бы быстрое преобразование Фурье… О, Matlab! Ну что, пошли на страшное преступление в ближайший торрент-трекер. Хотя ладно, вот есть бесплатная библиотечка для любимого PHP. Эхх…что-то как-то всё грустно и медленно. Octave? Octave… Octave! Мега-удобный синтаксис работы с матрицами, встроенные функции для кучи математических задач, да тут еще и графики с пол пинка строятся! Да оно еще совместимо с MatLab! А еще open-source!

4.  KnockoutJS (на JavaScript).

Как же мне надоели эти простыни с кодом, запутанная логика работы с объектами на странице, эти бесконечные onSomeEvent функции. Как бы хотелось MVC, но вот только на клиенте. Чтобы вот есть у тебя модель данных и при её изменении автоматически всё само менялось на странице. Добавил к ней объект «Задача», а на странице возьми и появись соответствующий блок для новой задачи.

KnockoutJS, как ты вовремя!

5.  Django (на Python)

Да-да, Zend Framework, ты не плох, но ты… рутинный. Каждый раз надо писать свою админку, прикручивать авторизацию, свои однотипные операции добавления, редактирования и удаления сущностей, расписывать формы ввода данных, писать однотипные виды для типичных задач, типа показа по 10 новостей на одной странице и разбивках остальных новостей по страницам. Copy-paste, copy-paste…

Ммм… что-то зачастили на хабре со своими дифирамбами во славу Django и Python.  Да давно уже поют, который год. Что ж они всё никак не угомонятся?) Ну попробуем и мы.

Так-так… значит я раскомментирую вот тут и вот тут, еще одна команда в консоли и… у меня готова полноценная админка?! Вы издеваетесь?) Так просто! А вот еще бы хотелось, чтобы в админке было удобно приписывать к разным авторам разные статьи, чтобы было красивая связь многим-ко-многим. Добавить одну строку в модель?! Ну-у, у вас совсем нет совести! Зачем же я столько времени тратил на эту рутину в зенде?»

Для этой записи хватит выводов, а то, ведь, до конца не дочитаете!) Оставим еще парочку на будущее.)

CouchDB: группировка данных по родительскому элементу

При разработке своего одного приложения (скоро анонсирую!) я использовал в качестве БД Apache CouchDB, точнее использовал его чуть более продвинутую версию от коммерческой организации – CouchBase. В этом посте я привожу решение нередкой, но нетривиально решаемой задачи (нетривиально для людей, не знакомых до этого с NoSQL).

Задача

Возврат сгруппированных значений по родительскому элементу.

В БД обычно данные хранятся в примерно таком формате:

{
   "_id": "256b9dd4492210351c9db34ee500d817",
   "_rev": "1-94366c1d2b7a075f33ebbd7a96565f4b",
   "url": "http://surdoserver.ru",
   "status": 200,
   "timestamp": 1969072012,
   "ping": 332
}
{
   "_id": "256b9dd4492210351c9db34ee500f288",
   "_rev": "1-1770b12a395ca76887c792e5c1d99f8f",
   "url": "http://surdoserver.ru",
   "status": 200,
   "timestamp": 1969073012,
   "ping": 220
}
и т.д.

Нам же необходимо получить статистику по каждому сайту без дублирования информации, то есть что-то типа такого:

{
   "url": "http://surdoserver.ru",
   "data":
   [
      "status": 200,
      "timestamp": 1969072012,
      "ping": 332
   ],
   [
     "status": 200,
     "timestamp": 1969073352,
     "ping": 220
   ]
}

Читать далее

Erlang: couchbeam rebar compile problem [SOLVED]

Всю жизнь писал я на обычных C-like языках (C++, php, Java, JS и пр.). Это довольно интересно, но выучив пару таких ЯП, понимаешь, что дальше все будет тоже самое. Поэтому в познавательно-развлекательных целях увлекся я функциональным языком программирования Erlang.

Сам язык очень интересный, позволяет писать железобетонные сервера с постоянными подключениями (готовимся к html5 sockets %) ), имеет необычный функциональный синтаксис, близкий к математическим выражениям, и т.д. В ближайшем будущем напишу о нем по-подробней и представлю небольшой проект, который я на нем пишу.

В моем приложении используется внешняя библиотека для работы с БД CouchDB – Couchbeam, которая в свою очередь требует еще пару библиотек.

Оказалось, в среде erlang есть аналог Maven (приложение для сборки всех зависимостей) – rebar. Неплохой мануал по теме есть на Хабре.

Чтобы настроить rebar на автоматическое скачивание и компиляцию couchbeam, в файле rebar.config пишется примерно следующее:

%% Здесь будут лежать зависимости
{deps_dir, ["deps"]}.

%% Поддиректории, в которые rebar должен заглядывать
{sub_dirs, ["rel"]}.

%% Список зависимостей
{deps,
[
{couchbeam, ".*", {git, "http://github.com/benoitc/couchbeam.git", "master"}}
]}.

Для непосредственного скачивания зависимостей выполняем

./rebar get-deps

а для компиляции

./rebar compile 

Вот тут-то и появилась ошибка на которую я убил не меньше часа:

./rebar compile
...
==> mochiweb (compile)
ERROR: compile failed while processing /Users/dimitry/Documents/workspaces/eclipse-java/site_stater/deps/mochiweb: {'EXIT',{function_clause,[{filelib,wildcard,[{"R14","c_src/*.c"}]},
                          {rebar_port_compiler,expand_sources,2},
                          {rebar_port_compiler,compile,2},
                          {rebar_core,run_modules,4},
                          {rebar_core,execute,4},
                          {rebar_core,process_dir,4},
                          {rebar_core,process_each,5},
                          {rebar_core,process_dir,4}]}}
 

Оказалось, все дело в файле конфигурации rebar (rebar.config) библиотеки ejson, для которой необходим сервер mochiweb. Для того, чтобы все нормально скомпилировалось, необходимо закомментировать первую строку:

%%{port_sources, [{ "R14", "c_src/*.c"}, {"R14", "c_src/yajl/*.c"}]}.

Точного описания директивы я так и не нашел, но, судя по всему, она указывает, откуда брать NIF (модули, написанные на C) для компиляции.
После её комментирования все компилируется, как по волшебству.)

UPDATE
Разобрался, в чем было дело: я пытался собираться проект основной версией rebar (из github), а нужна была та, что поставлялась в архиве с couchbeam. В этой версии есть компиляция Сишных модулей в erlang, видимо это улучшение где-то в pull коммитах. К сожалению, у этого проекта нет версий, поэтому и возникла такая ситуация.