Подтвердить что ты не робот

Проектирование больших проектов в OCaml

Что такое лучшие практики для написания больших программных проектов в OCaml?

Как вы структурируете свои проекты?

Какие функции OCaml следует и не следует использовать для упрощения управления кодом? Исключения? Первоклассные модули? GADTs? Типы объектов?

Сборка системы? Тестирование? Стек библиотеки?

Я нашел отличные рекомендации

4b9b3361

Ответ 1

Я собираюсь ответить за проект среднего размера в условиях, которые мне знакомы, то есть между 100 КБ и 1М строк исходного кода и до 10 разработчиков. Это то, что мы используем сейчас, для проекта, начатого два месяца назад в августе 2013 года.

Создание системы и организация кода:

  • одна исходная оболочка script определяет PATH и другие переменные для нашего проекта
  • один файл .ocamlinit в корне нашего проекта загружает кучу библиотек при запуске сеанса toplevel
  • omake, который является быстрым (с опцией -j для параллельных построений); но мы избегаем создания сумасшедших пользовательских плагинов omake.
  • один корень Файл Makefile содержит все основные цели (настройка, сборка, тестирование, очистка и т.д.)
  • один уровень подкаталогов, а не два
  • большинство подкаталогов встроены в библиотеку OCaml
  • некоторые подкаталоги содержат другие вещи (настройка, сценарии и т.д.).
  • OCAMLPATH содержит корень проекта; каждый подкаталог библиотеки создает META файл, делая все части проектов OCaml доступными из верхнего уровня, используя # require.
  • для всего проекта построен только один исполняемый файл OCaml (экономит много времени на соединение, все еще не уверен, почему)
  • библиотеки устанавливаются с помощью установки script с помощью opam
  • локальные пакеты opam создаются для программного обеспечения, которое не находится в официальном репозитории opam
  • мы используем переключатель opam, который является псевдонимом, названным в честь нашего проекта, избегая конфликтов с другими проектами на одной машине.

Редактирование исходного кода:

  • emacs с пакетами opam ocp-indent и ocp-index

Управление и управление источниками:

  • мы используем git и github
  • весь новый код просматривается через запросы github pull
  • tarballs для non-opam не-github-библиотек хранятся в отдельном репозитории git (который может быть удален, если история становится слишком большой)
  • Существующие на github библиотеки с кровоточием разворачиваются в нашу учетную запись github и устанавливаются через наш собственный локальный пакет opam.

Использование OCaml:

  • OCaml не будет компенсировать плохие методы программирования; преподавание хорошего вкуса выходит за рамки этого ответа. http://ocaml.org/learn/tutorials/guidelines.html является хорошей отправной точкой.
  • OCaml 4.01.0 делает намного проще, чем раньше, для повторного использования меток полей полей и конструкторов вариантов (т.е. type t1 = {x:int} type t2 = {x:int;y:int} let t1_of_t2 ({x}:t2) : t1 = {x} теперь работает)
  • мы стараемся не использовать расширения синтаксиса camlp4 в нашем собственном коде
  • мы не используем классы и объекты, если это не предусмотрено какой-либо внешней библиотекой
  • в теории, поскольку OCaml 4.01.0, мы должны предпочесть классические варианты над полиморфными вариантами.
  • мы используем исключения, чтобы указывать на ошибки, и пусть они проходят счастливо до тех пор, пока наш основной цикл сервера не поймает их и не интерпретирует их как "внутреннюю ошибку" (по умолчанию), "плохой запрос" или что-то еще
  • исключения, такие как Exit или Not_found, могут использоваться локально, когда это имеет смысл, но в интерфейсах модулей мы предпочитаем использовать параметры.

Библиотеки, протоколы, рамки:

  • мы используем батареи для всех товарных функций, отсутствующих в стандартной библиотеке OCaml; для остальных у нас есть библиотека "util".
  • мы используем Lwt для асинхронного программирования без расширений синтаксиса, а оператор привязки ( → =) является единственным оператором, который мы используем (если вам нужно знать, мы неохотно используем предварительную обработку camlp4 для лучшего отслеживания исключений при связывании точки).
  • мы используем HTTP и JSON для связи с сторонним программным обеспечением, и мы ожидаем, что каждый современный сервис предоставит такие API.
  • для обслуживания HTTP, мы запускаем собственный SCGI-сервер (ocaml-scgi) за nginx
  • как клиент HTTP, мы используем Cohttp
  • для сериализации JSON мы используем atdgen

"Облачные" услуги:

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

Тестирование:

  • У нас есть одна цель make/omake для быстрых тестов и одна для медленных тестов.
  • быстрые тесты - это единичные тесты; каждый модуль может обеспечивать "тестовую" функцию; файл test.ml запускает список тестов
  • медленными тестами являются те, которые включают запуск нескольких сервисов; они созданы специально для нашего проекта, но они охватывают как можно больше, как производственное обслуживание. Все работает локально либо в Linux, либо в MacOS, за исключением облачных сервисов, для которых мы находим способы не вмешиваться в производство.

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

