Пример реального проекта на F#

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

В экосистеме Майкрософт, F# занимает место экспериментального языка, удачные концепты из которого, впоследствии, переносятся в C#. Вместе с тем, во многом благодаря сообществу, фаршик стал реальной альтернативой для прикладных проектов. Под катом описаны ингредиенты бэкенда, фронтенда, тестов, сборки и инфраструктуры проекта, полностью написанного на F#. Исходный код прилагается.

Диаграмма контейнеров
Диаграмма контейнеров

SAFe

На выбор ингредиентов, определяющее влияние, оказал SAFe Stack. SAFe представляет собой шаблон dotnet CLI, в котором подобраны необходимые компоненты для гомогенной разработки SPA в связке с бэкэндом. Сайт проекта содержит много обучающих материалов и примеров.

SAFе облегчает старт для новичка. На первом этапе можно ничего не менять в шаблоне и сразу переходить к разработке функционала. По мере накопления опыта, вы, скорее всего, отойдете от SAFe. 

Первая буква акронима - ‘S’ - означает Saturn - идиоматический фреймворк над Giraffe, который, в свою очередь, функциональная обертка над Asp.net. 

Вторая буква - ‘A’ - означает Azure. Здесь мне было сразу не по-пути с SAFe, а тем, кто использует Ажур, как платформу, пригодится библиотека Farmer, которую пилят те же люди, что и SAFe.

Третья буква - ‘F’ - означает Fable - транспайлер из F# в JavaScript - настоящая сдобная булочка в экосистеме фарша.

Бэкенд

Для создания API используется библиотека Fable.Remoting. Fable.Remoting скрывает абстракции веб-сервера. Типы, определяющие контракт, помещаются в общий для бэкенда и фронтенда файл (или сборку). Реализовываете API на сервере, все остальное (создание прокси, сериализацию, обработку ошибок, логирование) делает за вас библиотека. Помимо JSON, поддерживается передача бинарных данных.

Сейчас, имея такой удобный инструмент, как Fable.Remoting, я не вижу смысла тянуть в бэкенд колбасу Saturn - Giraffe - Asp.Net. Но, по историческим причинам, в проекте остался Giraffe.

Если нужно использовать спецификацию OpenAPI, можно посмотреть на GiraffeGenerator.

В качестве хранилища данных, в проекте используется NoSql база DynamoDB. За основу реализации слоя доступа к данным была взята библиотека DynamoDb.Ok. В ней используется идиоматический подход на основе монады Reader. В итоге, могу сказать, что этот подход мне не понравился. В будущем хотелось бы вообще не отвлекаться на код в слое доступа к данным. Есть идеи, возможно, об этом выйдет отдельная статья.

C реляционными базами из F# работать не приходилось. В чате сообщества замечал нарекания на ограниченную поддержку типов F# в Entity Framework и рекомендации использовать Dapper.

В прошлом году сообщество обогатилось серией годных статей по теме внедрения зависимостей: статья 1, статья 2статья 3. Подход, базирующийся на Flexible Types, применяется и в данном проекте.

Для логирования используется библиотека Serilog, у которой есть расширение для Giraffe.

Для авторизации используется самописная реализация JWT.

Для связи с AWS частично используется дотнетовский AWSSDK, частично HTTP, так как SDK не покрывает весь функционал облака.

Фронтенд

Основа фронтендов на F# - Fable,  Ваш код и большая часть стандартной библиотеки переводится в JS. Можно легко взаимодействовать с библиотеками JS. Существует множество обвязок (binding) для популярных библиотек, в т.ч. React и его компонент.

Для управления состоянием используется Elmish - реализация Elm-архитектуры. Рендеринг страницы производится с помощью Fable.React и Bulma.

Разработка фронта в этой экосистеме доставляет.

пример кода
let quizView (dispatch : Msg -> unit) (settings:Settings) (quiz:QuizRecord) l10n = [
   br []
   figure [ Class "image is-128x128"; Style [Display DisplayOptions.InlineBlock] ] [ img [ Src <| Infra.urlForMediaImgSafe settings.MediaHost quiz.ImgKey ] ]
   br []
   h3 [Class "title is-3"] [str quiz.Name]
 
   div [Class "notification is-white"][
       p [Class "subtitle is-5"][
           match quiz.StartTime with
           | Some dt -> str (dt.ToString("yyyy-MM-dd HH:mm"))
           | None -> str "???"
 
           if quiz.Status = Live then
               str " "
               span [Class "tag is-danger is-light"][str "live"]
           br[]
       ]
 
       p [] (splitByLines quiz.Description)
 
       if quiz.EventPage <> "" then
           a[Href quiz.EventPage][str l10n.Details]
    ]
]

