Pull to refresh
2
0
Nick Gushchin @iNikNik

Software Engineer

Send message

Во первых уровни дублируют друг друг


Чисто теоретически это может позволить отследить попречный перекос (в некоторых случаях)

Согласен с вами! Но в то же время, то что там 203 л.с. не значит, что она плохо едет

Да, но в какой-то момент появляется потребность предоставлять качественный продукт, особенно если это IT-стартап. Вот тогда и нужны хорошие специалисты. И что-то не заметно тенденции, что бы на западе бежали с деньгами в первую очередь к Казахстанским айтишникам. Ну вот так вот ?‍♂️ Потому что одно дело -- продавать услуги, а совсем другое -- наличие большого количества зарекомендовавших себя специалистов (например из РФ)

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

Эх, а мне как-тот при лечении премоляра на верхней челюсти допустили попадание р-ра гипохлорида в пазуху, оттуда в носоглотку. Врач не сразу поверила, дала рот прополоскать и пошла дальше каналы промывать. И снова раствор оказался там, где не должен. Хотя стояла изоляция как на первом фото. По итогу гайморит с отеком пазухи на 90%+, курс антибиотиков и очень "увлекательные" несколько дней. При том что стоматолог утверждала, что все ок само пройдет, а я самостоятельно съездил на КТ и к ЛОРу сходил...

Теперь у меня такой-же премоляр, тоже сверху, только с другой стороны, но там уже надо перелечивать каналы после ОМС 10 летней давности. Что-то как-то боязно решаться на лечение после негативного опыта :(

Ликвидность — это когда товар нужный. И то, что акции стали высоколиквидным товаром — на мой взгляд есть плохо.


Ликвидность — плохо? Покупайте акции моего NoName стартапа, плачу дивидендов 6% в год в валюте. Один только нюанс — продать акции вы не сможете, потому что они никому не нужны. Ну а что? Вкладываетесь в актив по номиналу, на сумму, скажем, 1 000 000 $, затем я вам буду каждый год перечислять 60к$, а на остальное жить :)

Прошу прощения за шутливую манеру, но смысл как раз в том, чтобы ликвидность была высокой. Низкая или никакая ликвидность лишает возможности оценить стоимость актива и даже банально выйти из сделки. Или, хотя бы, оценить свои риски — потенциальную прибыль\убытки, когда и как можно закрыть позицию и чего это будет Вам стоить. Покупка акций это не только про дивиденды, но и про рост стоимости самих бумаг. Иначе можно закупаться облигациями)

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


В жизни все не так просто и представления о том, кто что кому должен у каждого участника торгов — свои. В текущей картине и трейдеры, и инвесторы, и торговые боты — нужны; и не все идет по плану — бывает, что закрыть сделку нужно именно сейчас, потому что потом закрывать будет нечего. Можно либо принять это и использовать для получения прибыли, либо строить различные конструкции несуществующей реальности (ну и, конечно, любой вариант между этими двумя)
Начиная с этого года на патенте можно получить налоговый вычет, в итоге ИП на ПСН по разработке ПО платит 60к налогов в год (фиксированно) в СПб. А лимит дохода что-то вроде 60млн. рублей.

Это кажется довольно выгодным
тесты не нужны, всё равно руками проверять


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

Следуя вашему аргументу легко придти к:

типы не нужны, всё равно руками проверять
линтеры не нужны, ...


Вы слишком смело расширили контекст css на область разработки целиком. Мои высказывания касались лишь css в виде JS объектов с TS против css в виде css с линтерами. Где я как раз аргументировал за линтеры и тесты.

отлетает проблема «опечатался в одной букве и что-то где-то может непоправимо полететь», например, кнопка важная пропадёт


Извольте! Отсутствие опечаток не гарантирует того, что все отобразится как на макете дизайнера. И Вам в любом случае это надо проверять (пример — тесты скриншотами). А если это нужно проверять, то каки-либо преимуществ от того, что в стилях у вас TS (и это уже вовсе не стили, а js-код) — нету, по сравнению, скажем, со здоровым CSS-In-JS:

