Основы
Инструкции по установке для всех ОС есть на официальном сайте.
После того, как Elixir установлен, вы с лёгкостью можете проверить, какая именно версия была установлена.
% elixir -v Erlang/OTP > [erts->] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace] Elixir >
Интерактивный режим
Вместе с языком в комплекте идет приложение интерактивной командной строки IEx, которое позволяет выполнять выражения языка на лету.
Для того чтобы начать, запустите iex :
Erlang/OTP > [erts->] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace] Interactive Elixir (>) - press Ctrl+C to exit (type h() ENTER for help) iex>
Примечание: В Windows PowerShell вам нужно написать iex.bat .
Попробуем написать несколько простых выражений:
iex> 2+3 5 iex> 2+3 == 5 true iex> String.length("The quick brown fox jumps over the lazy dog") 43
Не стоит волноваться, если пока вы поняли не все выражения.
Базовые типы
Целые числа
iex> 255 255
Поддерживаются также бинарные, восьмеричные и шестнадцатеричные числа:
iex> 0b0110 6 iex> 0o644 420 iex> 0x1F 31
Числа с плавающей запятой
В Elixir числа с плавающей запятой требуют наличия хотя бы одной цифры перед точкой. Также они поддерживают e для описания экспонентной части:
iex> 3.14 3.14 iex> .14 ** (SyntaxError) iex:2: syntax error before: '.' iex> 1.0e-10 1.0e-10
Логический тип
Elixir поддерживает два значения логического типа: true и false . Абсолютно все значения в языке считаются истинными кроме false и nil :
iex> true true iex> false false
Атомы
Атом — константа, название которой является и значением. В других языках (например, в Ruby) они называются символами:
iex> :foo :foo iex> :foo == :bar false
Стоит отметить, что булевы значения true , false являются атомами :true и :false .
iex> is_atom(true) true iex> is_boolean(:true) true iex> :true === true true
Названия модулей в Elixir — тоже атомы. MyApp.MyModule — валидный атом, даже если такой модуль ещё не был объявлен.
iex> is_atom(MyApp.MyModule) true
Также атомы используются в качестве ссылок на модули из библиотек Erlang, в том числе и встроенные.
iex> :crypto.strong_rand_bytes 3 23, 104, 108>>
Строки
Строки в Elixir всегда представлены в кодировке UTF-8 и заключаются в двойные кавычки:
iex> "Hello" "Hello" iex> "dziękuję" "dziękuję"
Строки могут включать разрывы и экранированные последовательности:
iex> "foo . > bar" "foo\nbar" iex> "foo\nbar" "foo\nbar"
В Elixir есть и более сложные типы данных. Мы узнаем о них больше, когда познакомимся с коллекциями и функциями.
Базовые операторы
Арифметика
В Elixir, ожидаемо, есть базовые операторы + , — , * , / . Стоит отметить что результатом вызова / всегда будет число с плавающей запятой:
iex> 2 + 2 4 iex> 2 - 1 1 iex> 2 * 5 10 iex> 10 / 5 2.0
Если нужно целочисленное деление или получение остатка — в языке есть две удобные функции специально для этого:
iex> div(10, 5) 2 iex> rem(10, 3) 1
Логические операторы
Elixir предоставляет операторы || , && , ! , которые поддерживают работу с любыми типами:
iex> -20 || true -20 iex> false || 42 42 iex> 42 && true true iex> 42 && nil nil iex> !42 false iex> !false true
Также есть три дополнительных оператора, у которых первый аргумент обязан быть логического типа ( true или false ):
iex> true and 42 42 iex> false or true true iex> not false true iex> 42 and true ** (ArgumentError) argument error: 42 iex> not 42 ** (ArgumentError) argument error
Примечание: операторы and и or в Elixir на самом деле соответствуют andalso и orelse в Erlang.
Сравнения
В Elixir поддерживаются все стандартные операторы сравнения: == , != , === , !== , = , < , >.
iex> 1 > 2 false iex> 1 != 2 true iex> 2 == 2 true iex> 2 3 true
Для строгого сравнения целых чисел и чисел с плавающей запятой используется === :
iex> 2 == 2.0 true iex> 2 === 2.0 false
Удобной возможностью языка является то, что любые типы сравнимы друг с другом. Это удобно при сортировках. Порядок не стоит запоминать, но о его существовании стоит знать:
number atom reference function port pid tuple map list bitstring
Это приводит к некоторым интересным правильным сравнениям, которых обычно нет в других языках программирования:
iex> :hello > 999 true iex> :hello, :world> > [1, 2, 3] false
Интерполяция строк
Если вы использовали язык Ruby, то интерполяция в Elixir покажется вам знакомой:
iex> name = "Sean" iex> "Hello #name>" "Hello Sean"
Объединение строк
Для объединения двух строк используется оператор <> :
iex> name = "Sean" iex> "Hello " <> name "Hello Sean"
Почему я ставлю на Elixir
6 лет я создавал приложения на языке Ruby и фреймворке Rails. Я щупал всякие новые языки программирования по мере их выхода, но Elixir – первый из них, который меня действительно увлёк.
В своё время Ruby уделал всех
Язык Ruby и фреймворк Rails полностью поменяли способ создания веб-приложений. Они дали начало религии ценностей для сообщества программистов. Они первые предложили идею, согласно которой инструменты программиста должны быть оптимизированы для продуктивной и радостной разработки.
Именно они постулировали, что задача тестирования и доведения кода до работоспособного состояния лежит на разработчиках. Другие языки и фреймворки насмехались над таким подходом, пока он не начал завоёвывать популярность. После этого они стали включать принципы, присущие сообществу Ruby, в другие языки и фреймворки.
Ruby прошёл путь от скромного положения невразумительного языка до одного из самых популярных языков, в основном из-за фреймворка Rails и огромного лидерского потенциала таких людей, как DHH, Wycats, Aaron Patterson, Jose Valim и множества других. Но периодически, и тут и там начинают вылезать артефакты, оставшиеся из-за такого скромного старта языка.
Убегающая память
Зед Шо [Zed Shaw] в посте «Rails – это гетто» разглагольствует на тему проблем со сборкой мусора, из-за которых первые приложения на Rails перезапускались каждые 4 минуты.
Один из самых популярных серверов для Rails сегодня – это unicorn. Моё веб-приложение – это приложение для Rails, оно довольно простое, по сравнению с другими приложениями, которые я разрабатывал. Я перенёс его на сервер с 512 Мб памяти, и после нескольких дней работы мой unicorn съел всю доступную память и приложение начало тормозить.
Решение? unicorn-worker-killer. Не слишком отличается от более ранних решений.
Мой сервер способен обслужить два потока unicorn, забирающих большинство ресурсов, базу данных Postgres и несколько других приложений. Отзывается он, правда, довольно быстро, поэтому работу свою делает.
Параллелизм
Хотя я занимаюсь разработкой приложений для Rails уже несколько лет, я ни разу не использовал дополнительные потоки в приложениях для продакшена. Сам по себе Rails нормально работает с потоками, но по моим ощущениям, от них возникают одни лишь проблемы – я пробовал использовать их в Java, C++ и других ООП-языках.
Суть в том, что я не хочу задумываться про мьютексы, семафоры, и всяком таком. Если я буду останавливать один поток, чтобы дать другому поработать, не особенный-то это будет параллелизм. И ещё — вы точно-точно уверены, что исполнение вашего кода не приводит к взаимным блокировкам?
Тестирование – главная парадигма сообщества Ruby, поэтому неудивительно, что большинство рубистов не трогают многопоточность, поскольку её практически невозможно тестировать, а её баги очень сложно воспроизводить.
Как и большинство нормальных разработчиков, я использую sidekiq или resque для обработки вещей в параллели. В Rails 2.2 добавили безопасность для потоков, но в Rails 4.2 добавили Active Job API, которое оказалось гораздо более полезным.
Но процессы, выполняемые в фоне, нужно выполнять в фоне. А критичные вещи нужно выполнять в главном процессе – чтобы можно было среагировать на ошибку или проследить, что все транзакции были успешно завершены, перед тем, как завершать задачу.
Скорость
Я эгоист и ценю своё время очень сильно. Поэтому скорость тестов меня волнует. Я много времени тратил на оптимизацию быстродействия моего набора тестов, не делая изменений в архитектуре приложения и не внося в дизайн разрушений из-за этого.
Какое-то время выполнение функциональных и юнит-тестов у проекта, над которым я работал, занимало порядка 20 минут. Я использовал hydra для распределённых тестов, но мне всегда было сложно сделать так, чтобы тесты проходили (скорее всего, из-за слишком сложного и не особо красивого кода).
Даже запуск тестов занимал секунд 40. Вы когда-нибудь ждали 40 секунд, только чтобы увидеть: “syntax error, unexpected end-of-input, expecting keyword_end”, или ещё такую же ерунду? А я ждал.
Что делать? Zeus. Прекрасный gem, которая предварительно загружает всё необходимое для приложения и может загрузить (согласно описанию на github) любое приложение для Rails за секунду. Он мне нравится, и я рекомендую его всем.
Но как они достигли такого быстродействия? Просто написали его на Go.
Scala
Пару лет назад я обрадовался появлению Scala. Потом я начал её использовать – и ненавидеть.
У неё есть много концепций из функционального программирования. Фреймворк akka позволяет писать надёжные приложения. Она запускается в JVM, поэтому может использовать любую библиотеку из Java, а JVM очень хорошо обработана на предмет быстродействия.
Сам язык приятный. Но что меня остановило? JVM. Управление пакетами jar слишком сложное, если сравнить его с Rubygems и Bundler.
Есть, конечно, всякие решения: SBT, Maven, Ivy,- но все они заставляют меня морщиться, когда мне нужно импортнуть чью-либо чужую библиотеку. Может, Ruby меня испортил, но управление пакетами в нём – одна из основных причин моей продуктивности.
Что меня ещё напрягало в Scala, так это что используемые мною библиотеки были написаны на Java людьми, чьи ценности и установки сильно отличались от моих.
Создание веб-приложения на Scala в фреймворке Play! выглядело так же, как создание веб-приложения на Java в фреймворке Play!, кроме чуть более простого синтаксиса и возможности поиска шаблонов. Хотя Rails сильно повлиял на Play!, разница между ними чувствуется интуитивно.
Экосистема Elixir
Управление пакетами через Mix
Впервые погрузившись в Elixir, я наткнулся на Mix. Это гибрид Bundler и Rake в Ruby. Что мне в нём так нравится – это то, что он не хуже, чем Bundler и Rake. Он и не сильно лучше, но планка поднята достаточно высоко и подняться до неё – это уже достижение.
Mix делает свою работу прекрасно, не мешается под ногами, и не заставляет вас возиться с XML.
Виртуальная машина Erlang
Elixir работает в виртуальной машине Erlang, и поддерживает почти все ценности сообщества Erlang. Elixir и Erlang гордятся фокусировкой на функциональном программировании, которое устойчиво к ошибкам и хорошо масштабируется.
- на Erlang работает 50% сетей телекоммуникационных компаний. Когда у вашего телефона в последний раз был перерыв на «запланированное обслуживание»?
- у WhatsApp, купленного за миллиарды денег, миллионы процессов работали на одном серваке, который поддерживал 450 миллионов пользователей – и всё это работало под управлением 32 инженеров
Веб-фреймворк Phoenix
На phoenix framework, очевидно, сильно повлиял Ruby on Rails, и создание веб-приложения для Phoenix выглядит очень похоже на создание приложения для Rails. Мне нравится роутер у Rails. А также ActionController, ActiveRecord, Rails Views и способ, каким вы можете программировать приложение. Мне нравится организация приложений в Rails.
Phoenix так похож на Rails, что вам покажется, будто вы делаете приложение для Rails, кроме того, что оно будет работать под Elixir и иметь все преимущества Elixir и виртуальной машины Erlang.
Кроме этого, он поддерживает WebSockets через каналы. Это позволяет вам легко использовать WebSockets, предоставляемые в Firebase.
А я говорил о том, что он быстр? Он быстр, как молния. Взгляните на логи с моего сервера на DigitalOcean стоимостью в $5/мес. Да, да – запросы обрабатываются за микросекунды на одноядерной машине.
Лидерство
По моему мнению, разница между просто открытым кодом и движением заключается в лидерстве, присутствующем в проекте. Короче, чтобы софт ежедневно улучшался, нужно, чтобы свою лепту в него вносили очень умные люди.
Движение Rails приобрело такой большой импульс, благодаря работе DHH, Aaron Patterson, Jose Valim, Wycats и кучи других. Не было такого, чтобы запустили первую версию Rails и работа встала.
Это всё старая привычка много работать – а построение грамотного сообщества требует большой работы. Jose Valim, Chris McCord, и все остальные члены основных команд Elixir-Lang и Phoenix работали и продолжают работать над процветанием их сообщества.
Веб ждут великие преобразования
Признайте – CRUD-приложения на сегодняшний день являются товаром. Следующий стартап «AirBnB для аренды кетчупа» скорее всего не выживет.
Победят те, кто примут изменения в технологиях. То, что в WebSockets, процессы и параллелизм в Phoenix и Elixir легко достижимы, и из-за них не надо поступаться лёгкостью программирования, просто меняет всё дело.
Я очень люблю Ruby on Rails. Он поменял способ создания веб-приложений в годах 2005–2014. Думаю, что Elixir и Phoenix произведут такой же эффект в годах 2015–2025.
Если вы уже хотите начать делать веб-приложения на Phoenix и Elixir, вот вам мой тьюториал.
- Веб-разработка
- Программирование
- Erlang/OTP
- Ruby on Rails
- Elixir/Phoenix
Что такое Эликсир?
Эликсир – динамический функциональный язык программирования, предназначенный для создания масштабируемых и поддерживаемых приложений.
Пришло время прояснить человеческую суть, лежащую под этим википедизмом.
Начнём с конца. На Эликсире пишут приложения. О, как! Они написаны настолько понятно, что становится легко добавлять новые возможности и сопровождать их в эксплуатации. Благодаря простому синтаксису и правильным идеям в основе языка, понять незнакомый проект на Эликсире не составляет труда. Другими словами, приложения являются легко поддерживаемыми.
Каждый отдельный кусочек кода такого приложения обрабатывается в отдельном процессе – маленькой подпрограммке внутри виртуальной машины Эрланга, поверх которой и работает Эликсир. Этой машине без разницы, запущен процесс на текущем сервере или же на сервере в другом дата-центре. Пропишите явки с паролями в конфигурацию, и инфраструктура языка сама разберётся, как связать эти части в распределённую сеть. Это называется горизонтальным масштабированием.
Под словом динамический подразумевается динамическая типизация. Это не значит, что строки складываются со списками – тут произойдёт ошибка. Типизация хоть и динамическая, но строгая. Типы в Эликсире просто не указываются явно – компилятор сам разберётся что к чему.
Осталось разъяснить последний термин, что же такое ф…
– А что такое функциональный язык? – нетерпеливый читатель.
…ункциональный язык программирования. Как раз об этом расскажем дальше.
Функциональное программирование
Парадигма, которой придерживаются языки программирования, – вещь туманная. Любой язык относится к главной парадигме, например, объектно-ориентированной, при этом дополнительно использует особенности других парадигм. Привычная практика программирования тесно связана с классами, объектами, прототипами и процедурами. Работа с этими абстракциями предполагает изменение внутреннего состояния компонентов системы. Из-за таких изменений бывает, что методы одного и того же класса, дают разный результат. Виновата в этом инкапсуляция.
Инкапсуляция позволяет хранить данные внутри объектов вместе с методами для работы с ними. Изменяя состояние данных, изменяется результат выполнения методов. Такая ситуация называется побочным эффектом – вроде подаём на вход метода одно и то же, а на выходе получаем разный результат. Становится сложно разобраться с таким кодом при отладке.
Спасают нас чистые функции, работа которых достигается неизменяемостью данных, говоря на сленге – иммутабельностью. В чистых функциях при одинаковом входе воспроизводится одинаковый выход. В качестве примера, возьмём реализацию хеш-функции MD5: если сто раз подадим на вход строку Elixir , то сто раз получим в ответ a12eb062eca9d1e6c69fcf8b603787c3 . Без вариантов.
Добиться такого кода можно, отказавшись от инкапсуляции. Было бы странно отказываться от объектно-ориентированных механизмов в объектно-ориентированном языке. Куда разумнее перенестись в функциональную плоскость и отдать решение задачи функциональному языку.
Основная часть сообщества Вунш – разработчики сетевых приложений. Как минимум, мы работаем с сетевыми протоколами, как максимум, пишем фуллстек веб-приложения. Значит искать нужно среди функциональных языков, заточенных под сетевую работу с прицелом на веб.
Под этот критерий точно подходит Эрланг, благодаря OTP – фреймворку для создания распределённых сетевых приложений (говоря грубо). Мешает одна проблема, язык застыл в прошлом (позапрошлом?) десятилетии, а главные изменения нужны в первую очередь мейнтейнерам, а не разработчикам его использующим.
Почему не Эрланг?
В диком мире можно встретить самых настоящих эрлангистов. Более того, свежая кровь до сих пор приходит в Эрланг, но не в том количестве, чтобы выстраивать современную экосистему вокруг языка. На помощь пришёл рубист со стажем – Жозе Валим, и решил провести ребрендинг.
Эликсир можно назвать Эрлангом 2.0. Помимо надёжности прародителя, в Эликсире:
- появилась экосистема под современные нужды: пакетные менеджеры, инструменты выполнения задач, фреймворк для тестирования и т.п.;
- улучшился синтаксис – порог вхождения снизился;
- началась кампания по пиару «свежего» языка для оживления сообщества;
- упростилось метапрограммирование;
- устранились некоторые недостатки, например, работа со строками;
- были написаны новые полезные абстракции и надстройки.
Эликсир всё ещё продолжает искать себя, и как только он встанет на ноги, отличий станет ещё больше.
Почему функциональные языки снова становятся популярными?
Помимо всех перечисленных особенностей и преимуществ Эликсира, функциональные языки снова становятся популярными благодаря распространению и удешевлению многоядерных процессоров. Говоря простым языком, на них отлично параллелится код в функциональном стиле. Особенно, если этот код запущен на виртуальной машине Эрланга.
Сравнение с конкурентами
Каждый язык старается занять свою нишу. Го и Раст – фантастические по скорости языки, они обгоняют в том числе и Эликсир. Однако сфера применения каждого из них разнится. Раст – системный язык программирования для решения низкоуровневых задач. Вряд ли на нём получится быстро написать отказоустойчивый бэкенд для приложения реального времени.
Сравнивать Эликсир с Го немного сложнее – они похожи. Начнём с того, что Го более низкоуровневый, чем Эликсир. Приготовьтесь, что вам придётся писать много кода с нуля. Го подходит для написания веб-микросервисов, как и Эликсир, однако второй из них гораздо лучше справится с группами микросервисов объединенными в одну систему. Го отлично подойдёт для конкретных небольших задач, в которых важна производительность. Эликсир же поможет легко написать распределённые веб-приложения с элементами реального времени.
А если нужна повышенная надёжность работы системы, то Эликсир точно ваш выбор – ему не страшны ошибки и падения, т.к. в языке существуют механизмы для обработки подобных ситуаций. Написать безопасный конкурентный код на другом языке программирования – та ещё задача.
С чего начать?
Надеемся, вас впечатлил Эликсир, и вам не терпится его попробовать. Предлагаем реализовать живую распределённую «записную книжку» на Эликсире. Таким образом, вы сможете пощупать Эликсир и познакомиться с его ключевыми возможностями на практике. Ответы на многие вопросы вы сможете найти в документации, а также в любой момент обратиться к статьям, которые мы регулярно переводим.
Удачи в изучении!
P. S. И не забудьте подписаться на нашу почтовую рассылку. Всё самое интересное мы пишем именно туда.
© 2020 / Россия Любые мысли и вопросы пишите на [email protected].
Ламповая рассылка про Эликсир
Один-два раза в неделю присылаем тёплые письма об Эликсире: переводы самых интересных статей до их появления в открытом доступе, анонсы событий и вкусные бонусы.
Обязательно подтверди почту, перейдя по ссылке в письме, иначе мы не сможем делиться с тобой полезностями.
Надоедать точно не будем 🙂
При подготовке материала использовались источники:
https://elixirschool.com/ru/lessons/basics/basics/
https://habr.com/ru/articles/269477/
https://wunsh.ru/elixir