-
Лучший язык
По мотивам обсуждений во внутреннем чатике, вот вам мысль.
Лучший язык для решения задачи — тот, который знаешь лучше всего. Если это Питон — пиши на Питоне. Если лучше всего знаешь Джаву — пиши на Джаве. Если это JS или PHP, то что ж… пиши на них.
Когда вам говорят, что C++ лучше подходит для игр, а R для статистики, не нужно вестись на эту удочку. Язык-то задаче подходит, а вы подходите языку?
Даже если взять “подходящий” язык, который вы плохо знаете, результат будет хуже, чем с “неподходящим”, но знакомым языком. Под “знаете” имеются в виду не основы синтаксиса и курсы, а пять лет опыта и больше.
Простыми словами, если с Питоном вы 10 лет, а на плюсах писали дай бог в универе, то умножение матриц на Питоне будет медленней, но понятней и проще в поддержке.
Игры, кстати, хорошо пишутся на C-шарпе в том же Юнити. Полно печатных плат, которые выполняют быдлокод на Питоне и JS. Если вы знаете Лисп как бог, то не составит труда написать мини-язык, который собирается в машкоды — так писали серию игр Crash Bandicoot. В случае с Питоном почти все либы написаны на Си, а Питон — это клей, чтобы их вызвать.
Поэтому нужно оценивать не язык, а себя. Пишите на том, что знаете лучше всего. А языки подучивайте в фоне, рассматривая их как инструменты.
-
AI и новички
В Кложурной слаке в канале для офтопа пошла речь о языковых моделях. Приведу хорошую цитату оттуда:
Library suggestions seems to be one of the areas they’re very weak: they hallucinate a lot about namespaces and functions so the suggested code looks feasible but won’t run, and it actually leads to beginners then raising issues against the suggested library that “gpt suggested this code but it doesn’t work as expected”
Прямо в точку. У меня было несколько раз, когда человек копировал выхлоп из GPT и жаловался, что он не работает. На первый взгляд код правильный, а потом смотришь: здесь нет двоеточия, здесь левый символ, здесь ссылка на неизвестный неймспейс. Между кодом — повествовательный стиль изложения: вы можете сделать то, можете это.
Досадно, что каждый раз человек сливается. Начинаешь объяснять, что не так, а в ответ — тишина. Видимо, человек рассчитывал, что GPT прав, ошибка на моей стороне и сейчас я быстро поправлю. Но оказывается не так, нужно думать, разбираться и вообще — все сложно.
Не советую новичкам пользоваться языковыми моделями для кода. Они как волшебное зеркало — что-то показывают, но откуда оно, какая гарантия и кто несет ответственность — неизвестно. В точности противоположно тому, что нужно на старте.
-
Всюду AI
Наиболее раздражающий тренд сегодня — это когда каждая программа подсовывает AI. Открываешь гугло-док, а сверху плашка: попробуй Gemini at no cost. Открываешь Feedly — а там AI-анализатор твоих фидов. Открываешь Хром — а там AI-алгоритм для группировки вкладок.
Все это в выпадашках, выпадашках, выпадашках. Даже если закрыл, покажут через два дня опять.
Когда-нибудь AI-истерия, конечно, пройдет. Просто иной раз думаешь — почему я опять должен пережидать очередной вирусняк? Ждать, пока программы отпустит от блокчейна, BLM, прайда и прочего? Я ведь не просил, оно само пришло.
-
Ring JDK Adapter
Ring JDK Adapter is a small wrapper on top of a built-in HTTP server available in Java. It’s like Jetty but has no dependencies. It’s almost as fast as Jetty, too (see benchmars below).
Why
Sometimes you want a local HTTP server in Clojure, e.g. for testing or mocking purposes. There is a number of adapters for Ring but all of them rely on third party servers like Jetty, Undertow, etc. Running them means to fetch plenty of dependencies. This is tolerable to some extent, yet sometimes you really want something quick and simple.
Since version 9 or 11 (I don’t remember for sure), Java ships its own HTTP server. The package name is
com.sun.net.httpserver
and the module name isjdk.httpserver
. The library provides an adapter to serve Ring handlers. It’s completely free from any dependencies.Ring JDK Adapter is a great choice for local HTTP stubs or mock services that mimic HTTP services. Despite some people think it’s for development purposes only, the server is pretty fast! One can use it even in production.
Availability
It’s worth mentioning that some Java installations may miss the
jdk.httpserver
module. Please ensure the JVM you’re using in production supports it first. Check out the following links:- StackOverflow: Is package com.sun.net.httpserver standard?
- Java® Platform, Standard Edition & Java Development Kit Version 21 API Specification
Installation
;; lein [com.github.igrishaev/ring-jdk-adapter "0.1.0"] ;; deps com.github.igrishaev/ring-jdk-adapter {:mvn/version "0.1.0"}
Requires Java version at least 16, Clojure at least 1.8.0.
Quick Demo
Import the namespace, declare a Ring handler as usual:
(ns demo (:require [ring.adapter.jdk :as jdk])) (defn handler [request] {:status 200 :headers {"Content-Type" "text/plain"} :body "Hello world!"})
Pass it into the
server
function and check the http://127.0.0.1:8082 page in your browser:(def server (jdk/server handler {:port 8082}))
The
server
function returns an instance of theServer
class. To stop it, pass the result into thejdk/stop
orjdk/close
functions:(jdk/stop server)
Since the
Server
class implementsAutoCloseable
interface, it’s compatible with thewith-open
macro:(with-open [server (jdk/server handler opt?)] ...)
The server gets closed once you’ve exited the macro. Here is a similar
with-server
macro which acts the same:(jdk/with-server [handler opt?] ...)
Parameters
The
server
function and thewith-server
macro accept the second optional map of the parameters:Name Default Description :host
127.0.0.1 Host name to listen :port
8080 Port to listen :stop-delay-sec
0 How many seconds to wait when stopping the server :root-path
/ A path to mount the handler :threads
0 Amount of CPU threads. When > thn 0, a new FixedThreadPool
executor is used:executor
null A custom instance of Executor
. Might be a virtual executor as well:socket-backlog
0 A numeric value passed into the HttpServer.create
methodExample:
(def server (jdk/server handler {:host "0.0.0.0" ;; listen all addresses :port 8800 ;; a custom port :threads 8 ;; use custom fixed trhead executor :root-path "/my/app"}))
When run, the handler above is be available by the address http://127.0.0.1:8800/my/app in the browser.
Body Type
JDK adapter supports the following response
:body
types:java.lang.String
java.io.InputStream
java.io.File
java.lang.Iterable<?>
(see below)null
(nothing gets sent)
When the body is
Iterable
(might be a lazy seq as well), every item is sent as a string in UTF-8 encoding. Null values are skipped.Middleware
To gain all the power of Ring (parsed parameters, JSON, sessions, etc), wrap your handler with the standard middleware:
(ns demo (:require [ring.middleware.params :refer [wrap-params]] [ring.middleware.keyword-params :refer [wrap-keyword-params]] [ring.middleware.multipart-params :refer [wrap-multipart-params]])) (let [handler (-> handler wrap-keyword-params wrap-params wrap-multipart-params)] (jdk/server handler {:port 8082}))
The wrapped handler will receive a
request
map with parsed:query-params
,:form-params
, and:params
fields. These middleware come from thering-core
library which you need to add into your dependencies. The same applies to handling JSON and thering-json
library.Exception Handling
If something gets wrong while handling a request, you’ll get a plain text page with a short message and a stack trace:
(defn handler [request] (/ 0 0) ;; ! {:status 200 :headers {"Content-Type" "text/plain"} :body "hello"})
This is what you’ll get in the browser:
failed to execute ring handler java.lang.ArithmeticException: Divide by zero at clojure.lang.Numbers.divide(Numbers.java:190) at clojure.lang.Numbers.divide(Numbers.java:3911) at bench$handler.invokeStatic(form-init14855917186251843338.clj:8) at bench$handler.invoke(form-init14855917186251843338.clj:7) at ring.adapter.jdk.Handler.handle(Handler.java:112) at jdk.httpserver/com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:98) at jdk.httpserver/sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:82) at jdk.httpserver/com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:101) at jdk.httpserver/sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:873) at jdk.httpserver/com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:98) at jdk.httpserver/sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:849) at jdk.httpserver/sun.net.httpserver.ServerImpl$DefaultExecutor.execute(ServerImpl.java:204) at jdk.httpserver/sun.net.httpserver.ServerImpl$Dispatcher.handle(ServerImpl.java:567) at jdk.httpserver/sun.net.httpserver.ServerImpl$Dispatcher.run(ServerImpl.java:532) at java.base/java.lang.Thread.run(Thread.java:1575)
To prevent this data from being leaked to the client, use your own
wrap-exception
middleware, something like this:(defn wrap-exception [handler] (fn [request] (try (handler request) (catch Exception e (log/errorf e ...) {:status 500 :headers {...} :body "No cigar! Roll again!"}))))
Benchmarks
As mentioned above, the JDK server although though is for dev purposes only, is not so bad! The chart below proves it’s almost as fast as Jetty. There are five attempts of
ab -l -n 1000 -c 50 ...
made against both Jetty and JDK servers (1000 requests in total, 50 parallel). The levels of RPS are pretty equal: about 12-13K requests per second.Measured on Macbook M3 Pro 32Gb, default settings, the same REPL.
-
Python Software Foundation
По мотивам событий с Линуксом обратим внимание на Питон. Итак, имеем Python Software Foundation, некоммерческая организация, у которой на уме только добро и радуга.
Смотрим: штаб-квартира в США, адрес Wilmington, Delaware, United States.
Все руководители из США: на странице персонала выделяем любое имя, копируем в Гугл и добавляем “linkedin”. Страну видно даже без перехода в профиль.
Ключевые спонсоры: NVidia, Bloomberg, Microsoft, AWS, Red Hat и другие.
Любой суд признает Питон цифровым продуктом США со всем последствиями. Не то чтобы я об этом волнуюсь, но нужно иметь в виду: в любой момент разговоры про опенсорс закончатся, и подключатся юристы.
-
Почтовые рассылки
Когда читаю рассылки Линукса или Постгреса, убеждаюсь: можно быть крутым разработчиком, но не уметь пользоваться почтой. Напомню главный критерий: никогда не цитировать все письмо. Нужно цитировать только то, на что конкретно отвечаешь или то, что было давно и теперь долго искать.
Цитирование всего письма — это засорение переписки и визуальный шум. Бывает, человек отвечает двумя предложениями, а за ними борода цитат на два экрана. Обязательно найдется чудак с консольным клиентом, который сломает цитирование левым тегом, и оно не будет распознаваться другими клиентами.
Наверное, на десять человек приходится один, у которого почта настроена нормально. Когда я смотрю на это, думаю: ты хоть видел со стороны, как выглядит переписка? В чем сложность зайти в опции и снять флажок, чтобы при ответе письмо было пустым? Сегодня даже самый кривой почтовый клиент выстраивает цепочки писем.
Перечитать: как пользоваться почтой.
-
Картина с Лениным
В одном из чатов скинули мем. Давайте проигнорируем текстовую часть и рассмотрим картину. Она хороша свой композицией, и сейчас я объясню почему.
Композиция в живописи — это такое расположение объектов, при котором они согласованы и уравновешены. Согласованность означает правильное расположение в пространстве, непротиворечивость углов, света, геометрии. Уравновешенность означает, что на каждый ключевой объект приходится парный, противоположный ему в цвете, размере, динамике.
Звучит непонятно, но вот несколько примеров. Центральный объект никогда не находится в центре картины, потому что иначе рушится композиция. Центр — это смерть композиции, ее тупик. Какой-то объект может быть в центре, но другие, более важные объекты, должны оттягивать на себя внимание зрителя. Большой темный объект можно уравновесить небольшим светлым с другой стороны. Статику уравновешивают движением. Например, когда герой заносит меч над чудовищем, его массу и статику уравновешивает тонкость и скорость меча.
Теперь посмотрим на картину. Очевидно, Ленин — главный персонаж, но он находится не в центре, а левее. Напротив него юноша, с которым он ведет диалог. Юноша “подсвечен”, чтобы было понятно, к кому обращается Ленин. Их лица — ключевые объекты картины, а между ними — указательный палец Ленина. Именно палец находится в центре картины, как бы говоря: истина здесь. Таким образом палец и лица по обе стороны образуют центр композиции.
Другие детали: в левой части находится сцена с обилием красного: знамя и скатерть. Этот красный уравновешен косынкой девушки справа. Ничто не мешало сделать косынку такой же блеклой, как одежда других людей. Но она именно красная, чтобы выступить противовесом.
Геометрия: обратите внимание на положение Ленина и зрителей. Ленин отделен от них небольшим коридорчиком, и в результате персонаж уравновешивает толпу. Если поделить картину ровно пополам, то получится один человек против многих. Это снова динамика, контраст величин. В целом толпа образует полукруг, все взгляды устремлены в центр — и композиция получается замкнутой.
Наверное, кто-то лучше разбирается в живописи и видит больше деталей. Но мне хватает и этих. Не важно, какое у вас отношение к Ленину — полюбоваться картиной стоит.
Полная версия картины:
“В.И. Ленин среди делегатов III съезда РКСМ”. Белоусов П.П., холст, масло.
-
Теория Дарвина
Теория Дарвина о происхождении видов считается главенствующей, занимает центральное место в учебниках. Но она так и не нашла поддержки в обществе. Как двести лет назад ее не принимали, так не принимают и сейчас.
Проверить это легко: спросите десять знакомых о том, что они думают о происхождении человека. Вам ответят про инопланетян, бога, высший разум, а также что все очень сложно. Может быть, один что-то скажет про Дарвина, но очень неуверенно.
Забавляет, что когда спрашивают про теорию Дарвина, употребляют слово “веришь”. Ты веришь в теорию Дарвина? Для меня это звучит как “веришь в синус” или “веришь в производную.” Все это модели, работа которых доказана — как в них можно верить или не верить? Ну, не веришь ты в производную — это ей все равно, ровно как и теории Дарвина.
Поэтому теория Дарвина как бы с нами, но как бы и нет. Каждый изучает ее в школе, чтобы позже переключиться на инопланетян.
Интересно, думал ли Дарвин о том, сколько времени уйдет на адаптацию общества к его теории? Сколько бы столетий он не прикинул — боюсь, он ошибался. Нужно еще.
-
Цветокоррекция
В последнее время раздражает цветокоррекция видео. Это когда накидывают слой, под которым все становится однотонным или близко к этому. Например, серых и металлических оттенков, бурых, цвета мокрого афальта.
Поставьте любой фильм на паузу и убедитесь, что картинка выглядит как сквозь бутылочное стекло.
На Хабре была интересная статья: кто-то прогнал все фильмы о Гарри Поттере через программу, которая строит гистограмму цветов. Не нашел ссылку, но помню красивые гистограммы и вывод: в каждом следующем фильме коррекции становилась больше. В последнем Поттере из цветов остались только зеленый и синий могильных тонов.
Я в курсе, зачем нужна коррекция, и я за то, когда ее применяют по делу. Например, в классической “Матрице”, когда действие происходит в программе, все зеленое. Когда герои перемещаются в реальный мир — цветное. Коррекцией выделяют особые моменты, например сны, кошмары или катастрофы. Коррекция нужна для компоузинга, чтобы актеры, фон и эффекты были согласованы.
Но сегодня такое чувство, что коррекцию ставят не задумываясь. Просто жахнули корректирующий слой в редакторе, потому что так делают другие. В результате цвета сузились до пещерных оттенков — серого, коричневого, бурого — и это считается круто.
Корректируют цвета в интервью, подкастах, обзорах техники — зачем? То же самое с фотографиями, например свадебными. Их нужно прогнать через сто фильтров с коррекцией. Сюда же эротика: снял ты красивое тело, молодец, но нет — нужно, чтобы оно сливалось с интерьером, как хамелеон.
Дизайнеры и монтажеры не понимают: когда одно и то же используется везде, оно приедается и выглядит глупо.
Замечаю такую же историю в играх. Запускаешь игрушку, пропускаешь логотипы и вжух — экран моргает, и накладывается глобальная коррекция цветов. Синий становится мокрым асфальтом, красный — бордовым, появляются серо-бурые оттенки. Если свернуть игру, можно наблюдать эффект в операционке. Опять же, зачем насильно глушить цвета? Кто просил?
Коррекция нужна, но слишком часто я замечаю обратное.
-
Память у Андроида (3)
И еще про Андроид. Я не хотел, но сама жизнь вынуждает.
Этим утром обратилась женщина, друг семьи. Классика: телефон — Андроид, 32 гига, забит под ноль фотками и видео всяких утренников. Вацап раздулся до 8 гигов. Женщина жила в таком режиме годами, телефон как-то шевелился. Но вот приплыли: Вацап устарел, просит обновить. Женщина не понимает, что от нее хотят.
Нажимаю “скачать”, Вацап перекидывает в Google Play. А там плашка: в целях безопасности подтвердите аккаунт, запрашивает пароль к гугло-почте. Разумеется, женщина не знает не то что пароль, а что такое гугло-аккаунт в принципе. Судя по всему, этот аккаунт ей создали в отделении связи, где она покупала телефон.
Сразу вопрос: какие именно “цели безопасности” преследует Гугл? В чем проблема обновить приложение? Это же всем на пользу: Гуглу, производителю, пользователю.
Пытаюсь подобрать пароль по фамилии и году рождения — Гугл не знает этой почты. Возможно, удалил из-за неактивности. Пытаюсь создать новый акк — не принимает российский номер.
Ладно, качаю APK с сайта Вацапа. Разрешаю установку из сторонних источников. Тыкаю на APK — он немного тупит, потом говорит, что не смог. Никаких деталей, ошибок, все молчком. Я думал минут десять, ребутнул телефон и догадался: бедняге не хватает места. А сказать об этом нельзя? Удалил левые приложения, какой-то утренник — и APK поставился.
Женщина видит Вацап и чуть не плачет от радости. У нее там родительский чат, секции внуков, подруги детства, соседи, ТСЖ, работа, клиенты. Предлагает деньги, еле отговорил. Представьте, что потеряли доступ к почте, на которой сидели 10 лет — вот так себя чувствовала она.
Я смотрю на это и не понимаю: почему нельзя сделать так, чтобы человек просто пользовался телефоном? Почему его нужно носить Ване-программисту, чтобы он работал? Почему нельзя продумать сценарии, чтобы избежать таких ситуаций? Опять пользователи не те попались?
Я не настаиваю насчет компьютеров: они явно не для людей. Это техника для обученного персонала. Но телефон, блин, это же повседневная вещь. Нам же показывали в презентациях: тыкаешь пальчиком, и оно все само. А на практике совсем не так. Неужели нам врали?
Какой-то сплошной гиговский бред, и ничего больше.