const Button = styled.a`
  background: transparent;
  color: white;
  border: 2px solid white;
`


Линтер не пропустит опечатки в прод, удобство работы с css сохранено (форматирование, копи-паста из браузера и прочие ништяки), тесты писать так и так нужно.
Код пишется программистами для программистов. Сложновоспринимаемый код стайл вполне может стать весомым аргументом против (для проектов сложнее туду-аппы из примеров в документации, размером в «100 строк»)
Вы не видите, а разработчики, которые по 10 лет поддерживают какую-то систему, видят


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

А в случае Scala оба подхода декларируются как верные.


Но тут опять же возврат к проблеме выбора, которую автор описывал в статье: если ты пишешь ООП, то kotlin будет лучшим выбором для JVM. Другими словами — нету смысла писать чистое ООП на scala.
enum в первую очередь — синтаксический сахар для более лаконичного выражения ATD в scala3/ Цитата из документации:

An enumeration is used to define a type consisting of a set of named values.


enum Color {
  case Red, Green, Blue
}


This defines a new sealed class, Color, with three values, Color.Red, Color.Green, Color.Blue. The color values are members of Colors companion object.


И уже во вторую очередь это те самые любимые enums, которые можно подружить с Java.

То есть мотивация у разработчиков немного другая, хотя на выходе мы получаем фичу которая подходит и для enums и для ADT.
Данная фича позволяет скрыть данный список, в статье это описывается.
Кстати, вы нижнюю строчку на картинке читали?


Конечно, конечно. И полностью согласен. Только эти паттерны нужны гораздо реже. Потому что паттерн — это обобщенное описание решения какой либо задачи\проблемы, а, скажем, монада

— это моноид в моноидальной категории эндофункторов


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

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

Пример аналогий паттернов ООП в ФП (на картинке) — вполне реальный. Конечно, не имеется ввиду, что DI заменяет буквально одна функция. Но сам тот факт, что, к примеру, в JVM мирке подавляющее большинство проектов на Java (ООП) используют сложный фреймворк (Spring Boot), которые предоставляют набор паттернов (в частности DI), то в проектах на Scala (FP) ничего из фреймворков не используется (да, там есть парочка: akka — но это не чистое ФП, а мультипарадигма; play — тоже самое). И при этом архитектура приложений только выигрывает и все плюшки того же DI присутствуют.
Ну а возвращать монаду или типа того, которая при вычислении и в базу сходит, и в файлы что-то запишет — не нарушение? Если что в монадах я слабо разбираюсь


Я пишу на scala, поэтому все примеры будут из этой области

Монада — это описание некоторого вычисления. Фраза «возвращать монаду» другими словами звучит как «возвращать описание вычисления». Есть так же понятие (сайд) эффекта. Ваша монада может как поддерживать различные эффекты (IO\Zio\Monix Task), так и не поддерживать (только чистые вычисления — Optional\Either).

Для приведенного Вами примера мы можем выразить нечто подобное:

def saveInvoice[F[_]: DBClient: Logging](invoice: Invoice): F[InvoiceId]


Где:
  • saveInvoice — название функции
  • F[_] — тайп параметр функции (читается как эф с дыркой, тип высшего порядка. Дырка означает, что конструктор этого типа принимет один аргумент. Пример: Option[T], Task[T], List[T], Array[T]). Этот параметр позволяет абстрагироваться от конкретного типа эффекта\монады
  • : DBClient — показывает, что внутри функции мы описываем сайд эффект в виде обращения к базе
  • : Logging — показывает, что внутри функции мы описываем сайд эффект в виде логгирования (в консоль)
  • invoice: Invoice — параметр функции
  • F[InvoiceId] — тип возвращаемого значения. В данном случае мы декларируем, что возвращаем описание некоторого процесса, результатом выполнения которого будет InvoiceId. При этом в процессе выполнения мы можем совершать описанные выше сайд-эффекты


