Maksim Fedorov

Golang Software Developer.

Help for developers  •  Posts on Habr

Оптимизация работы с браузерными событиями в Ангуляр-директиве

Если у вас директива слушает браузерные события, например движения/клики мыши или клавиатуры через HostListeener, то это может быть проблемой с перформансом.

Пример:

Допустим у вас директива, которая слушает в элементе с атрибутом editablecontent=true и в output отдает начало и конец текстового выделения.

Решение:


import {Directive, ElementRef, EventEmitter, HostListener, inject, Output,} from '@angular/core';

interface SelectedEvent {
  start: number;
  end: number;
}

@Directive({
  standalone: true,
  selector: '[selectedOffset]',
})
export class SelectChildren {

  @Output() onSelect = new EventEmitter();

  private readonly elementRef = inject(ElementRef);

  @HostListener('mouseup')
  @HostListener('mousedown')
  @HostListener('mousemove')
  @HostListener('keyup', ['$event'])
  listenEvents(event: KeyboardEvent) {
    this.reportSelection();
  }

  private reportSelection(): void {
    this.onSelect.next(this.getSelectionCharacterOffsetWithin(this.elementRef.nativeElement));
  }

  private getSelectionCharacterOffsetWithin(element: HTMLElement): SelectedEvent | null {
    const doc = element.ownerDocument;
    const win = doc.defaultView;

    const sel = win?.getSelection();

    if (!!sel && sel.rangeCount > 0) {
      const range = sel.getRangeAt(0);
      const preCaretRange = range.cloneRange();
      preCaretRange.selectNodeContents(element);
      preCaretRange.setEnd(range.startContainer, range.startOffset);
      const start = preCaretRange.toString().length;
      preCaretRange.setEnd(range.endContainer, range.endOffset);
      const end = preCaretRange.toString().length;

      return { start: start, end: end };
    }

    return null;
  }
}


В данном примере очень агрессивная политика у слушателя @HostListener(’mousemove’), который может очень сильно повлиять на перформанс работы вашего приложения.

Оптимизация:

Можно конечно слушать события mousemove только если произошло событие mousedown, сделав флаг в приватной переменной, а на mouseup его не обрабатывать, но есть споособ написать его через RxJs, который даст дополнительные возможности. Можем подписаться на mousemove только после события mousedown и отписываться на эмите mouseup событий.


  private mousedown$ = fromEvent(this.elementRef.nativeElement, 'mousedown');
  private mouseup$ = fromEvent(this.elementRef.nativeElement, 'mouseup');
  private mousemove$ = fromEvent(this.elementRef.nativeElement, 'mousemove');

  constructor() {
    this.mousedown$
      .pipe(
        switchMap(() => this.mousemove$),
        takeUntil(this.mouseup$),
        repeat(),
      )
      .pipe(
        takeUntilDestroyed(),
      )
      .subscribe(e => this.reportSelection())
  }


Дополнительной точкой оптимизации может быть выполнение логики снаружи от зоны, чтобы наш UI не тригерился на этой логике:


  private readonly zone = inject(NgZone);

  constructor() {
    this.zone.runOutsideAngular(() => {
      this.mousedown$
        .pipe(
          switchMap(() => this.mousemove$),
          takeUntil(this.mouseup$),
          repeat(),
        )
        .pipe(
          takeUntilDestroyed(),
        )
        .subscribe(e => this.reportSelection())
    })
  }


Но такого рода оптимизация повлияет на UI, если вам нужно реактивно отрисовывать изменения на mousemove — то UI не будет реагировать, потому нужно применять этот способ оптимизации по потребности.

15 июля   angular

Маленький лайфхак для работы с проектами в IDE

Пользуюсь годами — супер-удобно.

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

Добавить пути .ignore в глобальный конфиг гита такую инструкцию


     echo ".idea" >> ~/.gitignore && \
     echo ".ignore" >> ~/.gitignore && \
     git config --global core.excludesFile '~/.gitignore' 


В результате вы можете создавать в корне или в любой вложенности такие вспомогательные папки с вашим кодом:

