Для меня 2019 год был годом, когда я узнал как можно больше о качестве программного обеспечения - до такой степени, что я запустил блог, чтобы поделиться многими своими выводами. Как менеджер по разработке программного обеспечения, ответственный за разработку .NET (среди прочего) для унаследованных приложений, я полагаю, было вполне естественно, что я изучил F #.

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

В этой записи сообщества 2019 года Серия F # Advent я не собираюсь подробно погружать вас в одну из многих замечательных функций F #.

Вместо этого я собираюсь рассказать вам, почему вам следует внимательно изучить F # и как он может вписаться в вашу команду, какие преимущества он предлагает и как он может изменить ваше отношение к разработке .NET в целом.

Я неправильно понял

Год назад один из членов моей команды предложил рассмотреть возможность использования F # в нашем коде. Раньше я серьезно не рассматривал этот язык, хотя знал о его существовании.

Ее аргумент был обычным для F #: поскольку большая часть того, над чем мы работаем, связано с математикой, а F # имеет репутацию очень удобного для математических операций функционального языка, мы должны рассмотреть F #.

Оглядываясь назад, я не думаю, что ее аргумент был правильным. Неправильно характеризовать F # как только математический язык или математические операции как главную привлекательность языка.

Я решил, что использовать F # было неправильно, потому что его кривая обучения была слишком крутой, а его преимущества не были достаточно значительными для наших проектов.

Я был неправ.

Истинная привлекательность F #

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

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

Если бы я мог вернуться в прошлое и поговорить с Мэттом о F #, я бы не стал выделять математические аспекты языка.

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

Примечание: приведенные ниже примеры кода из моей серии статей о построении генетического алгоритма на основе белка на F #.

Неизменность

Я бы начал с разговора о том, что F # сильно отдает предпочтение чистым функциям и неизменяемости.

Сделав переменные неизменяемыми по умолчанию, F # удалил целые классы дефектов. Теперь уже нетрудно определить, что изменяет свойства объекта, потому что объекты эффективно изменяются с помощью функций reducer в простые, легко поддающиеся отладке функции.

В приведенном выше примере функция decreaseTimer создает новую версию параметра state с измененными значениями. Исходные значения параметров не меняются.

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

Нули и параметры

Поскольку значения NULL являются распространенной ошибкой, я хотел бы рассказать об обработке значений NULL в F # с помощью Параметры (либо some value, либо none). Параметры заставляют вас на уровне компилятора учитывать нулевые значения. Это эффективно устраняет исключения нулевой ссылки.

В приведенном выше примере вы не можете напрямую получить obstacle.Value, потому что компилятор распознает, что это может быть тип None, вынуждая вас явно проверять значение null в тех местах, где это потенциально возможно.

Дискриминационные союзы и совпадение

Если бы я действительно хотел продать суть, я бы рассказал об использовании в F # размеченных объединений и о том, как их можно использовать для представления совокупности возможных типов и состояний. Известно, что использование размеченных объединений делает невозможным представление плохих состояний на уровне компилятора.

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

Обратите внимание, что синтаксис стиля actor = Squirrel true здесь проверяет, совпадает ли target с Squirrel с hasAcorn = true.

Ремонтопригодность

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

Я уже говорил об этом раньше, но код, который вам не нужно писать, - это код, который не сломается, и код, который вам не нужно поддерживать.

Если вы хотите увидеть подробное сравнение, моим первым проектом на F # было преобразование небольшой библиотеки нейронных сетей с C # в F #.

Компилятор F # - ваш телохранитель

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

Я скажу более кратко: Привлекательность F # в том, что он способствует повышению качества программного обеспечения на уровне компилятора.

Фактически, я хотел бы сравнить F # в мире .NET с TypeScript в мире JavaScript.

В этом году моя команда взяла хрупкое приложение JavaScript и стабилизировала его, преобразовав в TypeScript. Это позволило нам использовать компилятор TypeScript, чтобы найти очевидные проблемы, которых не было бы в JavaScript.

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

Другими словами, у вас обычно большая степень уверенности в том, что скомпилированная программа на F # не содержит ошибок, чем скомпилированная программа на C # или VB.NET.

Общие проблемы

Давайте рассмотрим некоторые общие проблемы, которые возникают у людей при рассмотрении вопроса о F #. Эти опасения были у меня самого год назад, так что вполне уместно поговорить с ними сейчас.

Зрелость языка

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

Скажу прямо: F # не эквивалент новой многообещающей JavaScript-среды.

F # был представлен в 2005 году, и официальная поддержка и интеграция языка со временем только усиливаются.

С Visual Studio 2019 кажется, что F # достиг критической массы. Это отточенный и продуманный язык, который становится все лучше и лучше.

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

