Я вот бекенд разработчик, занимаюсь "чёрными ящиками" (вход -> магия -> выход) — WebAPI, ETL, Streaming. И мне очевидно две вещи:
я хочу всё распараллелить, заасинхронить
я не хочу проблем
Поэтому я просто пишу в ФП стиле: иммутабельность везде. Сразу снимает проблемы с рейс кондишнами и проблемой глобальных объектов. У меня всё глобально доступно, но кого это волнует если функции чистые и они не мутируют объекты, а создают новые?
Я видимо плохой бекенд разработчик, потому что хороший, судя по опросу, использует для бекенда исключительно ООП.
Почему глобальные объекты и статика — это зло? Можете показать на примере кода?
Чо эт сразу зло-то? В ФП вот всё по умолчанию статика и глобальные объекты. Ну не учитывая разбивку на модули (по сути неймспейс).
Наверное стоит спрашивать почему ИЗМЕНЯЕМЫЕ глобальные объекты зло? Но и это не всегда правда, может у меня есть изменяемый глобально параметр LogLevel, небеса не развернутся если я его буду менять из разных кусков кода.
Многие другие вопросы заранее в себе содержат "правильный" ответ, который собеседуемый должен взять за основу рассуждений (например: почему Java это плохо?).
Моё утверждение — преувеличение, как и Ваше.
Хороший — тот, кто умеет пользоваться инструментом. Программист — обычная работа, не надо быть гением, собирать дома компьютеры или создавать по фреймворку в месяц.
Иногда чтобы быть крепким середнячком можно просто выполнять свою работу.
Некоторые разработчики ещё и механики, а некоторые — только водители "у меня есть руль, я умею его крутить и знаю куда вонючая водичка на заправке заливается, остальное — не барское дело".
Вы так говорите, как будто в этом что-то плохое. Всякие люди нужны. В 1% работ нужны те, кто умеет фреймворки делать, стоят они дорого. В 99% нужны те, кто умеет фреймворками пользоваться. Зачем бизнесу переплачивать?
Я думаю они совместимы до сих пор, т.к. throw в виде выражения возвращает любой generic тип, который выводится компилятором из второй ветки оператора ?? в виду того что throw не возвращает в обычном смысле.
В F#, где всё является выражением есть похожие функции:
failwith: string -> 'a
raise: exn -> 'a
принимаем строку с описанием ошибки или объект Exception и валим выполнение программы. компилятору подсовываем любой тип какой он хочет, т.к. это уже неважно, функция нормально не вернёт.
А вы не пробовали F#? Там уже из коробки есть Discriminated Union и монструозные конструкции превращаются в:
type MyResult<'T> =
| Success of 'T
| Error of exn list
//Это ваш Select
let map f = function
| Success v -> Success (f v)
| x -> x
//Это ваш SelectMany
let bind f = function
| Success v -> f v
| x -> x
//Это ваш SelectMany от 2 функций
let bind2 f g = bind (fun x -> f x |> bind g)
А вообще в F# уже есть готовый тип Result с map, bind и пр, поэтому это всё не пригодилось бы.
Если у вас такая сложная доменная логика, вы можете отдельный проект под неё на F# запилить и 90% кодовой базы уйдёт за ненадобностью.
Меньше кода — меньше ошибок. А у вас за дженерик параметрами "леса не видно":
Не, не подзабил, т.к. F# всегда был у Microsoft языком второго сорта) Их продукт — C#, а F# делается командой Don Syme на гитхабе.
Поддержку .NET Core 2 в Visual Studio только-только завезли. Через год может быть паблиш F# проектов в Azure припилят =)
По поводу инфраструктуры только частично соглашусь. Для большинства библиотек хватает вот этих функций
let curry f a b = f (a, b)
let curry3 f a b c = f (a, b, с)
let uncurry f (a, b) = f a b
let uncurry3 f (a, b, c) = f a b c
чтобы свободно пользоваться преимуществами F#
На крайний случай можно небольшую обвязку сочинить поверх библиотеки с функциональным фасадом.
Кстати Newtonsoft.Json умеет работать с F# из коробки (списки, массивы, DU) кроме option. Достаточно добавить один кастомный Option Converter чтобы вообще всё заработало.
По поводу Jet.com любопытно. У них не так давно была волна агрессивного рекрутинга, где они предлагали "(high 5 to low 6 figures / year)", релокейт, но надо физически находиться в USA на момент обсуждения.
Если не секрет почему ушли из Jet.com?
От себя:
F# умеет всё что и C# (ООП, наследование, интерфейсы, netcore 2.0 вот это вот всё) + много сверху (Discriminated Unions, partial application, type inference везде где можно, кастомные операторы и пр).
Для создания бекенда прям самое оно. Система типов круче, ошибиться сложнее.
Фронты писать в функциональном стиле тоже можно, попытки видел, мне лично не нравится.
Есть просто отдельные крутые нугеты:
Logary, Hopac
Разве я здесь написал, что интерфейсы не нужны вообще?
Конечно нет. Вы написали что "интерфейсы не нужны к классам с единственной реализацией".
А я вот не согласен с этим утверждением.
Есть случаи когда к классу с единственной реализацией нужен интерфейс. Тестируемый код должен быть слабосвязанным.
Добиться этого проще через интерфейсы, поэтому даже если у Вас есть всего одна (и больше не планируется) реализация сервиса работы с очередью для получения данных, проще выделить интерфейс IQueueDataService чтобы замокать её в юнит-тестах с полпинка. Попутно получаем все прочие плюсы слабой связанности.
Эту фразу стоит превратить в вопрос:
и смело добавлять в статью, настолько она сильная.
Я не знаю как ещё это комментировать.
Так можно про любой язык сказать если в нём разобраться.
Я вот бекенд разработчик, занимаюсь "чёрными ящиками" (вход -> магия -> выход) — WebAPI, ETL, Streaming. И мне очевидно две вещи:
Поэтому я просто пишу в ФП стиле: иммутабельность везде. Сразу снимает проблемы с рейс кондишнами и проблемой глобальных объектов. У меня всё глобально доступно, но кого это волнует если функции чистые и они не мутируют объекты, а создают новые?
Я видимо плохой бекенд разработчик, потому что хороший, судя по опросу, использует для бекенда исключительно ООП.
Чо эт сразу зло-то? В ФП вот всё по умолчанию статика и глобальные объекты. Ну не учитывая разбивку на модули (по сути неймспейс).
Наверное стоит спрашивать почему ИЗМЕНЯЕМЫЕ глобальные объекты зло? Но и это не всегда правда, может у меня есть изменяемый глобально параметр LogLevel, небеса не развернутся если я его буду менять из разных кусков кода.
Многие другие вопросы заранее в себе содержат "правильный" ответ, который собеседуемый должен взять за основу рассуждений (например: почему Java это плохо?).
Короче, плохой опросник.
Хорошо что не плюсами едиными живём и есть ещё языки которые гарантируют оптимизацию хвостовой рекурсии на уровне спецификации языка.
В рекурсии нет ничего опасного. Если какой-то инструмент её неправильно готовит — это проблема инструмента, а не подхода.
Ровно до тех пор пока другое знание вам не подскажет про хвостовую рекурсию.
Моё утверждение — преувеличение, как и Ваше.
Хороший — тот, кто умеет пользоваться инструментом. Программист — обычная работа, не надо быть гением, собирать дома компьютеры или создавать по фреймворку в месяц.
Иногда чтобы быть крепким середнячком можно просто выполнять свою работу.
Вы так говорите, как будто в этом что-то плохое. Всякие люди нужны. В 1% работ нужны те, кто умеет фреймворки делать, стоят они дорого. В 99% нужны те, кто умеет фреймворками пользоваться. Зачем бизнесу переплачивать?
А чтобы быть хорошим водителем, обязательно надо собрать машину с нуля. Иначе никак.
Я думаю они совместимы до сих пор, т.к. throw в виде выражения возвращает любой generic тип, который выводится компилятором из второй ветки оператора ?? в виду того что throw не возвращает в обычном смысле.
В F#, где всё является выражением есть похожие функции:
принимаем строку с описанием ошибки или объект Exception и валим выполнение программы. компилятору подсовываем любой тип какой он хочет, т.к. это уже неважно, функция нормально не вернёт.
А вы не пробовали F#? Там уже из коробки есть Discriminated Union и монструозные конструкции превращаются в:
А вообще в F# уже есть готовый тип Result с map, bind и пр, поэтому это всё не пригодилось бы.
Если у вас такая сложная доменная логика, вы можете отдельный проект под неё на F# запилить и 90% кодовой базы уйдёт за ненадобностью.
Меньше кода — меньше ошибок. А у вас за дженерик параметрами "леса не видно":
Зачем пытаться из C# сделать F#?
Тем более этот SQL синтаксис
выглядит чужеродно для не коллекций.
Мне кажется человек ошибся и говорил про процедурное программирование. ФП же нифига непростое, т.к. матан.
Я думаю, Вы не уловили сарказм в словах автора.
Не, не подзабил, т.к. F# всегда был у Microsoft языком второго сорта) Их продукт — C#, а F# делается командой Don Syme на гитхабе.
Поддержку .NET Core 2 в Visual Studio только-только завезли. Через год может быть паблиш F# проектов в Azure припилят =)
По поводу инфраструктуры только частично соглашусь. Для большинства библиотек хватает вот этих функций
чтобы свободно пользоваться преимуществами F#
На крайний случай можно небольшую обвязку сочинить поверх библиотеки с функциональным фасадом.
Кстати Newtonsoft.Json умеет работать с F# из коробки (списки, массивы, DU) кроме option. Достаточно добавить один кастомный Option Converter чтобы вообще всё заработало.
По поводу Jet.com любопытно. У них не так давно была волна агрессивного рекрутинга, где они предлагали "(high 5 to low 6 figures / year)", релокейт, но надо физически находиться в USA на момент обсуждения.
Если не секрет почему ушли из Jet.com?
Почему же? Где можно, там выводит) Где не получается — надо ручками писать, да.
Это намного лучше чем их полное отсутствие (дада, C#, я о тебе).
Вполне хватает на любые нужды:
>>=
>?>
>>=.
|>
||>
!>
?>
и пр.
Подробнее можно здесь посмотреть как сделать постфиксные, префиксные и инфиксные операторы — http://www.readcopyupdate.com/blog/2014/09/10/custom-ops-associativity-precedence.html
Jet.com например бекенд весь на F#. Объяснение почему
От себя:
F# умеет всё что и C# (ООП, наследование, интерфейсы, netcore 2.0 вот это вот всё) + много сверху (Discriminated Unions, partial application, type inference везде где можно, кастомные операторы и пр).
Для создания бекенда прям самое оно. Система типов круче, ошибиться сложнее.
Фронты писать в функциональном стиле тоже можно, попытки видел, мне лично не нравится.
Есть просто отдельные крутые нугеты:
Logary, Hopac
Людей в гайдах по WPF/WinForms застращали этим ConfigureAwait, так теперь суют его везде.
Конечно нет. Вы написали что "интерфейсы не нужны к классам с единственной реализацией".
А я вот не согласен с этим утверждением.
Есть случаи когда к классу с единственной реализацией нужен интерфейс. Тестируемый код должен быть слабосвязанным.
Добиться этого проще через интерфейсы, поэтому даже если у Вас есть всего одна (и больше не планируется) реализация сервиса работы с очередью для получения данных, проще выделить интерфейс IQueueDataService чтобы замокать её в юнит-тестах с полпинка. Попутно получаем все прочие плюсы слабой связанности.
Расскажите где я неправ, очень будет любопытно.
Показываю:
Вам выше рассказали почему это утверждение не соответствует действительности.