Pull to refresh
32
0

Разработчик

Send message

Спасибо за статью, но код довольно запутанный и следить за ним не просто (Port вызывает методы AbstractActor и наоборот, каждый из них по отдельности нельзя понять), было бы неплохо добавить разбор того что происходит в простой паре producer-consumer и что означает block, поскольку он не блокирующий.


Пока не ясно чем этот подход лучше чего-то вроде:


class ProducerSubscription<T> extends Subscription<T> with Runnable {
  private Subscriber<T> subscriber; // from constructor
  private AtomicLong demand = new AtomicLong();
  private AtomicLong spawnedId = new AtomicLong();

  public void request(long size) {
    if (demand.getAndAdd(size) == 0) {
      executor.execute(this::send);
    }
  }

  private void send() {
    long id = spawnedId.incrementAndGet();
    // ensure only one send spawned most of the time
    while (spawnedId.get() == id) {
      long batch = demand.getAndSet(0);
      if (batch == 0) break;
      while (batch-- > 0) {
        subscriber.onNext(....);
      }
    }
  }
}

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


А между прочим такое разделение противоречит даже классическим многослойным архитектурам, так как тут нет бизнес слоя (он обычно размазан по всем, а в пакете "models" обычно анемичные модели или вообще DTO) и подходит разве что если у вас вся бизнес-логика в базе данных.

Абстрагирование — отвлечение в процессе познания от несущественных сторон, свойств, связей объекта (предмета или явления) с целью выделения их существенных, закономерных признаков.

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

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


Мастерство разработки складывается из двух частей — алгоритмов и структур данных (не заученных, а умения решать задачи и писать код) и архитектуры (умения собрать всякие циклы и хеш-таблицы в большой проект, который не умрет под своим весом).


Когда я спрашиваю про SOLID меня устроит ответ "не помню конкретных принципов, но вот каким должен быть проект". Я вообще уважаю людей, которые ищут причины. Почему в Java при переопределении метода можно сузить тип результата? Почему нельзя добавить исключений? Почему Spring рекомендует инъекцию в конструктор, а не в поле? Почему в проекте обычно пакеты верхнего уровня это models/controllers/services?

Сервис может нарушать DI если хардкодит адрес зависимости, если api не достаточно абстрактен или если сервис полагается на особенности реализации другого.
В силу физического разделения приходится использовать api, но и в ооп интерфейс это не всегда абстракция.

Почему нет? Полиморфизм это про абстракцию, DI, open/closed, инкапсуляция, паттерны это вообще все абстракции.

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

Конечно существуют более общие и более абстрактные принципы как Low Coupling, High Cohesion а так же в целом абстракция. SOLID это более конкретные и более практичные советы на их базе. А уж двигаясь дальше в сторону практики и конкретики возникают паттерны.

Спасибо, немного увлёкся)

Даже если вы соберёте все хотелки от бухгалтеров в одном классе, но код будет на одном уровне абстракции этот код будет лучше, чем многое из того, что я видел.

Для "простой" архитектуры не нужны принципы, это ещё php показал завоевав популярность всем кодом в одном файле.
Конечно не нужно цитировать solid с точностью до буквы, нужно их понять. А когда понял причины понимаешь когда следовать, а когда нарушать.

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


Что касается SOLID, я пожалуй даже соглашусь, увы это вызвано желанием использовать стандартный тайпкласс, который в Scala не слишком сегрегированный, тут как по мне лучше стандартное чем небольшое. Код же вполне точно описывает требования, странно называть часть требований "особенностью" — все требования особенные.


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

Я бы не назвал это tagless final, просто тайпкласс под специфичную проблему, что в целом не очень хорошо, так как такой тайпкласс не будет повторно использован.

На самом деле интервью вещь двусторонняя, у команды есть свои критерии и если вы по ним не подходите, то и команда вам не подходит. Хотя конечно желательно предупреждать о желаемом стиле.


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


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

На самом деле нет, в коде:


  def divisibleBy(n: T)(implicit I: Integral[T], ev: Eq[T]): Boolean = {
    import I._
    (value % n) === zero
  }

Оператор % это синтаксис для I.rem, который импортируется из I, так что это будет работать для любого типа, не только стандартных числовых.

Да, остаток от деления определяется строго говоря делителем, так что нужен zero для типа делителя, да и отрицательные числа из Integral тут не нужны, но это стандартный тайпкласс, проще использовать его, чем писать свой.

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

Многие спорят о том, в чем секрет успеха Java. Да, язык консервативен, да, многословен, часто не безопасен, не слишком выразителен и неконсистентен.
Котлин в свою очередь довольно приятный язык, с очень чёткой маркетинговой нишей синтаксического сахара.
Но я думаю Java будет жить. Потому что писать плохой код можно на любом языке — я видел очень много плохого кода на Java и уверен, что Котлин даёт программисту свободу написать ещё хуже (в чем конечно нет вины языка). Java код скушный, но обычно понятный, ужасы кроются на уровень выше — в кривых абстракция, отсутствии архитектуры, копипасте и т.п. Но понятный код даёт ложное ощущение контроля и возможность средним программистам связать воедино куски, которые они не понимают.
Ни в коем случае не утверждаю, что все Java программисты средние — там немало ярких и интересных личностей. Но массовая популярность и спрос, а главное культура языка делают свое дело. И в копилку плюсов идёт все-же возможность как-то заставить этот хаос работать.
Kotlin на мой взгляд это возможность принести в Java проект немного свежего воздуха. Но если вы почувствовали вкус свободы — не стоит останавливаться, идите дальше — есть Scala, Haskell, Rust и много других интересных языков.
Развивайтесь.

Type class это не class, это класс типов — интересный вариант полиморфизма из функциональных языков когда протокол описывается отдельно от самого типа.


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

Смотря как считать, все функции кроме собственно fizzBuzz полезны в широком контексте и в проекте были бы общим кодом. Так что самого решения — одна функция в три строки :-)

Information

Rating
Does not participate
Location
Украина
Date of birth
Registered
Activity