Позже в этой статье мы увидим, насколько легко F # интегрируется в существующие экосистемы .NET.

Пробел в обучении

На мой взгляд, проблема кривой обучения немного более оправдана, чем предыдущая, и почему я изначально осторожно относился к F #.

F # может быть трудно изучить, особенно если вы раньше не работали с функциональным языком программирования.

Фактически, я отказался от F # после того, как прочитал книгу по F #, попробовал несколько простых экспериментов и по-настоящему разочаровался и запутался, пытаясь делать базовые вещи с последовательностями объектов.

Честно говоря, я думаю, что прочитал не ту книгу.

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

Я рекомендую эту книгу для изучения F #, и я настоятельно рекомендую покупать копии для всей вашей команды, если вы рассматриваете этот язык.

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

Если вы посмотрите на F # и попытаетесь использовать этот язык для реализации классов с наследованием, свойствами, членами и другими общими функциями объектно-ориентированного языка, у вас будут плохие времена.

F # лучше всего работает с коллекциями объектов для их преобразования, выполнения простых действий и объединения хорошо спроектированных небольших функций для выполнения более крупных задач.

Наем талантов F #

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

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

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

Если вы возьмете на работу разработчика, имеющего опыт работы с .NET и понимающего основы функционального программирования, он сможет выучить F # за относительно короткий период времени.

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

Хотя я говорю об этой теме, это основано только на личных наблюдениях, но я сильно подозреваю, что было бы легче нанять опытных разработчиков .NET, желающих изучить F #, чем опытных разработчиков VB .NET, желающих остаться на VB. NET проектов.

Функции в масштабе

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

Допустим, у вас в проекте 100 функций. В менталитете объектно-ориентированного программирования вы можете разделить их на 10 классов по 10 методов в среднем на каждый класс. Скрытие логики внутри связанных классов помогает уменьшить объем глобальной логики и помогает легче обнаруживать логику.

Изначально я опасался, что при использовании F #, имея большое количество функций, будет сложно найти ту функцию, которая вам действительно нужна.

Оказывается, это не проблема F #, главным образом по двум причинам:

  1. F # имеет концепцию модулей, которые содержат типы и функции. Это позволяет вам организовать связанные функции в один модуль.
  2. F # позволяет объявлять функции как private, что означает, что они не отображаются в глобальной области видимости. Эти функции все еще могут использоваться объектами внутри текущего модуля.

Эти два метода улучшают способность обнаруживать соответствующие функции и уменьшают шум, обеспечивая такую ​​же степень поддержки крупномасштабных проектов, как и любое другое приложение .NET.

Интеграция F # в устаревшие проекты .NET

Итак, F # интересен, но у меня есть годы устаревшего кода. Как я могу заменить его кодом на новом языке?

Короче говоря, вы, вероятно, ничего не заменяете.

Поскольку F # компилируется до Common Language Runtime (CLR), он может взаимодействовать с другим кодом .NET, включая код, написанный на C # и VB .NET. Кроме того, C # и VB .NET могут вызывать функции F #, как показано ниже:

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

Совершенно допустимо иметь решение с проектами F #, C # и VB .NET, которые взаимодействуют с другими проектами в этом решении, а также с пакетами NuGet.

Начало работы с F #

Поскольку F # как перчатка вписывается в экосистему .NET, если вы хотите его оценить, вы можете рассмотреть ряд возможностей:

  • Создайте служебную библиотеку на F #
  • Напишите консольное приложение на F #
  • Напишите небольшое приложение WPF на C #, ссылающееся на логику F #
  • Напишите уровень логики предметной области на F #
  • Создайте проект модульного тестирования F # для тестирования кода C # (лично я бы не стал, но это вариант)

Есть много возможностей. Лично я бы рекомендовал начать с служебной библиотеки для работы с коллекциями предметов. Это наименее рискованное вложение, поскольку, если оно не соответствует вашим потребностям, вы можете быстро заменить его библиотекой C #.

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

Заключительные мысли

Хотя у F # приличная кривая обучения, преимущества качества, которые он предлагает с точки зрения выявления большего количества проблем во время компиляции и меньшего объема кода, стоят вложенных средств.

Хотел бы я сказать, что я принял F # в своей организации в начале 2019 года, и вот преимущества, которые он нам дал. К сожалению, я не могу, потому что ошибся.

Не будь таким, как прошлый Мэтт.

Скажите своим друзьям - F # по-настоящему.

Мэтт - непосредственный менеджер по разработке программного обеспечения для .NET и JavaScript, специализирующийся на наставничестве, архитектуре и качестве программного обеспечения.

Первоначально опубликовано на https://killalldefects.com 15 декабря 2019 г.