Сучасна диджитал-освіта для дітей — безоплатне заняття в GoITeens ×
Mazda CX 30
×
Software Developer, System Architect, Analyst
  • Обстановка в Крыму

    Интересно как себя будут чувствовать офшорные девелоперские компании в Крыму, сотрудничавшие с американцами в свете только что принятых санкций: lenta.ru/...0/usasanctions

  • Логи как лучшее средство от дебага

    Две сущности: Event, Category.

    Category — справочник, который задаёт категорию аудит-сообщения со строковым ключом в формате level1.level2...levelN — зависит от глубины структуры, которая обычно строится по детализации предметной области. Не что иное как хитрый способ отфильтровать дочерние подкатегории, не прибегая к иерархическим запросам — через LIKE ’parentId.%’, ну и суррогат обхода всего дерева через простой ORDER BY id. Тут же хранится человеческое название категории, severity level (тот самый INFO, WARN, etc), ну и самое интересное — атрибут pattern, о котором чуть позже.

    Event — собственно, событие, эквивалент одной записи в лог-файле. Содержит время регистрации, обязательную ссылку на сущность Category, привязку к каким-то прочим сущностям, связанным с событием — например пользователя, породившего событие. И самое главное — произвольный набор текстовых атрибутов «ключ/значение». В реляционной БД это будет третья таблица, для правильного ORM это выглядит как обычный атрибут Map[String,String], ну а для NoSQL — это вообще родная концепция. Там хранятся параметры конкретного события, всё то, что когда-нибудь может понадобиться для анализа.

    Таким образом мы обеспечили машинную читаемость событий, что же касается человеко-читаемости, то она реализуется атрибутом Category.pattern, который представляет из себя выражение с синтаксисом какого-нибудь простого движка-шаблонизатора, который не сложно реализовать и самостоятельно, где, помимо статических фрагментов текста, могут присутствовать ссылки на атрибуты события. Например: «User {user.login} logged in from {ip:unknown IP}». Генерация финального текстового выражения происходит динамически уже на уровне поближе к пользовательскому интерфейсу. Это даёт возможность впоследствии изменить шаблон сообщения, например, добавив новые параметры или ввести возможность многоязыковых сообщений.

    Теперь о некоторых полезных расширениях, построенных на этой концепции. Можем определить интерфейс с одним методом, например такой (дальше пойдёт код на Scala, но это не принципиально):

    trait Auditable {
    def auditAttributes: Map[String, Any]
    }

    class User extends Entity with Auditable {
    // model entity definition...

    override def auditAttributes = super.auditAttributes ++ Map(
    «login» → login,
    «name.full» → s"$firstName $lastName«,
    «roles» → roles sortBy (_.id) map (_.name)
    )
    }

    теперь можем определить метод для логгирования как:

    class AuditService {
    def log(category: String, attributes: (String, Any)*) = ???
    }

    и реализовать в нём раскрытие параметров через интерфейс Auditable.

    Таким образом, вызов

    auditService.log("security.login«, «user» → user, «ip» → ip)

    сгенерирует событие с примерно таким набором атрибутов:

    user.id=123
    user.login=basil
    user.name.full=Basil Pupkin
    user.name.roles=Administrator Manager
    user.name.roles.0=Administrator
    user.name.roles.1=Manager
    ip=1.2.3.4

    что по вышеприведённому шаблону построит текстовое сообщение: «User basil logged in from 1.2.3.4»

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

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

    def diff[T <: Auditable, R](category: String, obj: T)(action: ⇒ R): R = ???

    что откроет возможность такого рода трюкам:

    val user = load[User](userId)
    auditService.diff("user.change«, user) {
    user.firstName = request.firstName
    user.lastName = request.lastName
    }

    Метод diff на входе получит состояние объекта до изменений, сериализует его в плоские строковые атрибуты через интерфейс Auditable, затем выполнит тело выражения в фигурных скобках, и повторно сериализует атрибуты. Сравнив две коллекции легко найти изменившиеся значения. В случае, если таковые есть, можно залоггировать событие с указанием конкретных изменившихся атрибутов, например, в формате «было > стало».

    Ну вот, вкратце, суть идеи. Буду рад, если кому-нибудь ещё пригодится.

  • Логи как лучшее средство от дебага

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

    Підтримав: Alexander Bulgakov
  • Данія запроваджує безвізовий режим для українців з біометричними паспортами

    То есть, на маршруте Киев-Амстердам-Цюрих мне должны были в Амстердаме поставить штамп о въезде?

  • Данія запроваджує безвізовий режим для українців з біометричними паспортами

    Вот тут всё подробно изложено: blog.kupibilet.ru/transit-visa
    Если внутри Шенгена всего одна пересадка и в аэропорту есть транзитная зона, то таможенный контроль не производится.

    Підтримав: Viacheslav Karnaukh
  • Данія запроваджує безвізовий режим для українців з біометричними паспортами

    В 2009. По вашей логике один из штампов в паспорте должен был быть голландский, но вот он передо мной — оба штампа швейцарские.

  • Данія запроваджує безвізовий режим для українців з біометричними паспортами

    Киев-Амстердам-Цюрих рейсами KLM

  • Данія запроваджує безвізовий режим для українців з біометричними паспортами

    Вы уверены? Что-то не припомню чтоб транзитом через Шенген в Шенген я вообще таможенный контроль проходил.

  • Кто там про кредитный лимит возмущался?

    Вы просто не в теме. Приватбанк заблокировал все текущие счета ФОПов, открытые в крымских филиалах. Доступа к средствам нет до сих пор ни у кого, несмотря на перерегистрацию на материке и открытие новых счетов в других отделениях. Перерегистрироваться крымчанам стало довольно просто относительно недавно. В течение полугода до этого обязательным условием была местная прописка. На все претензии банк тупо морозится. НБУ не вмешивается. Милиция заявления не принимает. Иски и физических, и юридических лиц украинскими судами отклоняются со ссылкой на форс-мажорные обстоятельства в Крыму. Так что мой совет, как непосредственно пострадавшего, немедленно выводите все свои деньги из донецких и луганских отделений Приватбанка.

    Підтримав: Євген Козлов
  • Дайте дітям Lego Mindstorms EV3

    Аналогично. Ребёнку очень нравится

    Підтримав: anonymous
  • ООП, развенчание стереотипов-наследовать нельзя обобщать

    Отнюдь. Ни одна из этих фич не является функциональной. Все они вполне могли бы присутствовать в чисто императивном языке со строгой типизацией, таком как Java или C#.

    Годная статья по type classes была здесь: danielwestheide.com/...pe-classes.html ; сейчас почему-то только через кэш: webcache.googleusercontent.com/...lient=firefox-a

  • ООП, развенчание стереотипов-наследовать нельзя обобщать

    Scala позволяет избежать многих проблем с наследованием при помощи traits, type classes, abstract types, stackable traits, structural types, implicit conversions, views — если и не уникальные, то довольно редкие фичи для языков программирования. Практикую все из них, прямому наследованию предпочитаю компонование свойств в виде подмешивания из других trait’ов (mixins) или создание ускоспециализированных type classes.