921 заметка с тегом

программирование

Статический анализ в Go

С интересом попробовал в действии gocritic — статический анализатор для Гоу, статья о котором в прошлом месяце появилась на «Хабре». Он в самом начале пути, но кое-что уже умеет.

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

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

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

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

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

Во-первых, в одном из циклов происходила итерация с копированием значения, цикл вызывается нередко, поэтому это заметное исправление.

rangeExprCopy: copy of utf (256 bytes) can be avoided with &utf

Во-вторых, в трёх местах анализатор посоветовал заменить «магические значения» на константы, которые оказывается (я не знал), есть в соответствующих модулях. Это полезно для читаемости кода и для самообучения — как результат я узнал что-то новое.

stdExpr: can replace "POST" with net/http.MethodPost

По моему мнению очень полезный проект, желаю ему дальнейшего развития!

13 июля   googlego   программирование

Падение libmemcached

С годами «Мемкешед» всё меньше кажется хорошим выбором в связке с ПХП. Всё время какие-то проблемы. Недавно столкнулись с очередной — при выставлении определённых опций распределения ключей на несколько серверов, модуль мемкешеда в ПХП иногда крашится вместе с интерпретатором.

Баг известный и проявляется на системах с libmemcached 1.0.16, а у нас ЦентОСь, там новее нету.

Пока отказались от этой опции, но когда-нибудь проблему всё равно придётся решить. То ли делать собственную сборку, то ли искать какой-нибудь доверенный репозиторий с версией посвежее.

11 июля   memcached   php   программирование

Третий параметр define

ПХП неисчерпаем, как атом, — читал какую-то статью о развитии языка (ссылку потерял) и узнал, что у функции define есть третий, необязательный параметр. Столько лет программирую на ПХП и не знал!

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

А ещё define возвращает результат — успешна ли операция:

@var_dump(define("True", false, true)); // bool(false), будет конфликтовать со встроенной константой
var_dump(define("True", false)); // bool(true)

Кстати, вторая строка константу вроде успешно устанавливает, но на деле воспользоваться ей невозможно — булевые константы языка к регистру нечувствительны и видимо перекрывают пользовательские. Странно, что тут нет ошибки, ещё один камень в огород ПХП.

1 июля   php   программирование

Злой ПХП

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

var_dump(DateTime::createFromFormat("d.m.Y", "01.01.1970"));
/*
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "1970-01-01 18:43:06.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(3) "UTC"
}*/

Совершенно неинтуитивно, что в разобранную дату в данном случае подставится текущее время. У меня даже нет идей для чего это могло бы пригодиться. А чтобы текущее время не подставлялось, нужно использовать символ «восклицательный знак» или «вертикальная черта»:

var_dump(DateTime::createFromFormat("!d.m.Y", "01.01.1970"));
/*
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "1970-01-01 00:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(3) "UTC"
}*/
25 июня   php   программирование

Загрузка на «Спектруме»

Игра «Ливингстон, я полагаю?», созданная испанскими разработчиками в ноябре 1986 года, выпускалась и версия под ДОС

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

Мощи́ у компьютера хватало лишь на небольшое разрешение 256×192, пиксели были по современным меркам чудовищной величины и чтобы их ещё больше не растягивать, но сделать экран зрительно больше, создатели «Спектрума» сделали вокруг экрана специальную одноцветную область «бордюра» — используя 254-й порт ей можно было задавать один из небольшого набора цветов.

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

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

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

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

Мы с братишкой тоже поучаствовали в общем безумии — приделали к игре «Ливингстон, я полагаю?», которая на скриншоте, загрузчик собственного изготовления, помню моя была идея и графика, а братишка больше программировал.

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

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

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

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

7 июня   speccy   программирование

Файл, состоящий из нулей

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

Предпринимаю вторую попытку посмотреть на язык программирования «Раст», первую я предпринимал, когда язык бурно развивался и меня быстро утомила скорость с которой устаревают примеры.

