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

  1. Использование Excel для учета, инвентаризации и т. д.
  2. Реализация той же бизнес-логики в пользовательской программе с пользовательским интерфейсом и сериализацией данных в JSON или XML.
  3. Переписать программу для поддержки многопоточности или асинхронной обработки.
  4. Переписываем программу для использования базы данных SQL.
  5. Переписываем программу на Java для использования распределенных систем типа Hadoop.
  6. Переписываем программу на Scala для совместимости со Spark.
  7. Создание небольшой программы для обработки подмножества данных на рабочей станции для определенного отдела.
  8. Переписывание части бизнес-логики на JavaScript, чтобы сделать ее доступной для интерфейсных приложений.

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

Проблема использования прямого ввода-вывода в библиотеках

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

Вопросы о существующих решениях

Хотя существуют языки программирования без побочных эффектов и прямого ввода-вывода, такие как Haskell, Elm и PureScript, их интеграция с существующими системами может быть очень сложной задачей. Кроме того, не многие программисты знакомы с этими языками. Это поднимает два важных вопроса:

  1. Как мы можем эффективно интегрировать функциональную бизнес-логику в существующие системы?
  2. Как мы можем найти программистов, которые хорошо разбираются в чисто функциональных языках программирования?

Знакомство с функциональным скриптом

FunctionalScript — это чисто функциональное подмножество JavaScript, предназначенное для предоставления масштабируемых и многократно используемых компонентов для бизнес-логики. Как подмножество, он поддерживает прямую совместимость с JavaScript, что означает, что любой модуль FunctionalScript можно использовать в любой программе JavaScript без каких-либо модификаций. Эта функция упрощает интеграцию в существующие системы, не требуя дополнительных шагов сборки или инструментов. Он позволяет программистам использовать имеющиеся у них знания JavaScript и опирается на знакомый JavaScript API в качестве стандартной библиотеки.

Одним из существенных преимуществ FunctionalScript по сравнению с другими языками функционального программирования является отсутствие привязки к поставщику. Язык не имеет зависимостей, таких как стандартная библиотека или модули времени выполнения. Если языковой проект будет заброшен, модули FunctionalScript по-прежнему будут работать как обычные модули JavaScript, обеспечивая долговечность вашего кода.

Более того, JavaScript — самый популярный язык программирования в мире, а это означает, что программистам не нужно изучать новый сложный язык, чтобы извлечь выгоду из функционального программирования с помощью FunctionalScript. Это широкое знакомство облегчает поиск и привлечение разработчиков для работы с FunctionalScript, помогая решать проблемы, связанные с другими чисто функциональными языками программирования.

Система типов

FunctionalScript, как и JavaScript, является динамически типизированным языком. Тем не менее, он выигрывает от использования аннотаций типов TypeScript/JSDoc, которые помогают обнаруживать большинство ошибок типов. TypeScript использует структурную систему типов, в отличие от систем номинальных типов, которые можно найти во многих современных языках, таких как C++, Rust, C# и Java. На практике система структурных типов, как правило, вызывает меньше проблем, чем система номинальных типов, что часто приводит к чрезмерному количеству адаптеров между интерфейсами, что в конечном итоге ухудшает возможность повторного использования кода.

Вот пример, иллюстрирующий, как аннотации типов TypeScript/JSDoc можно использовать в FunctionalScript:

/**
 * @template T
 * @typedef {T|undefined} Option
 */

/** @type {<T, R>(f: (value: T) => R) => (value: T|undefined) => R|undefined} */
const optionMap = f => value => value === undefined ? undefined : f(value)

// test optionMap
{
    const optionSq = optionMap(v => v * v)
    const sq3 = optionSq(3)
    if (sq3 !== 9) { throw sq3 }
    const sqUndefined = optionSq(undefined)
    if (sqUndefined !== undefined) { throw sqUndefined }
}

Создание приложений с использованием FunctionalScript

  • В: Как мы можем создавать приложения с помощью FunctionalScript, если у него нет ввода-вывода?
  • A: Это правда, что любая работающая программа требует ввода-вывода. Однако ключевая идея FunctionalScript состоит в том, чтобы как можно дольше задерживать операции ввода-вывода, гарантируя, что основная бизнес-логика остается отделенной от проблем, связанных с вводом-выводом. Такой подход позволяет использовать основные функции повторно и адаптировать их к различным системам ввода-вывода. Следующая диаграмма зависимостей демонстрирует эту структуру:

В этой структуре application.js служит оркестратором, содержащим только связующий код, который соединяет lib.f.js (основную бизнес-логику) с вводом-выводом для конкретной платформы. Вот пример простого приложения:

логика.f.js

/** @typedef {(text: string) => undefined} ConsoleOut */

/** @type {(out: ConsoleOut) => undefined} */
const main = out => out('Hello world!')

module.exports = { main }

приложение.js

const logic = require('logic.f.js')

logic.main(console.log)

FunctionalScript можно использовать в различных типах приложений, в том числе:

  • Интерфейсные приложения (веб, мобильные)
  • Серверные приложения (Node.js, Deno, Bun)
  • Расширения JSON для языков сценариев, такие как инструменты сборки и развертывания.
  • Сложные языки запросов для распределенных систем

Используя FunctionalScript в этих сценариях, вы можете обеспечить лучшее разделение задач, более простое обслуживание кода и большую адаптируемость к различным системам ввода-вывода или требованиям.

Как упоминалось ранее, основная цель — иметь масштабируемые и многократно используемые компоненты. Пользователи, формально описывающие бизнес-логику, не должны переписывать ее для новой системы распределенных вычислений или изучать новый язык программирования.

Текущее состояние

FunctionalScript — это проект с открытым исходным кодом, выпущенный под лицензией MIT. Проект все еще находится на ранней стадии разработки, и мы активно работаем над созданием парсера и других необходимых модулей.

Весь код написан на FunctionalScript, что свидетельствует о возможностях языка. Когда синтаксический анализатор завершен, его можно использовать для создания различных инструментов линтера и компиляторов. До тех пор мы вручную проверяем наш код, используя FunctionalScript в качестве соглашения по коду.

Ссылки