Отличное введение в экосистему - книга The Elmish Book.

Однако, фронтдендеры такие фронтендеры, связка Elmish + Fable.React + Boolma уже вышла из моды. В 2021 году, чтобы быть в тренде, вам нужно освоить Feliz + Fable.React.WebComponent + Material UI и рассмотреть альтернативу - Fable.Svetle. Моя бэкендер страдать.

Для взаимодействия с Aws, а именно с брокером сообщений в AppSync, используется библиотека Aws Amplify.

Тесты

Для проверки нефункциональных требований были реализованы нагрузочные тесты. Без использования сторонних решений (тянуть сюда JMeter показалось перебором). 

Модульные тесты не писались. Не могу не отметить то чувство защищенности, которое дает система типов F#. Глупые ошибки обычно отлавливаются компилятором. За все время эксплуатации проекта, словил всего один мажорный баг на проде. В других проектах использовал FsUnit и expecto. Первый проще встраивается в инструментарий, второй гибче в синтаксисе, но, как по мне, большой разницы между ними нет.

Из прочих решений для тестирования, в моем списке на попробовать:

  • FsCheck - для тестирование на основе свойств

  • Canopy - фреймворк и DSL для тестирования UI

  • NBomber - для нагрузочных тестов

Сборка и развертывание

Для управления пакетами используется Paket. Для сборки используется скрипт Fake. Оба инструмента входят в шаблон SAFe. Судя по обсуждению, в настоящее время есть какие-то проблемы в запуске фейковых скриптов и, в будущем, сборка будет выполняться из консольного приложения. В таком случае, вообще не вижу смысла в фейке.

Для обновления инфраструктуры и развертывания используется AWS Cloud Development Kit. Поддержка F# не заявлена, но идет из коробки, вслед за C#. 

Инструментарий

Хорошая новость. В SAFe сконфигурировано горячее обновление клиента и сервера в режиме разработки. К этому быстро привыкаешь и потом не понимаешь, как можно было работать по-другому.

Плохая новость. Инструментарий развивается, но он уступает тому, что есть в C#. Проект разрабатывается в VSCode с расширением Ionide. Подвисания, перезагрузки, регулярная необходимость удалять временные файлы - все это по-прежнему присутствует. Есть подозрение, что, в более крупных проектах, это может сильно испортить жизнь разработчику. Альтернативой Ionide является Rider. И там и там недавно вышли обновления, будем надеяться, что ситуация улучшится.

Помимо Ionide, используется расширение ILSpy, для того, чтобы понимать логику компилятора.

Также, работая с F# необходимо менять привычки отладки. Меньше пошаговой отладки, больше вывода в консоль. Использовать FSI.

Итого

По состоянию на начало 2021, F# пригоден для прикладных проектов небольшого и среднего размера. Для меня, преимуществами этого языка являются:

  • экосистема фронтенд-разработки,

  • система типов,

  • компактный синтаксис.

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

исходный код проекта

Картинка-поощрение для тех, кто дочитал эту статью до конца.
Картинка-поощрение для тех, кто дочитал эту статью до конца.

Источник: https://habr.com/ru/post/539370/


Интересные статьи

Интересные статьи

25 января 2021 состоится релиз видеокурса «Администрирование и разработка в облачных системах на примере AWS». Курс поможет понять принципы работы облачных вычислительных платформ. Про...
Чтобы готовить высококлассных IT-специалистов, приходится постоянно дорабатывать учебные программы, подстраиваясь под требования рынка. И у нас в Mail.ru Group уже 9 лет работает отде...
Мы уже не раз рассказывали про свой GitOps-инструмент werf, а в этот раз хотели бы поделиться опытом сборки сайта с документацией самого проекта — werf.io (его русскоязычная версия — ru.werf.io)....
Cтатья будет полезна тем, кто думает какую выбрать CMS для интернет-магазина, сравнивает различные движки, ищет в них плюсы и минусы важные для себя.
Автор — Сальваторе Санфилиппо, разработчик и мейнтейнер свободной СУБД Redis Несколько месяцев назад мне написал мейнтейнер одного системного open source проекта с довольно большим и активным...