Ответ 2

OASIS

Чтобы добавить к Павлу ответ:

Отказ от ответственности: я являюсь автором OASIS.

OASIS также имеет oasis2opam, который может помочь быстро создать пакет OPAM и oasis2debian для создания пакетов Debian. Это чрезвычайно полезно, если вы хотите создать цель "выпуска", которая автоматизирует большинство задач для загрузки пакета.

OASIS также поставляется с script под названием oasis-dist.ml, который автоматически создает tarball для загрузки.

Посмотрите все это в https://github.com/ocaml.org.

Тестирование

Я использую OUnit, чтобы выполнить все мои тесты. Это просто и довольно эффективно, если вы привыкли к тестированию xUnit.

Управление/управление источниками

Отказ от ответственности: Я являюсь владельцем/сопровождающим forge.ocamlcore.org(aka forge.o.o)

Если вы хотите использовать git, я рекомендую использовать github. Это действительно эффективно для обзора.

Если вы используете darcs или subversion, вы можете создать учетную запись на forge.o.o.

В обоих случаях наличие общего списка рассылки, в котором вы отправляете все уведомления о фиксации, обязательно, чтобы каждый мог их видеть и просматривать. Вы можете использовать либо группы Google, либо список рассылки на forge.o.o.

Я рекомендую иметь хорошую веб-страницу (github или forge.o.o) с сборкой документации OCamldoc каждый раз, когда вы совершаете. Если у вас огромная база кода, это поможет вам с самого начала использовать документацию, созданную OCamldoc (и быстро ее исправить).

Я рекомендую создавать tarballs, когда вы достигаете стабильной стадии. Не просто полагайтесь на проверку последней версии git/svn. Этот совет спас меня от работы в прошлом. Как сказал Мартин, сохраните все ваши tarballs в центральном месте (репозиторий git - хорошая идея для этого).

Ответ 3

Этот, вероятно, не полностью отвечает на ваш вопрос, но вот мой опыт в отношении среды сборки:

Я действительно ценю OASIS. Он имеет хороший набор функций, помогающий не только создавать проект, но и писать документацию и поддерживать тестовую среду.

Система сборки

  • OASIS создает файл setup.ml из спецификации (_oasis file), который работает в основном как здание script. Он принимает флаги -configure, -build, -test, -distclean. Я довольно привык к ним при работе с разными GNU и другими проектами, которые обычно используют Makefiles, и я считаю удобным, что здесь можно использовать все из них автоматически.
  • Makefiles. Вместо генерации setup.ml можно также создать Makefile со всеми описанными выше опциями.

Структура

Обычно мой проект, созданный OASIS, имеет как минимум три каталога: src, _build, scripts и tests.

  • В предыдущем каталоге все исходные файлы хранятся в одном каталоге: файлы источника (.ml) и интерфейса (.mli) хранятся вместе. Может быть, если проект слишком велик, стоит добавить дополнительные подкаталоги.
  • Каталог _build находится под управлением системы сборки OASIS. Здесь хранятся как исходные, так и объектные файлы, и мне нравится, что файлы сборки не мешают исходным файлам, поэтому я могу легко удалить их, если что-то пойдет не так.
  • Я храню несколько сценариев оболочки в каталоге scripts. Некоторые из них предназначены для выполнения тестов и создания файлов интерфейса.
  • Все файлы ввода и вывода для тестов, которые я храню в отдельном каталоге.

Интерфейсы/документация

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

Но главная причина, по которой мне нравятся интерфейсные файлы, - это документация. Я использую ocamldoc для создания (OASIS поддерживает эту функцию с флагом -doc) html страниц с документацией автоматически. На мой взгляд, достаточно написать комментарии, описывающие каждую функцию в интерфейсе, и не вставлять комментарии в середине кода. В OCaml функции обычно короткие и сжатые, и если есть необходимость вставлять туда дополнительные комментарии, возможно, лучше разделить функцию.

Также обратите внимание на флаг -i для ocamlc. Компилятор может автоматически генерировать файл интерфейса для модуля.

Испытания

Я не нашел разумного решения для поддержки тестов (я хотел бы иметь некоторое приложение ocamltest), поэтому я использую свои собственные скрипты для выполнения и проверки вариантов использования. К счастью, OASIS поддерживает выполнение пользовательских команд, когда setup.ml выполняется с флагом -test.

Я долгое время не использую OASIS, и если кто-нибудь знает какие-либо другие интересные функции, я также хотел бы узнать о них.

Кроме того, вы не знаете OPAM, это определенно стоит посмотреть. Без него установка и управление новыми пакетами - это кошмар.