• Уровень

    Пока мир сходит с ума по искусственному интеллекту, всплакну о низком уровне разработчиков. Подкатило, нужно выплеснуть.

    Ситуация: разработчик пишет функцию get-by-id, чтобы достать сущность из базы. Не моргнув глазом, он передает ее в map на пять тысяч элементов. Это, на минутку, один запрос, а запросов может десятки в секунду. Подобные вещи приходится ловить в code review и объяснять, что один запрос лучше, чем пять тысяч.

    Идет 2023 год, а программисты пишут SQL конкатенацией строк. В порядке вещей код на два экрана с format, str и join, который ни понять, ни отладить. Полученный запрос уходит в базу, и дай бог, чтобы оно работало. Если передать nil или пустой список, получим битый SQL, потому что автор этого не предусмотрел. И конечно, инъекции во все поля.

    Почему-то программисты не могут записать и получить данные из базы. Им нужна ORM, и чтобы она сразу мапилась на REST. Получается километр глючного кода без документации и поддержки. Автор ORM отлынивает от задач под видом ее доработки. Часть команды уходит в партизаны: работают с базой через SELECT и UPDATE в обход ORM. Так спокойней, главное чтобы автор ORM не зашел в пулл-реквест.

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

    Программисты не доводят дело до конца, хотя в бóльшей степени это упрек руководству. Например, у кого-то задача, чтобы была документация Swagger. Человек пишет генератор json-файла, покрывает тестами, все готово. Осталось захостить, чтобы документацию увидели клиенты. Но прилетает горящая задача или девопс-инженер уходит в отпуск. В итоге документация есть, но ее никто не видит. Задача не достигнута, время потрачено зря, но это никого не смущает. Недостигнутые цели я вижу постоянно.

    Сюда же относятся висящие пул-реквесты. Открываешь борду и видишь у кого пять, а у кого семь пул-реквестов. Зачем программист писал код, если его не принимают? Если бы он смотрел Ютуб, эффект был бы тот же. Почти во всех системах можно задать auto-expire, не говоря уж о ботах, которых полно.

    Беда с локальным окружением. Программисту лень потратить день на docker-compose.yaml, чтобы сервисы работали локально. Приходится объяснять, что локальный ресурс лучше стейджинга где-то в Амазоне.

    Иной программист генерит айдишники для базы вручную. Берет рандом от 0 до 9999 и густо перчит номером треда, числом миллисекунд и фазой Луны. И это работает в проде.

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

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

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

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

    Все, отпустило, работаем дальше.

  • Помощь Chat GPT

    Сегодня я столкнулся с “помощью” Chat GPT, а точнее — его необдуманным применением.

    Я немного занимаюсь Латехом, и когда верстал книгу, решал массу технических вопросов. Что-то вышло изящно, а что-то нет: работает, но коробит душу. Хочу закрыть эти недостатки в будущем.

    Добрые люди подсказали группу в Телеграме, где тусят любители Латеха. Зашел туда и задал наболевший вопрос про жирный шрифт в minted. Через какое-то время один пользователь (судя по био, женщина), скинула ответ с примером на Латехе. Я горячо поблагодарил и побежал пробовать.

    Запускаю — ошибка, что нет такого-то свойства. Ладно, думаю, устарели пакеты. Обновил все под чистую. Запускаю — то же самое. Что же это за свойство? Полез в документацию пакета, а там его вообще нет. Пакет ничего не знает об этом свойстве.

    Посмотрел на ответ свежим взглядом и понял — это Chat GPT (вчера вечером мозги были уже не те). Во-первых, в нем повествовательный стиль: “обратите внимание”, “вы можете” и так далее. От первого лица в Телеграме так не пишут. Во-вторых, в копипасте я нашел артефакты, свойственные интерфейсу Chat GPT. В частности, название языка перед участком кода (python, latex). Их всегда забывают вычистить при копировании ответа целиком.

    Что тут можно сказать? История не нова. Помните сервисы вопросов и ответов на Яндексе и Мейл.ру? Раньше домохозяйки копировали с Википедии. Теперь то же самое, только научились пользоваться Chat GPT. Понимаю, почему на StackOverflow запретили им пользоваться — можно засрать сервис нерабочим кодом без какой-либо ответственности.

    Лишний раз убеждаюсь в том, о чем писал недавно. Chat GPT — это никакой не интеллект. Это языковая модель, которая производит текст, максимально близкий к вопросу. Ей неважно, работает код или нет, у нее другие метрики. А мне, наоборот, важно. Мне платят за код, который не только выглядит хорошо, но и работает хорошо. Единственный способ проверить код — запустить его и предъявить результат работы. Этого Chat GPT не может, и поэтому мне с ним не по пути.

  • Выпадашки

    Бич современного интерфейса — это выпадающие элементы, которые я называю “выпадашками”. Часто упоминаю их, когда пишу об интерфейсе, и вот пора сделать отдельный пост.

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

    Типичный пример — форма комментариев на Хабре. Действие “Ответить” выражено текстом, к этому вопросов нет. Затем идет иконка закладки. Далее выпадашка, под которой ссылка, редактирование и жалоба. Зачем было их прятать? Места хватит и для иконок, и для текстовых ссылок.

    Пользуясь случаем, замечу, что у выпадашки адская разреженность. Ее можно было сжать в два раза без какого-либо ущерба.

    Другой пример — форма закладок на том же Хабре. Закладки бывают двух типов: статьи и комментарии. Почему переключалка сделана в виде выпадашки? Что мешало расположить элементы по горизонтали: Статьи / Комментарии?

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

    Впрочем, и на Айпаде я видал интерфейсы, когда на весь экран пустота и в правом верхнем углу жалкое многоточие.

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

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

    С ростом экрана дизайнер не знает, как им воспользоваться. Поэтому искусственно раздувает интерфейс: больше отступы, крупнее иконки, половину кнопок под выпадашку. Скрытая профессиональная импотенция.

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

    Со временем придет ясность, что все элементы можно расположить, не пряча один под другой. Но это требует усилий над собой.

  • Clojure + GraalVM framework for AWS Lambda

    Lambda is a small framework to run AWS Lambdas compiled with Native Image.

    Motivation & Benefits

    There are a lot of Lambda Clojure libraries so far: a quick search on Clojars gives several screens of them. What is the point of making a new one? Well, because none of the existing libraries covers my requirements, namely:

    • I want a framework free from any Java SDK, but pure Clojure only.
    • I want it to compile into a single binary file so no environment is needed.
    • The deployment process must be extremely simple.

    As the result, this framework:

    • Depends only on Http Kit and Cheshire to interact with AWS;
    • Provides an endless loop that consumes events from AWS and handles them. You only submit a function that processes an event.
    • Provides a Ring middleware that turns HTTP events into a Ring handler. Thus, you can easily serve HTTP requests with Ring stack.
    • Has a built-in logging facility.
    • Provides a bunch of Make commands to build a zipped bootstrap file.

    Installation

    Leiningen/Boot:

    [com.github.igrishaev/lambda "0.1.1"]
    

    Clojure CLI/deps.edn:

    com.github.igrishaev/lambda {:mvn/version "0.1.1"}
    

    Read more →

  • Заменят ли ИИ разработчиков и почему? Если да, то на каких задачах?

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

    Что ж, если коротко, то нет: ИИ, который у нас сегодня, не заменит программистов. Волноваться незачем, продолжайте работу. Если вы учитесь на программиста и испытываете тревогу, успокойтесь и продолжайте. Никакие чаты и боты программистам не угрожают. А также журналистам, учителям и вообще — любым профессионалам своего дела.

    Да, про ИИ говорят и пишут из каждого утюга. Но важно знать, что информационная волна всегда сильнее повода, который ее вызвал. Изданиям нужен трафик, а люди склонны экстраполировать: если сегодня бот написал Тетрис, то через год он сделает Киберпанк. Увы, это не так.

    Причина моего скепсиса в том, что все помощники и боты слабы в деталях. У меня есть колонка Яндекса, она прекрасно играет музыку и говорит погоду. Но ее крайне легко ввести в ступор. Например, играет песня, и я хочу послушать альбом, которому она принадлежит (пусть даже первый, если их несколько). Однако этой функции не предусмотрено: какую бы фразу я ни высказал — перейди к альбому, включи альбом, из какого это альбома, — Алиса не понимает. Хотя в мобильном приложении это одна кнопка “show album”.

    Read more →

  • Такой же

    Наверное, вы слышали вопрос о корабле, заданный еще до нашей эры. Если постепенно заменить в корабле все детали, будет ли это тот самый корабль?

    Проблема в том, что на вопрос отвечают, не разобравшись с определениями. Если не договориться, что значит “тот же самый”, можно спорить весь день, имея в виду не то, о чем думает оппонент.

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

    Еще один довод в адрес “то же самости” — это мы сами. Тело человека обновляется постоянно. Скелет меняется за три года, а у кожи, волос и ногтей срок исчисляется днями. Жидкости поступают и выходят.

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

    Поэтому и корабль, в котором обновили все доски, тот же самый. Если, конечно, понимать под “тем же самым” то, что удобно большинству.

    Забавный эпиграф к библиотеке re-frame8:

    This, milord, is my family’s axe. We have owned it for almost nine hundred years, see. Of course, sometimes it needed a new blade. And sometimes it has required a new handle, new designs on the metalwork, a little refreshing of the ornamentation … but is this not the nine hundred-year-old axe of my family? And because it has changed gently over time, it is still a pretty good axe, y’know. Pretty good.

    Вкратце: господин, этот топор служит нашей семье девять столетий. Иногда ему меняли рукоять, а иногда клинок. Но поскольку это делали постепенно, это все тот же топор.

    В этом и проявляется забавное свойство “той же самости”: если ее размазать по времени, предмет будет тем же самым (менять ручку и клинок раз в сто лет). Если потерять топор и заказать новый, это будет другой топор.

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

    Команда может саботировать новые правила, если их слишком много. Внедряйте по одному с интервалом в месяц.

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

    В завершение — пазл, который висит у меня на стене (Яцек Йерка):

  • Письма Notion

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

    Итак, я написал текст в Ноушене и попросил руководство обсудить. На следующий день открываю почту на телефоне и вижу штук 20 уведомлений от Ноушена: пошли комментарии. Тыкаю, чтобы прочитать. А письма, сюрприз, выглядят так:

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

    И вот опять, смотрите: сапожник без сапог. Как мы помним, Дропбокс, программа для работы с файлами, не умеет показывать файлы. А Ноушен, программа для текста, не может показать текст. Разработчики, вы вообще своим Ноушеном пользуетесь? Если бы я там работал, то в первый же день открыл бы тикет и долбил им каждый спринт — ваши сраные письма не читаются. Поправьте стили. Высылайте plain text вместо HTML, он мне нахрен не сдался. Просто чтобы можно было прочесть текст.

    Директор Ноушена без конца гонит какую-то графоманию, которую постят на Хакер-ньюз и Хабре. Подобно Грефу внедряет искусственный интеллект и машинное обучение (которые дают пустую строку). И при этом никто сделает нормальный шрифт в письмах. Просто стыд.

  • Эта удивительная Clojure: что на ней разрабатывают, чем она отличается от других языков и подходит ли для входа в программирование

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


    Мы расспросили разработчиков на Clojure из сообщества clojure_ru. Выясняли, как применяют язык, что на нём пишут, легко ли на нём программировать.

    Что программируют на Clojure

    Павел: сфера применения Clojure в техническом плане — в основном веб и серверные приложения. На успешно работающий Clojure-код можно посмотреть, например, в продуктах Metabase и Penpot, их исходный код открыт.

    Но постепенно язык проникает и в другие области. ClojureScript работает в браузерах и других средах для JavaScript, с помощью проекта Esprit его уже запускают на микроконтроллерах, а сейчас развивают ClojureDart, чтобы захватывать мир Flutter. Конечно, не все эксперименты в итоге «взлетят», но такое разнообразие работающих проектов показывает, что применимость языка ограничена скорее настроениями разработчиков, чем самим языком.

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

    Иван: сфера применения Clojure широка, она решает те же задачи, что Java, Python и другие языки. На ней пишут сетевые сервисы, бэкенд веб- и мобильных приложений. Clojure подходит для обработки данных из разных источников — баз данных, очередей, HTTP API — и часто служит их оркестратором.

    Существует ClojureScript — компилятор кода на Clojure в JavaScript. С его помощью создают браузерный фронтенд и мобильные приложения на базе React Native.

    Код на Clojure можно скомпилировать при помощи GraalVM и native image, получив бинарный файл. С этим подходом пишут утилиты командной строки, интерпретаторы, AWS Lambda и многое другое.

    Read more →

  • Сбер

    Постоянно пользуюсь Сбером, чтобы оплатить что-нибудь по QR-коду. Каждый раз удивляюсь анимации вверху экрана. За каким-то хреном кнопка с QR не зафиксирована, а выезжает справа. Как в рекламных полях, где анимацию делают ради анимации: что-то выехало, покачалось, мигнуло. Типа, управление вниманием.

    Зачем? Кто просил эту анимацию? На автомате тычу в левый угол, клик приходится на другой элемент, открывается что-то не то. Ясное дело, все тормозит, потому что параллельно загружаются другие виджеты.

    Если функция кнопки известна заранее, а также ее текст и оформление, никакой анимации не нужно. Может, балбесу-дизайнеру из Сбера нравится: у него эмулятор на мощной тачке, запущено одно приложение, все плавно. А потребитель видит слайдшоу и промахивается кнопкой.

    Дорогие дизайнеры! Засуньте уберите ваши анимации подальше. Они не нужны, вы делаете лишнюю и вредную работу.

  • The Mask library for Clojure

    (This is a copy of the readme file from the repository.)

    Mask is a small library to prevent secrets from being logged, printed or leaked in any similar way. Ships tags for Clojure, EDN and Aero.

    Why? Because I’ve been in such a situation three times, namely:

    • We don’t mask the secrets.
    • Someone logs the entire config.
    • Secrets have leaked!
    • Rotate all the keys, tokens, etc.
    • Change the team and face the same.

    This library is an attempt to break this vicious circle.

    Installation

    Leiningen/Boot:

    [com.github.igrishaev/mask "0.1.0"]
    

    Clojure CLI/deps.edn:

    com.github.igrishaev/mask {:mvn/version "0.1.0"}
    

    Usage

    The mask.core namespace provides mask and unmask functions. Pass a value to mask to make it safe for logging or printing in REPL:

    (in-ns 'mask.core)
    #namespace[mask.core]
    
    (def -m (mask "Secret123"))
    
    -m
    << masked >>
    
    (str "The password is " -m)
    "The password is << masked >>"
    

    Masking is idempotent meaning that you can mask the same value multiple times but the result will be one-level masked value:

    (-> -m mask mask mask)
    << masked >>
    

    To release a value from a mask, unmask it:

    (unmask -m)
    "Secret123"
    

    Unmasking is idempotent a well:

    (-> -m unmask unmask unmask)
    "Secret123"
    

    Note: the library treats nil as an error value that cannot be masked. You’ll get an exception:

    (mask nil)
    Execution error (IllegalArgumentException) at ... (core.clj:34).
    Cannot mask a nil value
    

    Masking an empty value signals you’re doing something wrong. Most likely you’ve missed a corresponding key or an environment variable. Thus, the further work makes no sense.

    Spec

    The mask.spec module provides the ::mask spec that checks if a value is really masked. An example from the tests:

    (let [config
          {:username "Ivan"
           :password #mask "secret"}]
    
      (is (s/valid? ::config config)))
    
    ;; true
    

    Clojure tag

    The built-in #mask tag wraps any value with a mask:

    => {:token #mask "abc123" :password "SecretABC"}
    
    {:token << masked >>, :password "SecretABC"}
    

    EDN tag

    There is a reader-edn function that acts like an EDN reader for the same tag:

    (let [source (-> "{:foo #mask 42}")]
      (edn/read-string {:readers {'mask reader-edn}}
                       source))
    
    ;; {:foo << masked >>}
    

    Aero tag

    To extend Aero with the #mask tag, import the mask.aero namespace:

    (require 'mask.aero)
    

    Then read a config with the tag:

    ;; config.edn
    {:foo #mask #env "SOME_PASSWORD"}
    
    ;; code
    (aero/read-config (io/resource "config.edn"))
    
    ;; {:foo << masked >>}
    

    The Aero dependency is not included. You’ve got to provide it by your own.

    Ivan Grishaev, 2023

Страница 15 из 75