Иногда .ignore может быть неудобным — многие загрузкчики и менеджеры пакетов в языке не поддерживают с точки, а `Ignore` опасно добавлять глобально — такой путь может быть в гите проекта...

Тогда есть такой лайфхак — вы можете через средства IDE добавить путь для исключения отслеживания гитом локально для проекта

Вот теперь пример для PHP-проекта — у вас есть свой неймспейс `\\Ignore`, который работает с автозагрузкой (например для отслеживания DI-контейнером), при это путь не попадает в git.

Приятной и удобной работы!

2022  

Подробные гайдлайны написания кода

Во многих компаниях гайдлайны только Project specific. Например как делать структуру проекта или как называть те или иные методы/переменные. Остальное разработчики как-бы «понимают» из принятых в нужном языке.

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

Из плюсов: описывается только разница, это как правило меньше инструкций и скорость вникнуть в проект простая и легкая.

Свитчеры и полиглоты

Переключившись на язык Golang понял: есть свитчеры и полиглоты. Если первых некоторые компании не берут в силу малого опыта (по крайней мере в РФ). Но есть полиглоты, с ними сложнее — они пишут в разных стилях на разных языках и более широкие гайдлайны им сильно помогут.

Пишите подробный гайдлайн или ссылайтесь на подборку с таковыми!

2022  

Ревью: защищайте свое решение!

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


В одном из проектов год назад перед коллегой встала задача: построить сложный график операторов. Нужно было объединить кучу данных: расписания, отдых, отгулы и все это наложить друг на друга и вывести в некоторый массив данных и выводить в API для отрисовки в UI.

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

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

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

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

Хорошим итогом этого процесса было бы то, что программист стал бы защищать свое решение, но этого не было.

Защищайте свое решение!

2021  

Почему пенсия нужна

Смирение, с тем, что пенсии не будет — страшнейшая ошибка нашего поколения.


Последнее время и в живую, и на Ютубе вижу много опросов или просто косвенные мнения о том, что наше молодое поколение все равно останется без пенсии, ну и ладно, «все равно будем без пенсий — нужно будет самим позаботиться». Это очень глупо и очень ветрено, это очень опасно, очень... Грубо говоря мы «забиваем» на то, что будет дальше.

Время пролетит одним мигом. По щелчку вам станет 40-50-60-70. Че говорить, если вам 30, то многие из вас уже ловили мысли «АААА! 10 лет пролетели махом». Отчетливо помню маму, когда ей было 33 года, сейчас уже шестой десяток разменяла.
Болячки вылезают уже после 30, где-то врожденное, где-то травма. Даже если на протяжении жизни у вас один не стареющий организм — все равно с течением времени вероятность сделать что-то не то и не так сильно вырастает (подвернуть ногу, сделать ушиб под чашкой колена, сломать челюсть с 6-7 зубами на вылет в аварии и не по вашей вине даже), но организм еще и стареет, нервная система расшатывается, генные расположенности становятся ярче и прочее.

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

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

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

Я отказываюсь принимать за действительности, что мы останемся без пенсий, с х*я ли!

Бюджет доступности сервиса

Слайд из конференции П.Зайцева про высокую доступность MySQL

У Booking.com есть некая метрика «сколько должен сервис не работать».
Вопреки первой логичной мысли, топ-менеджеры не всегда заинтересованы в 100% доступности.

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

Интересная мысль.

Тестирование кода в некомпилируемых языках

Увидел в одном из интервью Андрея Солнцева (разработчик фреймворка для тестирования Selenide на Java) очень сильный довод в пользу использования unit-тестов в динамически-интерпретируемом языке, таком как Ruby/PHP/Python — unit-тесты нужны только лишь потому, что он (язык) не компилируется :-)

И действительно, стат-анализаторы/код-сниферы далеко есть не всегда, потому ошибка точно может проскочить, да и код можно нарушить в обход сниферов, а об ошибке узнаем на стороне сервера, при том он может сработать не сразу!

Да и вообще — кто сейчас не пишет тесты?!