Формально у функции одна задача — описать процесс сохранения некого инвойса в БД. Это важный момент, т.к. когда мы вызываем данную функцию — ничего не происходит, а только лишь возвращается описание процесса, который мы уже сможем запустить в самом конце (end of the world, обычно это 1 раз на все приложение, в конце main):

val invoice: Invoice = ???
val res = saveInvoice[IO](invoice)
// res: IO[InvoiceId]

res.unsafeRunSync(); // Запускаем процесс сохранения


Внутри могут вызываться другие функции, которые описывают процесс логирования или запрос к базе. Таким образом сохраняется и SRP, и чистота функций.

Подход, который я описал, называется Tagless Final. Есть и другиие: скажем, Free Monad. В нем структура программы описывается не как выражение (композиция функций), а как данные (деревоподобная структура).

Их (подходы) можно комбинировать как удобно, чтобы достичь лучшего результата, т.к. все, что идет в рамках ФП можно описать словом compositional, в то время как остальной код (ООП) можно описать словом composable (тут очень тонкая разница в значении, но она выливается в колоссальную разницу на практике).

Ну, нарушить его можно как с классом (объектом), так и с функцией.
Тут имелось ввиду, что у функция, в парадигме ФП, выполняет одно преобразование, которое указано в ее типе: A => B. В «крестьянских» (не чисто функциональных) языках никто не запретит делать что угодно. Но только тогда Ваш код уже будет не совсем про ФП :) Тоже самое верно и про ООП — вы можете поместить любую логику внутрь ваших методов. Паттерны проектирования — это не механизм языка, а общий подход к решению задачи. Ему можно следовать, можно не следовать.
И как вы будете доказывать объективность этого анализа?


Это крайне сложно сделать на 100% объективно.

Я не пытаюсь навязать свою точку зрения. Воспринимайте это с позиции человека, который долгое время писал (и даже сейчас продолжает писать) в парадигме ООП, но вдруг обнаружил нечто действительно крутое и воодушевлен этим.

Если Вам, вдруг, интересна эта тема — мы можем пообщаться. Я могу скинуть пару-тройку докладов, которые мне зашли. Возможно Вы захотите провести свой подобный анализ. Возможно, что кто-то другой захочет. Я думаю, что если достаточное количество человек это сделает, то в среднем, оценка мат ожидания результатов и будет близка к объективной.
Да, его трудно проверить, если говорить без контекста: сферические трудозатраты на коня в вакууме.

Но можно провести сравнительный анализ, результатом которого будет, скажем, табличка: критерий|ООП|ФП. То я искренне полагаю, что можно получить достаточно точную оценку.

Но опять же, я повторюсь: все зависит от задачи. Где-то выиграет ООП, где-то ФП.

PS Под ресурсозатратами я имел ввиду человеко-часы и (условный) скилл разработчика.

PSS В частности такой вывод я делал на основе того, что можно выкинуть тонну нетривиальных паттернов в пользу функций (или композиции функций), потому что они были придуманы в те времена, когда функции не были объектами первого класса (first class objects\citizens) и это порождало определенное количество проблем.

image
Только вот наследование в большинстве случаев — это без пяти минут антипаттерн и где только можно его рекомендовано заменять на композицию.

что человеку удобно делить предметы на категории


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

если все собаки хвостаты, а пудели — собаки, то пудели хвостаты


Тут еще отмечу, что очень многое зависит от задачи. Если мы пытаемся моделировать условных пуделей и их хвосты… то — возможно да, в ООП это хорошо зайдет. А если мы работаем с данными (что в подавляющем большинстве случаев истинно), то при одинаковых ресурсозатратах ООП код будет проигрывать (по критериям: восприятие кода\рефакторинг\кол-во ошибок\легкость расширения\time to market\качество абстракий) функциональному подходу.

Information

Rating
Does not participate
Location
Санкт-Петербург, Санкт-Петербург и область, Россия
Registered
Activity