Почитал руководство, написал «Песню о пиве», теперь попробовал решить более практическую задачу — у одного нашего клиента после восстановления сбойной файловой системы часть файлов занулилась — внутри них одни байты с кодом ноль. Сейчас надо бы её просканировать и восстановить из бакапа всё испортившееся.

В общем, попробовал написать нужную утилиту на «Расте», если кто его вдруг знает, покритикуйте, кода там совсем немного.

2 июня   rust   программирование

Копирование при записи и reset

Когда-то в ПХП жили без копирования при записи (copy-on-write). Думаю некоторые олдскульщики ещё помнят, как когда-то приходилось для экономии обмазывать всё ссылками. Копирование при записи очень облегчает жизнь, но настолько расслабляет, что всё реже задумываешься как всё работает под капотом.

Многие ли увидят тут проблему?

function array_first(array $array)
{
	return reset($array);
}

Проблема в том, что reset меняет внутреннее состояние массива, а значит вызывает копирование при записи — в этот момент массив будет удвоен. Это небольшая неприятность для небольших массивов, но если в нём миллион элементов…

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

Но в общем случае использование тут reset — плохая идея, на мой взгляд, лучше сделать так:

function array_first(array $array)
{
	return current(array_slice($array, 0, 1));
}

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

К слову, в ПХП 7.2 функция each объявлена устаревшей.

25 мая   php   программирование

99 бутылок: Rust

64. Rust — довольно известный язык, на слуху, очень интересный своими концепциями. Пока писал «песню о пиве», даже захотелось познакомиться с ним поближе.

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

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

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

Тип u8 — это тип «байт», match — конструкция проверяющая совпадение с образцом, мощная вещь, умеет сопоставлять что угодно — значения, типы, реализованные методы и так далее, mut — ключевое слово, указывающая, что переменную можно модифицировать, по-умолчанию они константны, println с восклицательным знаком — макрос, в языке очень хороший макроязык, с поддержкой рекурсии.

// Beer song. Evgeny Stepanischev, 2018
fn bottles(beer: u8) -> String {
    match beer {
    	0 => "no bottles".to_string(),
    	1 => "1 bottle".to_string(),
    	_ => format!("{} bottles", beer)
    }
}

fn main() {
	let mut beer = 99;
	while beer > 0 {
	    println!("{} of beer on the wall, {0} of beer.", bottles(beer));
	    beer -= 1;
	    println!("Take one down and pass it around, {} of beer on the wall.\n", bottles(beer));
	}

	println!("No more bottles of beer on the wall, no more bottles of beer.");
	println!("Go to the store and buy some more, 99 bottles of beer on the wall.");
}
22 мая   99   rust   программирование

Как сконвертировать bytea

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

Ограничусь фотографией на которой почти ничего не видно, дабы не эпатировать публику

Отдельно про поездку рассказывать не буду, я вообще подумал, что пора завязывать с публикациями на такие темы, а пока ехал, накидал на коленке функцию на Пайтоне, положу сюда, чтобы не потерялась:

def decodeBytea(bytes: bytearray, charset: str) -> str:
	if bytes[:2] == b'\\x':
		return bytearray.fromhex(bytes[2:].decode()).decode(charset)
	else:
		raise ValueError('Invalid format')

Формат немудрёный — впереди слеш-экс, дальше идут шестнадцатеричные коды байт, которые надо превратить в символы.

20 мая   postgres   python   программирование

Модуль PHP на Go

Потешную штуку показали на днях — php-go, позволяет писать модули для ПХП на Гоу. У меня как-то такой потребности не возникало, но попробовать-то интересно!

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

Ссылка давно протухла, но «Вебархив», к счастью, имеет копию страницы — статья называется «Ridiculous UTF-8 character counting».

Программа там на Си, я её минимально подпилил, чтобы она нормально компилировалась, завернул через cgo в Гоу, а оттуда при помощи php-go протащил как модуль ПХП.

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

Зато попробовал php-go, вещь предельно простая, в случае нужды можно будет что-то быстренько набросать с её использованием.

15 мая   php   программирование   язык гоу
Ранее Ctrl + ↓