Поддерживаю вас!
Если эту мысль рассматривать в контексте программирования, то в теории категорий (и в целом в математике) такие преобразования называются изоморфизмом:
A ⭢ B
B ⭢ A
Т.е. мы можем однозначно преобразовать из одного типа в другой и обратно, не потеряв информации.
Спасибо. У меня была примерно такая же идея, но чтобы не писать свою реализацию — после нахождения контура я его заменял отдельной вершиной с весом равным одному проходу по контуру.
Но не покидала мысль, что может быть ученые умы как-то более элегантно решают это задачу)
Спасибо за статью — очень наглядно. А есть ли какие-то методы, позволяющие обсчитать граф с негативным циклом? Ну, к примеру, наложить условие, что по циклу можно проходить только 1 раз… или что-то в этом роде.
Где-то в плюс, где-то в минус. Лично мне сложно представить, чтобы на основе ФП были полноценные современные приложения, особенно ui.
Полностью согласен, что каждый из подходов имеет и плюсы и минусы, о чем я и упоминал в своем комменте. И я тоже считаю, что скорее всего, чистое ФП — не лучший выбор для UI. По крайней мере потому, что рантайм таких приложений не очень предназначен для чистого ФП кода.
но ФП также легко может генерировать костыли и проблемы поддержки кода
Я может не точно выразился, но имелось ввиду, что при одинаковых ресурсозатратах, ФП на выходе дает более качественный код. Коротко говоря: из-за абстракций. На абстрактный код накладывается много ограничений, что уменьшает количество возможных реализаций. Очень часто можно услышать фразу на подобии: «По сути есть только единственный вариант, корректно реализовать эту функцию» — это означает, что ограничения на типы сделаны так, что разработчик может написать «единственную» реализацию, которая скомпилируется (и попадет в прод).
Наличие контекста — это уже не ФП.
В корне неверно. Контекст есть и прекрасно описывается и далее ложится на все существующие (в мире ФП) абстракции. И мутабельность тоже: мутирование данных = сайд эффект.
А вот в ООП все как раз очень плохо с контекстом: регулярно можно встретить код, который работает только в определенном окружении: нужно чтобы в мутабельных переменных находились «определенные» значения, что очень легко поломать при следующем же рефакторе. Очень простенький пример: есть некий класс, который отвечает за коннекшен к БД и прежде чем делать запросы (получать соединение) — нужно его проинициализировать. Из этого следует, что просто поменяв две строчки местами, мы можем получить баг, о котором узнаем только в рантайме.
Похоже на дань моды — «сейчас популярно стало функциональное программирование
ФП стало «модным» потому что неуклонно растет уровень образования в сфере IT: университеты стали давать более адекватные учебные программы, множество онлайн курсов, все больше и больше книг, качество и количество тематических конференций растет из года в год.
Все это приводит к тому, что разработчики начинают более осознанно подходить к проблеме выбора инструментов и подходов для решения задачи. Вот тут как раз и появляется ФП, так как это гораздо более фундаментальный подход, позволяющий значительно сократить количество костылей в продакшене. И чем более разработчиков понимает, что возможно идея «инкрементить в рантайме количество лап кошке, унаследованной от животного» не самая оптимальная для решения их задачи — они начинают копать в сторону. В сторону ФП. Со стороны это может показаться как «мода»\«тренд»\«хайп», но все это существует уже многие многие годы.
Я не утверждаю, что ФП (или ООП) не имеет минусов и тем более не утверждаю, что для реализации UI приложений — это лучший выбор, поскольку JS довольно специфичен. И отсюда, кстати, выходит, что хуки реализованы через какие-то грязные хаки на мой взгляд.
Что-то я растекся мыслью по древу… примеры в статье — это только примеры. Если вы фигачите загрузку данных и прочий бизнес в компонентах, то ваш код очень сильно пахнет, не зависимо от реакта. И callback-hell был еще задолго до того, как ФП стало набирать популярность: в nodejs, например.
И да, использование функций не конвертирует магическим образом вашу программу в ФП-парадигму :)
Это скорее непрофессионализм и невежество отдельно взятых коллег. Это такое себе независимо от того, про какую технологию идет речь.
Плюсы статической типизации переоценены
Поделитесь ссылкой если у вас получится объективное сравнение, мне будет очень интересно почитать, особенно с точки зрения сложных (больших) проектов с длительным жизненным циклом (регулярные релизы\рефакторы) или проектов из области критических бизнес-процессов (важно чтобы работало корректно)
const item = {
createdAt: new Date(),
}
// function isOutdated(item) {};
console.log(isOutdated(item));
Этот «чистейший алгоритм» отработает корректно?
Ответ — конечно нет. И динамически типизированный язык не позволил ни увидеть, ни понять ни больше, ни лучше. Докопаться до истины мы можем только изучив, что делает функция isOutdated.
isOutdated
function isOutdated(item) {
// createdAt is timestamp
return Date.now() - item.createdAt >= 123456;
};
Для примера я упростил все по максимуму, в реальности эти два куска кода могут быть даже в разных репозиториях.
Теперь посмотрим, как этот код выглядел бы на Typescript
Вывод такой, что строгая типизация позволяет добиться таки желаемого эффекта:
программист может видеть/понимать больше/лучше
Даже на динамически типизированном языке вы оперируете типами, просто они нигде не записаны, кроме как в голове у условного разработчика. Программист сменил место работы — с ним ушли важнейшие знания о проекте. Адекватный подход с точки зрения работодателя — это когда все знания о проекте остаются в нем.
Мне тоже было бы интересно посмотреть на методологию. И если смешивание чисел и строк еще хоть как-то более-менее легко отследить с помощью статического анализа, то вот более не тривиальные ошибки (пример в комменте выше habr.com/ru/post/506088/#comment_21722482) уже гораздо сложнее отследить. А уж чтобы провести частотный анализ по таким группам ошибок… интригующе.
Ну а так-то да, с этим никто и не спорит. Просто это совсем не то же самое, с чем вы в эту ветку пришли.
Эм, у меня там было пару тезисов. Уточните тогда с чем это не стыкуется
Я не пропущу код без внятной документации интерфейса на код ревью.
Ну, окей. Но это ваш личный опыт, применительно к проектам, в которых вы проводите код ревью.
А вот компилятор не пропустит в продакшен код с тайп-еррорами любого проекта, который его использует. И количество таких проектов, скажем так, значительно больше, чем то, что может проревьювить 1 человек.
Возможно вы не успели заметить — я дописал одно предложение к моему комменту:
Я не имею ввиду какую-нибудь опенсорс библиотеку. Я про внутренний проект и документация\типизацию именно внутреннего проекта.
Кажется, что у опен сорс проектов своя специфика и там действительно нужно более подробно все документировать. В корпоративной разработке зачастую просто нету столько ресуров. Но повторюсь: чем больше знаний закоммичено непосредственно в проект — тем лучше, и не важно что это: типы, доки.
Про типы все слышали, про документацию пока не все.
Пишем типы в комментах?) Великолепное решение (нет). Если код нельзя читать и понимать без доков, то у меня плохие новости. Я не имею ввиду какую-нибудь опенсорс библиотеку. Я про внутренний проект и документация\типизацию именно внутреннего проекта.
как формула для вычисления площади круга сразу же будет завернута компилятором
Не уверен, что понял вас.
Я просто немного понимаю в разработке, а не повторяю за большинством средней руки тезисы.
:)
Каким большинством? Имеется какая-то статистика? Как минимум не очевидно, что большинство (разработчиков я так понимаю?) пишет на статически типизированных языках. А про тезисы «да-да» лучше умолчать.
Я не пытаюсь сказать, что PHP какой-то уж совсем медленный. Беглое гугление говорит, что swoole — довольно интересный инструмент, но так или иначе — нужно разбираться в том, как работают все эти инструменты, чтобы эффективно использовать их в проде. Кажется, что swoole не переварит блокирующие операции (хотя может я и не прав).
В общем, мой поинт остается в том, что если Вам реально нужна производительность, то асинхронщина + мультитрединг Вам в руки. А лучше всего они будут работать на тех языках, где это из коробки есть (а не приделано сбоку).
быстрее чем на golang
Ничего не могу комментировать про go, к сожалению.
Плюсы статической типизации — это миф. Сейчас хайпово повторять эту мантру, но никаких доказательств этому нет, и быть не может.
Вы должно быть шутите. Строгая статическая типизация — это и есть доказательство работоспособности. А еще оно подкрепляется доказательством корректности системы типов, которое ученые умы закладывают в основы компилятора.
Конечно, никто не дает вам 100% гарантий. Это реальный мир — тут всегда есть погрешности и трейдоффы. Но просто сравните строго типизированный язык с динамически типизированным — и там и там есть типы, просто во втором случае они в голове у автора кода… т.е. грубо говоря — эти знания разработчик не коммитит в проект, а уносит с собой по окончании рабочего дня. Не трудно догадаться, что с точки зрения работодателя это такая себе ситуация и ему хотелось бы, чтобы все знания оставались в проекте.
Восьмерка php с её jit — это еще один шаг к тому, чтобы сделать из php java. Почему это хотят сделать? Читаем пункт номер 1.
Сделать из PHP Java, только хуже. Java в свою очередь сейчас «собирается» из Scala и Kotlin (если смотреть JVM-мирок), только хуже, чем они.
Единственная причина почему пхп развивается так, а не иначе — это желание бизнеса, который начинался в гараже и смог выжить — с минимальными усилиями поддерживать свою кодовую базу.
И всего вышесказанного выходит, что PHP — лучший выбор для legacy проекта, который по «причинам бизнеса» не вариант рефакторить на что-то адекватное.
везде хайлоад проекты на php
Совсем очевидно, что новый проект с уклоном в хайлоад никто в здравом уме не будет делать на PHP. И не потому что язык плохой — а потому что конкурентный асинхронный код всегда будет эффективнее. Нормальная система типов всегда будет давать больше качественных абстракций и (что самое главное) гарантий работоспособности кода.
Все зависит от специфики и бизнес требований. В идеальном мире, конечно, хотелось бы всегда и везде иметь progressive web apps, которые хороши и на 2G и на 5G, но на практике если таких посетителей 1 человек в месяц (условно), то нету никакого профита (для бизнеса) вкладывать деньги в разработку комплексного решения (увы).
Но фронтендеры, привыкшие обрабатывать нажатие мышки по кнопочке, не понимают как написать многопоточную программу, вот и лепят свою лапшу из коллбэков в свою node.js.
Звучит как какая-то обида на фронтенд…
callback hell и т.д.
Что значит «и т.д.»? Callback hell — это были первые попытки структурировать асинхронный код. С тех пор мир уже ушел далеко вперед и есть гораздо более эффективные и элегантные решения о чем я и писал в своем комментарии.
То в современных реалиях это жутко неффективно и тотально проигрывает нормальным тредам на современном 32-х ядерном тредрипере. Потому что треды на таком тредрипере выполняются действительно параллельно.
100%. Поэтому я и говорю, что для высоконагруженной программы нужно писать асинхронный + конкурентный код. Это позволит добиться наилучших результатов при использовании ограниченных вычислительных ресурсов
Ну и я совсем не понял, почему Вы ставите знак равенства между «асинхронность» и «высокая нагрузка», не поясняя, что имеется в виду под «нагрузка».
Не совсем так. Я пытался сказать, что асинхронный конкурентный код — это самый эффективный способ использования вычислительных ресурсов, а значит — позволяет наиболее эффективно (с точки зрения потребления ресурсов) обрабатывать высокие нагрузки. Под нагрузками я имею ввиду то, что подразумевает термин highload.
Асинхронный == треды не простаивают впустую.
Конкурентный == все ядра CPU используются по максимуму.
а Вы про какую-то революцию говорите
Я про эволюцию. Чтобы подходы, которые имели место быть 10-15-20 лет назад заменялись подходами, которые актуальны сейчас.
Посмотрите пожалуйста статью What Color is Your Function?
Почитал, но что-то полезное оттуда вынести сложно. Как я выше написал — люди уже пережили callback-hell и прочие грабли с промисами. Уже есть адекватные механизмы построения control-flow Вашей асинхронной программы. Статья 2015 года, поэтому неудивительно, что автор не упоминает практически ни одного из них. Думаю, что в то время они были не особо распространены. Сейчас фактически все перечисленное там — не актуально.
Project Loom как раз пытается хотя бы частично решить именно те проблемы, о которых Вы пишете
Еще раз — я двумя руками за грин треды и прочие решения этих проблем. Но очень хотелось бы, чтобы это не было в стиле — «я обновил версию JVM и о чудо мой блокирующий код стал не блокирующим». Потому что это не сработает. По крайней мере в Java-мире.
Правильное направление — это наконец-то понять, что асинхронный код существует уже много лет и есть нетривиальное количество примеров и подходов, которое позволяет примерно оценить наиболее эффективное направление.
А то, что сейчас джависты идут по пути, который, скажем, JavaScript комьюнити уже прошло N-лет назад (callback hell -> promises hell -> control flow streams\...), наступая по пути на все те же грабли просто потому что «мы привыкли писать синхронный блокирующий код но это нормально не работает на 32ядерном тред-риппере, давайте закостылим!». Просто смешно.
Если бы это была какая-то революция — еще можно было понять. Сейчас асинхронный конкурентный код — это стандарт для высоконагруженного бэкенда.
Я не против появления грин-тредов, но при их проектировании надо учитывать реальный контекст применения, а не пытаться спасти динозавров.
Если эту мысль рассматривать в контексте программирования, то в теории категорий (и в целом в математике) такие преобразования называются изоморфизмом:
A ⭢ B
B ⭢ A
Т.е. мы можем однозначно преобразовать из одного типа в другой и обратно, не потеряв информации.
Но не покидала мысль, что может быть ученые умы как-то более элегантно решают это задачу)
Полностью согласен, что каждый из подходов имеет и плюсы и минусы, о чем я и упоминал в своем комменте. И я тоже считаю, что скорее всего, чистое ФП — не лучший выбор для UI. По крайней мере потому, что рантайм таких приложений не очень предназначен для чистого ФП кода.
Я может не точно выразился, но имелось ввиду, что при одинаковых ресурсозатратах, ФП на выходе дает более качественный код. Коротко говоря: из-за абстракций. На абстрактный код накладывается много ограничений, что уменьшает количество возможных реализаций. Очень часто можно услышать фразу на подобии: «По сути есть только единственный вариант, корректно реализовать эту функцию» — это означает, что ограничения на типы сделаны так, что разработчик может написать «единственную» реализацию, которая скомпилируется (и попадет в прод).
В корне неверно. Контекст есть и прекрасно описывается и далее ложится на все существующие (в мире ФП) абстракции. И мутабельность тоже: мутирование данных = сайд эффект.
А вот в ООП все как раз очень плохо с контекстом: регулярно можно встретить код, который работает только в определенном окружении: нужно чтобы в мутабельных переменных находились «определенные» значения, что очень легко поломать при следующем же рефакторе. Очень простенький пример: есть некий класс, который отвечает за коннекшен к БД и прежде чем делать запросы (получать соединение) — нужно его проинициализировать. Из этого следует, что просто поменяв две строчки местами, мы можем получить баг, о котором узнаем только в рантайме.
ФП стало «модным» потому что неуклонно растет уровень образования в сфере IT: университеты стали давать более адекватные учебные программы, множество онлайн курсов, все больше и больше книг, качество и количество тематических конференций растет из года в год.
Все это приводит к тому, что разработчики начинают более осознанно подходить к проблеме выбора инструментов и подходов для решения задачи. Вот тут как раз и появляется ФП, так как это гораздо более фундаментальный подход, позволяющий значительно сократить количество костылей в продакшене. И чем более разработчиков понимает, что возможно идея «инкрементить в рантайме количество лап кошке, унаследованной от животного» не самая оптимальная для решения их задачи — они начинают копать в сторону. В сторону ФП. Со стороны это может показаться как «мода»\«тренд»\«хайп», но все это существует уже многие многие годы.
Я не утверждаю, что ФП (или ООП) не имеет минусов и тем более не утверждаю, что для реализации UI приложений — это лучший выбор, поскольку JS довольно специфичен. И отсюда, кстати, выходит, что хуки реализованы через какие-то грязные хаки на мой взгляд.
Что-то я растекся мыслью по древу… примеры в статье — это только примеры. Если вы фигачите загрузку данных и прочий бизнес в компонентах, то ваш код очень сильно пахнет, не зависимо от реакта. И callback-hell был еще задолго до того, как ФП стало набирать популярность: в nodejs, например.
И да, использование функций не конвертирует магическим образом вашу программу в ФП-парадигму :)
Это скорее непрофессионализм и невежество отдельно взятых коллег. Это такое себе независимо от того, про какую технологию идет речь.
Поделитесь ссылкой если у вас получится объективное сравнение, мне будет очень интересно почитать, особенно с точки зрения сложных (больших) проектов с длительным жизненным циклом (регулярные релизы\рефакторы) или проектов из области критических бизнес-процессов (важно чтобы работало корректно)
Простите!
Этот «чистейший алгоритм» отработает корректно?
Ответ — конечно нет. И динамически типизированный язык не позволил ни увидеть, ни понять ни больше, ни лучше. Докопаться до истины мы можем только изучив, что делает функция isOutdated.
Для примера я упростил все по максимуму, в реальности эти два куска кода могут быть даже в разных репозиториях.
Теперь посмотрим, как этот код выглядел бы на Typescript
Вам даже не нужно заглядывать внутрь функции, чтобы понять в чем ошибка.
Вывод такой, что строгая типизация позволяет добиться таки желаемого эффекта:
Даже на динамически типизированном языке вы оперируете типами, просто они нигде не записаны, кроме как в голове у условного разработчика. Программист сменил место работы — с ним ушли важнейшие знания о проекте. Адекватный подход с точки зрения работодателя — это когда все знания о проекте остаются в нем.
Эм, у меня там было пару тезисов. Уточните тогда с чем это не стыкуется
Ну, окей. Но это ваш личный опыт, применительно к проектам, в которых вы проводите код ревью.
А вот компилятор не пропустит в продакшен код с тайп-еррорами любого проекта, который его использует. И количество таких проектов, скажем так, значительно больше, чем то, что может проревьювить 1 человек.
Кажется, что у опен сорс проектов своя специфика и там действительно нужно более подробно все документировать. В корпоративной разработке зачастую просто нету столько ресуров. Но повторюсь: чем больше знаний закоммичено непосредственно в проект — тем лучше, и не важно что это: типы, доки.
Да, согласен. Думаю, что я сужу с уклоном в свою область разработки.
В целом — да, потому что не всегда многопоточку можно сделать красиво и правильно.
Пишем типы в комментах?) Великолепное решение (нет). Если код нельзя читать и понимать без доков, то у меня плохие новости. Я не имею ввиду какую-нибудь опенсорс библиотеку. Я про внутренний проект и документация\типизацию именно внутреннего проекта.
Не уверен, что понял вас.
:)
Каким большинством? Имеется какая-то статистика? Как минимум не очевидно, что большинство (разработчиков я так понимаю?) пишет на статически типизированных языках. А про тезисы «да-да» лучше умолчать.
В общем, мой поинт остается в том, что если Вам реально нужна производительность, то асинхронщина + мультитрединг Вам в руки. А лучше всего они будут работать на тех языках, где это из коробки есть (а не приделано сбоку).
Ничего не могу комментировать про go, к сожалению.
Вы должно быть шутите. Строгая статическая типизация — это и есть доказательство работоспособности. А еще оно подкрепляется доказательством корректности системы типов, которое ученые умы закладывают в основы компилятора.
Конечно, никто не дает вам 100% гарантий. Это реальный мир — тут всегда есть погрешности и трейдоффы. Но просто сравните строго типизированный язык с динамически типизированным — и там и там есть типы, просто во втором случае они в голове у автора кода… т.е. грубо говоря — эти знания разработчик не коммитит в проект, а уносит с собой по окончании рабочего дня. Не трудно догадаться, что с точки зрения работодателя это такая себе ситуация и ему хотелось бы, чтобы все знания оставались в проекте.
Сделать из PHP Java, только хуже. Java в свою очередь сейчас «собирается» из Scala и Kotlin (если смотреть JVM-мирок), только хуже, чем они.
И всего вышесказанного выходит, что PHP — лучший выбор для legacy проекта, который по «причинам бизнеса» не вариант рефакторить на что-то адекватное.
Совсем очевидно, что новый проект с уклоном в хайлоад никто в здравом уме не будет делать на PHP. И не потому что язык плохой — а потому что конкурентный асинхронный код всегда будет эффективнее. Нормальная система типов всегда будет давать больше качественных абстракций и (что самое главное) гарантий работоспособности кода.
Звучит как какая-то обида на фронтенд…
Что значит «и т.д.»? Callback hell — это были первые попытки структурировать асинхронный код. С тех пор мир уже ушел далеко вперед и есть гораздо более эффективные и элегантные решения о чем я и писал в своем комментарии.
100%. Поэтому я и говорю, что для высоконагруженной программы нужно писать асинхронный + конкурентный код. Это позволит добиться наилучших результатов при использовании ограниченных вычислительных ресурсов
Не совсем так. Я пытался сказать, что асинхронный конкурентный код — это самый эффективный способ использования вычислительных ресурсов, а значит — позволяет наиболее эффективно (с точки зрения потребления ресурсов) обрабатывать высокие нагрузки. Под нагрузками я имею ввиду то, что подразумевает термин highload.
Асинхронный == треды не простаивают впустую.
Конкурентный == все ядра CPU используются по максимуму.
Я про эволюцию. Чтобы подходы, которые имели место быть 10-15-20 лет назад заменялись подходами, которые актуальны сейчас.
Почитал, но что-то полезное оттуда вынести сложно. Как я выше написал — люди уже пережили callback-hell и прочие грабли с промисами. Уже есть адекватные механизмы построения control-flow Вашей асинхронной программы. Статья 2015 года, поэтому неудивительно, что автор не упоминает практически ни одного из них. Думаю, что в то время они были не особо распространены. Сейчас фактически все перечисленное там — не актуально.
Еще раз — я двумя руками за грин треды и прочие решения этих проблем. Но очень хотелось бы, чтобы это не было в стиле — «я обновил версию JVM и о чудо мой блокирующий код стал не блокирующим». Потому что это не сработает. По крайней мере в Java-мире.
Правильное направление — это наконец-то понять, что асинхронный код существует уже много лет и есть нетривиальное количество примеров и подходов, которое позволяет примерно оценить наиболее эффективное направление.
А то, что сейчас джависты идут по пути, который, скажем, JavaScript комьюнити уже прошло N-лет назад (callback hell -> promises hell -> control flow streams\...), наступая по пути на все те же грабли просто потому что «мы привыкли писать синхронный блокирующий код но это нормально не работает на 32ядерном тред-риппере, давайте закостылим!». Просто смешно.
Если бы это была какая-то революция — еще можно было понять. Сейчас асинхронный конкурентный код — это стандарт для высоконагруженного бэкенда.
Я не против появления грин-тредов, но при их проектировании надо учитывать реальный контекст применения, а не пытаться спасти динозавров.