Как повысить себе зарплату?

Отличный совет от программиста и ИТ-директора Сергея Горностаева (@TheDeadOne) на Тостере о том, как повысить себе зарплату и что нужно учесть:

Центральный показатель для бизнеса, а следовательно и руководителей, как людей представляющих интересы этого самого бизнеса — это коэффициент возврата инвестиций (ROI). Соответственно, сотрудник должен приносить компании больше денег, чем потребляет. Естественно, что чем выше разрыв между затратами и прибылью, тем лучше, поэтому фонд оплаты труда руководитель должен держать на том минимальном уровне, который гарантирует бесперебойную работу сотрудников.
Один из факторов этой бесперебойности — низкая текучка. Сотрудников терять нежелательно. И чем ценнее для компании сотрудник, чем более он профессионален и/или чем больше на него завязано, тем дороже обходится его потеря. Натурально в деньгах. Придётся затратить больше, чем обычно, денег на поддержание работы без него. Придётся затратить деньги и время (те же деньги) на поиск, найм, введение в работу, возможно, обучение нового сотрудника. При этом он может оказаться совсем неподходящих и цикл придётся повторить. Или может оказаться просто хуже прошлого и эффективность отдела снизится. Поэтому, когда сотрудник приходит просить прибавку, руководитель оценивает может ли этот сотрудник уйти или только блефует, насколько легко его будет заменить, какой урон компании будет нанесён его уходом. Потом руководитель оценивает стоимость расширения ФОТ — есть ли резервы, какой сейчас ROI, будет ли больший ROI от реинвестиции этих средств во что-то другое? Если уход сотрудника будет стоить меньше, чем увеличение ФОТа, сотруднику откажут.


Важный момент:

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

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

Разработка через TDD

Андрей Солнцев пишет браузерную игру через Unit тесты и UI тесты.
Делает на языке Java, но абсолютно понятно каждому.

Абстракции и как они текут

Статья будет полезна начинающим разработчикам и менеджерам.

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

Абстракция

По определению Википедии, абстракции — это «придание объекту характеристик, которые чётко определяют его концептуальные границы, отличая от всех других объектов».

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

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

Абстракции текут

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

Реальный пример. У нас в компании приходит много товаров из Китая и Турции разных брендов. Исторически сложилось, что в 1С карточки товаров объединяются в группы по брендам (это, к слову, абстракция — менеджер выделил товары по определенным границам, которые совпадают с брендом).

Это хорошо работает — менеджеру удобно работать с клиентом и показывать целые линейки брендов. Но возникает как всегда НО — часто приходит товар неизвестного бренда в количестве 1-2 вещей и таких товаров много. Проблема — под одну вещь заводить группу с брендом — неудобный и лишний труд. Тогда менеджер решает создать помимо группы брендов одну отдельную группу — группу «Китай», в которую накидывает единичные товары произвольных брендов.

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

Проблемы утечек

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

Но 1С в 21 веке почти всегда работает бок о бок с веб-системами — выгрузка в интернет-магазин, выгрузка партнерам, отчеты и статистика.

Рассмотрим интернет-магазин. В интернет-магазине есть куча абстракций и самые явные — меню категорий и фильтр товаров. Исторически сложилось, что категории в первую очередь строятся по виду товара (джинсы, куртки) или полу (М и Ж), но не по брендам. Тогда бренд нам нужно сделать одним из свойств фильтра и тут мы получаем первые проблемы — пользователь сайта среди возможных брендов видит бренд с названием «Китай», так как мы взяли утекшую абстракцию за значение свойства.


Избегайте утечек абстракций по возможности — это чревато проблемами.



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

Текут в любом месте

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



Каково было мое удивление, когда спустя некоторое время в меню для сайта я увидел данные для  продавцов розничного магазина :) Да-да, это чистой воды утечка абстракции.

Чем это чревато? Меню может быть несколько для нескольких сайтов, к какому из них прикреплять данные для розничного магазина? :) Или будет путаница в отчетах, ведь в некоторых меню нет этих значений.

Ctrl + ↓ Ранее