Я - автор двух пакетов, входящих более-менее во все дистрибутивы Linux: sane-airscan и ipp-usb. Кроме того, sane-airscan входит во все основные дистрибутивы BSD (FreeBSD, NetBSD и OpenBSD) и в ChromeOS. ipp-usb в ChromeOS не взяли потому, что он написан на Go, а у них там очень жестко с размером исполняемых файлов, вместо этого они написали свое на Rust, но предпочли бы взять моё изделие, если бы могли. Совсем недавно появился порт ipp-usb на FreeBSD, вероятно, другие BSD тоже скоро подтянутся. Вместе эти два пакета образуют стек "бездрайверного" сканирования документов для Linux и *BSD, а в перспективе нескольких лет, когда старые сканеры, наконец, вымрут, вероятно других драйверов и не останется. Кроме того, ipp-usb делает возможным "бездрайверную" печать на USB-устройствах. Здесь я хочу рассказать, каково оно, быть автором популярных OpenSource пакетов. Хоть эта работа и не принесла мне особых денег (на что я, впрочем, особо и не рассчитывал), она принесла мне бесценный опыт. В целом, я полагаю, продвижение OpenSource пакетов структурно близко к продвижению на рынок программных продуктов. Занимаясь этой деятельностью, очень хорошо начинаешь понимать разницу между (1) написать программу, которая работает для меня (2) написать программу, которую можно назвать продуктом (3) вывести продукт на рынок.  Первое занимает гораздо меньше времени, чем второе. Второе - гораздо меньше времени, чем третье. Началось все довольно банально: я купил себе многофункциональный принтер со сканером, который под Linux не сканировал. Немного осмотревшись, я узнал, что протокол моего сканера называется eSCL, что спецификация его не опубликована, но существует reverse engineering этого протокола, в целом протокол не сложный, и даже существует скрипт на Питоне, который, впрочем, с моим устройством не слишком-то работал. Сам по себе протокол состоит из поиска устройства с помощью DNS-SD (оно же MDNS, Randezvois, Bonjour - этому протоколу повезло иметь много названий) и общения с устройством посредством сочетания HTTP с незамысловатым XML внутри. Я посмотрел на то, что такое драйвер SANE и подумал, "тыжпрограммист", почему бы не попробовать написать драйвер самому. Задача, к тому же, выглядела совсем не сложной. Ну и сел писать. Начиная, как положено, с системы сборки, логов, общей инфраструктуры драйвера, парсера файла конфигурации и т.п. А не с того, чтобы быстренько написать пару запросов на libcurl, а потом как-нибудь довести это до состояния, напоминающего драйвер SANE. Я ж профессиональный программист, в конце концов, а не студент 3-го курса :) От использования libcurl, кстати, пришлось быстро отказаться. Драйвер SANE, по природе своей, это shared object, DLL-ка, которая работает в контексте приложения. Любого приложения. Например, такого большого и сложного, как Libre Office. А libcurl имеет статическое состояние, которое надо инициализировать явным запросом перед использованием и делать наоборот после. И если в контексте приложения окажется две DLL-ки, использующие libcurl, то они запросто могут подраться между собой. В процессе выяснилось, что у меня появились конкуренты, студенты из франции с драйвером sane-escl, опередившие меня буквально на две недели. Я даже подумал было бросить это дело, но посмотрев на их исходники, решил все же продолжать. Студентов, тем временем, взяли в проект SANE, куда я планировал попасть изначально. Очень уж в проекте SANE не хватало драйвера eSCL. А мне пришлось пробиваться. Тут следует немного объяснить, что такое "бездрайверное" сканирование и печать (driverless), и что такое драйвер бездрайверного сканера. Если кто помнит, раньше все принтеры были разные. И каждому требовался свой драйвер. Драйвера, естественно, были только для Windows, а пользователям других операционных систем приходилось тщательно выбирать устройство, которое будет работать под их операционной системой. Microsoft, по-видимому, устраивала возня с вендорами аппаратуры и их драйверами, а вот фирме Apple это в какой-то момент надоело. И Apple встал в положение: принтеры с поддержкой IPP работают на маке из коробки, а для всех прочих производители вольны поставлять драйвера, если хотят, а мы тут не при чем. Если учесть избалованность пользователей мака тем, что все работает "само", их многочисленность к моменту, когда это произошло и их платежеспособность, не удивительно, что эта технология победила. И теперь более-менее все принтеры худо-бедно поддерживают IPP. Это называется "бездрайверная" печать - в том смысле, что не драйвер подстраивается под устройство, а устройство подстраивается под драйвер, который реализует один, универсальный, протокол. Потом Apple то же самое проделали со сканерами. По-ихнему это называется Bonjour Scanning, который является частью неопубликованного Bonjour Printing 1.4 (выдается только под NDA, мне не дали, но я особо и не просил), неофициально называется Apple Airscan (по аналогии с Airprint - более ранним названием Bonjour Printing) в более узких кругах известно под названием eSCL. Автором самого протокола, по-видимому, является HP, но это не точно. Сейчас еще не все сканеры поддерживают eSCL, но дело туда явно идет. Поскольку HTTP подразумевает сеть, а бывают устройства без сети, а только с USB, то с этим тоже надо что-то делать. В результате организация, занимающая стандартизацией USB, изобрела протокол под названием IPP over USB, который вернее надо было назвать HTTP over USB, потому что он этим и является: прям в USB endpoint отправляется HTTP-запрос, а на него обратно приходит HTTP-ответ, и так работает все HTTP-ное: печать, через IPP, который пользуется HTTP-транспортом, сканирование, через eSCL и даже веб-консоль принтера через него тоже удивительным образом работает. И там все тоже не совсем просто, потому, что HTTP, в общем-то, рассчитан на TCP. А TCP-соединение можно в любой момент закрыть, и сервер все поймет правильно, что клиент не заинтересован в продолжении запроса. А в USB никакой индикации того, что клиент отвалился, не предусмотрено, поэтому если уж клиент начал посылать запрос, то запрос надо дослать до конца и вычитать ответ. Иначе кусок недопосланного запроса или кусок недополученного ответа застрянет в USB-буферах, и синхронизация между хостом и устройством будет потеряна. И ее не так-то просто потом восстановить. На USB-reset, например, разные устройства реагируют по-разному... И вот в какой-то момент мой драйвер дошел до состояния, когда его было не стыдно показать людям (я из тех людей, кто не любит показывать или анонсировать недоделанную работу). Ну и я, весь такой наивный, зафайлил в sane-backends багу #202 с предложением sane-escl выкинуть, а вместо него вставить моё изделие. Что тут началось... Главный мейнтейнер проекта SANE спросил ребят, которые написали sane-escl, что они думают о моем поделии. Ну они понятно что сказали, что думают (у них, к тому же, тестовая база была из десятка разных устройств, а у меня из одного. Ну и они нашли, конечно, в своей тестовой базе несовместимые устройства, и только о них и написали). В итоге случилась война за рынок сбыта, результатом которой явилось следующее: sane-airscan не вошел в дистрибутив SANE. Сначала не брали, а потом я уж и сам не захотел в sane-airscan появилась поддержка еще одного "бездрайверного" протокола, WSD от Microsoft. sane-airscan вошел во все дистрибутивы Linux sane-escl входит в состав SANE, но в большинстве дистрибутивов запрещен Эх, был бы я политиком потоньше, предложил бы не заменить одно на другое, а положить вместе. Глядишь бы, WSD писать не пришлось :) В конечном итоге, то, что мой проект существует отдельно от SANE для меня хорошо. И цикл релизов у меня свой, как мне удобно, и вся слава достается мне :) Последствием неудачной попытки войти в состав SANE стало то, что sane-airscan вышел под SANE-овской лицензией (GPL с исключениями, фактически - LGPL). Я не люблю эту лицензию, считаю ее слишком жадной, и если бы не оглядывался на SANE, использовал бы 2-clause BSD. Пользователи, правда, выиграли. Как потом выяснилось, примерно 1/3 устройств, на которые я получил ответ от пользователей (а у меня нет своей тестовой базы, вся отладка по переписке) поддерживают только WSD, но не eSCL Сколько у меня в итоге пользователей? Я не знаю. В списке сейчас 170 устройств. За каждым стоит какая-то история. По большей части люди приходят сказать, что у них какая-то проблема. Многие проблемы разрешались без моего участия, мне только сообщали, что очередное устройство заработало. Некоторые пользователи приходили просто поблагодарить. Кое-кто даже присылал PR со своим устройством, добавленным в список - я никогда не отказывал им в merge. Думаю, что количество пользователей, которые просто молча пользуются, не подозревая о моем существовании, измеряется тысячами. Возможно, десятками тысяч. Как это узнать, мне неизвестно. Продвижение в основном заключалось в том, что я время от времени заходил в англоязычные форумы пользователей Linux и советовал гражданам с проблемами попробовать мой драйвер. Чтобы это было возможно, пришлось научиться собирать пакеты под основные дистрибутивы. Потому что для нормального пользователя, конечно, идея собрать что-то самому, ну, это как подвиг, примерно, совершить (хотя бывают и исключения). Для этого в природе существует openSUSE Build Service, который, на удивление, умеет собирать пакеты под кучу дистрибутивов, а не только под SUSE. Но разобраться в нем нелегко, документация у него довольно своеобразная. Но зато потом все работает, и не надо учить пользователей собирать программы. Другая важная составляющая успеха в деле продвижения - это поддержка пользователей с проблемами. Тут требуется много терпения. Не все пользователи обладают достаточной квалификацией. Для некоторых просьба прислать нужный файл из нужной директории является непростой задачей. Некоторые проявляют чрезмерное рвение. Пришлет он тебе лог, из которого почти все уже понятно, и осталось еще совсем чуть-чуть дополнительно проверить, а за время, пока ему отвечаешь, выяснится, что он систему три раза переставил, сменил дистрибутив и еще сунул свои руки во всякие разные неожиданные места, и начинай всё с начала. Первым дистрибутивом, который принял мой драйвер в свой состав, был Arch. Потом подтянулись Ubuntu, Debian и Fedora. Потом оно пошло как-то само. Российские дистрибутивы (Alt и Astra) подтянулись очень поздно, с большой задержкой по сравнению с их западными коллегами. За другими я не следил и не в курсе, что там делается. Интересно, что в Ubuntu новые пакеты попадают через Debian. Они там активно взаимодействуют между собой, и Ubuntu очень предпочитает основываться на Debian-овской кодовой базе. Минуя Debian, пакет попадет в Ubuntu только в том случае, если Убунте очень хочется этот пакет у себя иметь, а Дебиану почему-то очень не хочется. Интересна так же разница в подходах. Debian/Ubuntu сделали очень дотошный code review глазами, Fedora прогнали через статический анализатор. Остальные дистрибутивы не заморачивались, и брали, как есть. Так же стоит отметить, что такой контроль есть только при первоначальном включении пакета в дистрибутив. Потом мои патчи никто уже особо и не смотрел - разве что из любопытства. Я с самого начала понимал, что мне придется иметь дело с несовместимыми устройствами, находящимися в руках неквалифицированных пользователей. Поэтому сразу позаботился о качественной системе логирования. Из логов должно быть понятно все, что происходит. Конечно, сразу этого не получилось, иногда возникали ситуации, когда что-то происходит, а деталей по логам не видно, приходилось добавлять недостающее. При этом следует отметить, что идея писать в логи вообще всё подряд, иногда по пять раз одно и то же (потому, что на разных уровнях), она такая себе. Такие логи очень трудно читать, они сбивают с толку избытком ненужных подробностей. В идеале, в логе должны быть отображены все разветвления в программе и информация, на основании которой принято решение разветвиться. И желательно без пропусков и без повторений. Сам по себе многолетний опыт отладки по логам, а не отладчиком, приводит к формированию особого стиля организации кода. Стараешься основные сюжетные линии развивать, по возможности, просто и прямолинейно. Иначе потом очень сложно разобраться. Я считаю, что это существенно улучшает и структурирует код. Есть большой смысл писать в лог конфигурацию вашей программы и имеющую отношение к делу конфигурацию системы, сведения об оборудовании и т.п. - это куда, как проще и надежнее, чем выяснять эту информацию, задавая пользователю вопросы (часть из которых будет ему непонятна или будет неверно проинтерпретирована). Поскольку я с самого начала предполагал, что часть проблем будет связана с декодированием изображений, полученные со сканера изображения тоже надо куда-то складывать. Писать их в основной лог неудобно, они большие и бинарные. Плодить кучу файлов - потом замучаешься объяснять пользователю, что именно мне из этого надо. В итоге было принято решение параллельно .log-файлу писать еще и .tar-файл, складывая туда полученные изображения и ответы, которые мне не удалось расшифровать. У .tar-а очень простой формат, и генерировать его прямо из программы совсем несложно. Фактически, .tar - это последовательность файлов, в которой на каждый файл пишется несложный заголовок, а потом идет тело файла. В основном с проблемами в прошивках. Прошивки принтеров на удивление глючные. Незначимый пробел в XML-е будет проигнорирован одними устройствами, вызовет ответ с невнятной ошибкой у других устройств и отправит третьи устройства в перезагрузку (я не шучу). Устройства enterprise класса ничуть не менее глючны, чем бюджетные устройства потребительского сектора. Более того, они еще умеют засыпать и по полминуты просыпаться, ведя себя в полусонном состоянии странным образом, и это приходится учитывать. Некоторые устройства от HP хотят зачем-то, чтобы в HTTP-запросе, в поле Host: было написано localhost. А иначе не работают. Что это, наивная защита от доступа из сети? Непонятно. Как я догадался, что они этого хотят? Не знаю, интуиция сработала. Но как-то вот догадался. В силу особенностей SANE, сразу после возврата из функции, которая запускает процесс сканирования, драйвер обязан правильно отвечать на вопросы о фактических параметрах изображения (а не о запрошенных, они могут отличаться). sane-escl решает эту проблему, зависая в запросе на начало сканирования до его фактического завершения, я же пошел более сложным путем: мой драйвер возвращается из запроса на начало сканирования сразу, в качестве фактических параметров спекулятивно возвращает запрошенные, а вот если картинка разошлась с ними, приводит фактическую картинку в соответствие с обещанными параметрами. Благодаря этому в моем драйвере корректно работает cancel. Некоторые устройства присылают картинку большего размера, чем попросили, округляя размеры вверх до удобного им размера - пришлось сделать обрезание. Потом этот механизм мне пригодился, когда выяснилось, что в режиме WSD некоторые устройства вообще игнорируют запрошенный размер. Некоторые устройства могут в ответ на просьбу сделать черно-белое сканирование прислать в ответ RGB-файл. В котором может быть черно-белая картинка, но RGB, а может быть и цветная. Пришлось сделать пересчет цветной картинки в черно-белую. Потом я немного обобщил этот механизм, и сделал in-software управление яркостью и контрастом (хотя надо бы сделать in-hardware для тех устройств, которые умеют, потому что некоторые из них реализуют управление яркостью, изменяя яркость подсветки, а не пересчитывая сигнал с сенсора, и это дает лучший результат на плохих изображениях). Недавно мне попалось устройство, которое анонсировало поддержку PNG, но фактически присылало JPG. Пришлось сделать автодетект формата по сигнатуре файла. Некоторые устройства заявляют возможность сканировать с большим разрешением, но фактически ее не реализуют. Видимо, памяти не хватает. Приходится распознавать их и не верить их обещаниям - мой выбор возвращать параметры картинки, не получив еще саму картинку, имеет не только свои достоинства, но и свою цену. Я долго колебался, стоит ли с этим связываться. Но хотелось иметь неоспоримое конкурентное преимущество перед sane-escl Microsoft, как известно, это своя особая вселенная, наполненная своими звездами и планетами, на них проживает свое особое человечество. И все сетевые протоколы у них тоже свои. Идея бездрайверной печати и сканирования не прошла мимо них, но сделали они все по-своему. Это называется, WSD. Web Services for Devices. WS-Print и WS-Scan. При чем тут Web, не вполне понятно, никто не собирается свой родной принтер в Интернет выставлять, он там долго не проживет. Но Microsoft, зачем-то, провели WSD как стандарты W3C. Причем есть два диалекта: один, который описан на MSDN-е, а другой - в W3C-ных стандартах. Они как бы одинаковые, но URL-и, которые обозначают XML-ные namespaces - разные. Мой принтер понимает оба варианта, другие не проверял. Но реализовывать, разумеется, лучше тот вариант, который в Windows. Понятно, что производители принтеров ни с каким другим никогда не тестировали свои изделия. WSD - это целый собственный мир. У них даже поиск устройств в сети не на основе DNS-SD, а свой собственный. На основе XML-ек, которые рассылаются UDP-мультикастами. И в отличии от DNS-SD, готовой такой службы в Linux не было, пришлось ее самому, прям в драйвере, написать. В конечном итоге, как выяснилось, примерно 1/3 устройств, которые понимают WSD, при этом не понимают eSCL. Так что оно того стоило, многим людям я открыл в Linux поддержку для их устройств. Хотя в более долгой перспективе, WSD, вероятно, умирающий протокол. Для печати он никогда особо и не использовался, потому что был IPP, для сканирования в Windows 11, говорят, наконец добавили eSCL-клиента. Так что у производителей оборудования особой мотивации поддерживать WSD вроде как не осталось. Ну может разве только на каком-то очень крутом enterprise-рынке, ориентированном на экосистему Microsoft... Про это стоит сказать еще пару слов. Представьте себе, ваше устройство поддерживает IPv4 и IPv6, HTTP и HTTPS, eSCL и WSD. Да еще и подключено по WiFi и проводами. В результате, вы найдете его в сети... 16 раз, во всех возможных сочетаниях. Вываливать всё найденное на голову бедному пользователю - пусть студенты так делают. Это не наш метод. В результате, примерно 1/4 кодовой базы sane-airscan - это сведение вместе всех вариантов, в каком виде может быть найдено одно и то же устройство. Тот факт, что DNS-SD и WSD пользуются совершенно разными пространствами имен, совсем не упрощает этой задачи. Кроме того, DNS-SD, фактически, читает список уже найденных устройств из кеша демона Avahi. А вот WS-Discovery приходится все делать самому, на старте драйвера. И чтобы все это работало надежно, недостаточно один раз послать мультикастный запрос, немного подождать ответов и на этом успокоиться. Приходится сканировать несколько секунд - я рискнул поставить это время в 2.5 секунды. Но даже это слишком долго. Поэтому пришлось изобрести хитрый алгоритм: если все устройства, которые найдены, как IPP-принтеры (по DNS-SD) откликнулись или как WSD-устройства, или как eSCL-сканеры, дальше можно поиск не продолжать. Я рассчитываю на то, что чистых сетевых сканеров, без принтерской части, в природе встречается мало, а сканеры, объединенные с принтерами, откликаются на протокол IPP, потому, что он все же основной для печати. В большинстве случаев этот алгоритм существенно сокращает время поиска. Теоретически, в некоторых случаях он может находить устройство нестабильно, и для борьбы с этим его можно выключить через настройки драйвера, перейдя на прямолинейное полное сканирование. Но никто пока не жаловался... Изначально я не собирался его писать. Более того, я даже не подозревал о существовании такого протокола. Первым человеком, который написал bug report на sane-airscan был Till Kamppeter - человек, который отвечает за систему печати в Linux вообще и в Ubuntu в частности. Till - потрясающий совершенно инженер, работать с ним одно удовольствие. При удаленной отладке он с полуслова понимает, чего я от него жду, и делает ровно то, что надо - как если бы я сам сидел с другого конца, только лучше. Очень и очень редко выпадает удовольствие поработать с таким человеком. Принтер, которым он располагал, был тоже совершенно потрясающим. Недорогой какой-то HP, в котором были реализованы все интересные протоколы. Кажется, это замечательное устройство собрало в себе если не все, то уж по крайней мере 90% багов прошивок. Если что-то работало на принтере Till-а, ну, я был почти уверен, что оно и на других устройствах заработает. В какой-то момент Till спросил, а почему sane-escl работает на его принтере через USB, а мой драйвер - нет. Собственно, ipp-usb был ответом на вопрос. До него в Linux был ippusbxd - демон, который просто принимал TCP-соединения и релеил их в USB. Я не собирался туда лезть, но вот пришлось. У меня тогда не было IPP over USB устройства (вернее, не было кабеля, который втыкается в принтер. Они там не такие, как все, а с квадратным разъемом). Поэтому отлаживаться пришлось с Till-ом по переписке. Выглядело так, словно иногда ответ на HTTP-запрос приходил в обрезанном виде. Сначала я подумал, ippusbxd глючит. Все-таки, он многопоточный, по потоку на TCP-соединение, и написан очень по-простому. Мог бы и запутаться среди своих потоков. Внимательно его вычитал всего. Ну нет явных ошибок, хоть ты тресни. Потом меня осенило, что возможно, кусок предыдущего ответа остается в буфере самого USB. И что возможно это происходит потому, что sane-airscan в некоторых случаях не заморачивался дочитывать ответ до конца, а просто бросал соединение, когда ему уже все было понятно. Я быстренько, буквально за несколько часов, написал на Go и отладил с Till-овской помощью прототип HTTP-to-USB proxy, который всегда доводил HTTP-транзакцию до конца, если уж начал, независимо от заинтересованности клиента в продолжении. И все прям заработало: sane-airscan, печать, веб-консоль, которая через ippusbxd вообще никогда не работала и никто не знал, почему. А вот чтобы этот работающий прототип превратился в подобие продукта, ушел месяц. За это время мне пришлось: сделать анонс устройства через DNS-SD. Для этого пришлось научиться извлекать параметры устройства через IPP для принтерной части и через eSCL для сканерной части. А для этого пришлось написать клиентскую библиотеку IPP, потому что готовой работающей для Go, к моему удивлению, не нашлось, а которая была, падала в панику, а чтобы ее починить, надо было разобраться в протоколе, а в протоколе разобраться было проще всего, написав свою реализацию, которая не падает в панику, а раз уж я ее написал (что заняло, впрочем, два дня всего), то уже имеющуюся чинить не захотелось отказаться от http.Client, потому что он в Go, в основном, автоматический менеджер HTTP-соединений, а мне в этом месте совершенно не хотелось никакого автоматизма, а хотелось иметь полный контроль над происходящим отказаться от готового Go-ной обертки над libusb и приладиться к libusb напрямую через cgo, потому, что появились какие-то другие глючные устройства, и хотелось быть к железу поближе, чтобы сподручнее было с ними разбираться сделать логи с авторотацией сделать конфигурационный файл. Потом Till попросил не использовать стороннюю библиотеку потому, что Go их качает сам, а система сборки дистрибутивов линукса работает в сетевой изоляции, и каждая лишняя внешняя зависимость - это аццкий геморой, и мне пришлось переписать парсер руками (вернее, спортировать свой старый, Сишный, на Go) сделать запуск демоном из systemd и без написать man-page И вот когда все это было сделано, из работающего прототипа получился продукт, и это заняло месяц (вспомним, что прототип был написан за несколько часов). А вот чтобы уже вполне работающий и оформленный продукт попал в основные дистрибутивы, прошло еще несколько месяцев, порядка года - это при том, что Till мне изрядно помогал в организационном плане. И вот этот урок, про разницу между написанием программы, превращением ее в продукт и выводом на рынок, я запомнил навсегда, это был весьма поучительный опыт (обычно это делает организация, и большая часть этой деятельности проходит мимо программистов и ими не осознается). Обычно мы, программисты, общаемся с Google на собеседованиях или поступаем туда на работу или что-то в этом роде. Как автор опенсорсных проектов, в которых Google был заинтересован, я общался с Google, как две равные сущности. Они присылали мне свой код на ревью, я капризничал и просил переделать (ну, на самом деле, я не очень вредный. Но они решали свои проблемы, а мне всем этим хозяйством потом владеть). Они переделывали и приходили снова. Они обсуждали со мной, как лучше сделать те или иные вещи, и слушали, что я им говорю. Иногда соглашались, иногда возражали, но это был разговор двух равных партнеров. Они хвастались, что перепишут ipp-usb за пару недель на Си (на Go они взять в ChromeOs не могли, из-за размера), но не смогли, и приходили ныть, что не смогли. Намекали, что может я возьмусь, но денег не предлагали, и я не взялся. Потом переписали на Rust-е, это у них получилось. Потому, что для Rust-а есть нормальный HTTP в библиотеке, а для Си нету. А написать руками у них не хватило пороху, а у меня - мотивации. Не важно, что у них миллиарды долларов и они владеют всем Интернетом мира, а я - отдельный физический человек. Мы говорили, как равные, с равным уважением друг к другу. Это очень необычный опыт. OpenSource имеет плохую репутацию кода, который каждое очередное обновление может сломать (хотя глядя на последние новости в области обновления Windows начинаешь задумываться, так ли уж заслужена эта репутация). Проблема в том, что если бы я был корпорацией, у меня был бы стенд с сотней устройств, и каждый релиз проходил бы тестирование на всех устройствах. Но я не корпорация, у меня нет тестового стенда. И я не могу попросить моих уже довольных пользователей перетестировать каждое обновление. Их проблема уже решена, они не хотят об этом больше думать, они хотят, чтобы всё просто работало, как раньше. Приходится быть очень осторожным. Приходится думать о том, чтобы каждое следующее обновление, по возможности, не меняло поведение программы на уже проверенных устройствах. Иногда поведение приходится менять - тогда надо тщательно продумывать последствия. В целом, мне это пока удается. Не смотря на то, что работа с широким спектром оборудования - это как хождение по граблям, и никогда не знаешь, где стрельнет, я на удивление мало чего поломал. Вероятно, сказывается многолетняя привычка работать не по принципу "что-то накрутили, оно почему-то заработало, мы не знаем, почему, но работает - и хорошо", а всегда стараться докапываться до сути, не оставляя за спиной тонны технического долга. В конце концов, стреляет именно из него, из тех пластов кода, который вы до конца не понимаете, почему он работает. И вы что-то в нем трогаете, и работать перестает. Если у вас нет (или мало) такого кода, он не имеет привычки неожиданно стрелять. И нет, это не отнимает кучи времени. На самом деле, если вы полностью контролируете свой код, разработка идет легко и быстро. Просто не надо срезать углы и отправлять в релиз код, который работает чудом, а не потому, что так и задуман. На удивление, ничего не изменилось. Отношение зарубежных коллег и пользователей осталось прежним. Меня один раз спросили, нет ли у меня проблем с доступом и не надо ли чем помочь, и на этом все. Больше темы политики никто не касался. Хорошо, что в мире остались еще какие-то области, куда тревожные политические вопросы пока не просочились. И хорошо, что программное обеспечение остается достоянием человечества, а не одного какого-то народа. По крайней мере, то, которое с открытыми текстами. На мой взгляд - да. На человека с двумя успешными проектами, пусть и достаточно нишевыми, по-другому  смотрят на собеседовании. Сам по себе опыт самостоятельного ведения проектов, когда всё сам, а не тикеты в TFS-е закрываешь по команде менеджера - он совершенно ни с чем не сравнимый и очень полезный. Приучает к самостоятельности, к планированию, к разумному целеположению и т.п. Учит не разбрасываться силами, у меня же не бесконечное количество ресурсов, а денег мне сама по себе эта деятельность не приносит. Чисто технически, работать в своем собственном проекте очень комфортно. Сам себе архитектор, сам себе программист, сам себе отдел контроля качества. Нет никаких согласований между отделами, решения принимаются взвешенно и комплексно. Если, конечно, любишь и умеешь это все делать. Опыт продвижения на рынок - это то, с чем программисты вообще редко сталкиваются. За них это обычно делает работодатель. Свой собственный опыт избавляет от многих иллюзий. Например, становится понятно, что компания делает для меня, а не только, что я делаю для компании. Начинаешь понимать (не в теории, а на опыте), что написание работающего, отлаженного, проверенного кода - это очень сильно меньше, чем половина работы по созданию продукта. Большую часть времени занимает вовсе даже не багфиксинг, как иногда любят говорить, а вот создание тех самых мелочей, которые, в совокупности, и отличают прототип от продукта, и которые, каждая сама по себе, кажутся не очень обязательными и не очень объемными, но вместе набегает, как надо. Очень много времени занимает само по себе продвижение. Даже не усилий, а именно времени, никому неизвестный продукт никому и не нужен, а известность нарастает весьма неторопливо - даже если сама по себе программа хороша.  Программист на все руки