Category: it

Category was added automatically. Read all entries about "it".

cat with many words

Временной аспект

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

Любая система живет во времени. В таблицах хранятся актуальные сущности. Вот у вас пользователь, у него такие-то свойства - имя, теги какие-нибудь. Допустим есть еще другие сущности - покупатели, продавцы, товары. Но есть еще и артефакты, которые эти сущности производят - транзакции, товары и т.д. И для них внезапно оказывается важно знать, в каком состоянии были эти сущности в момент создания артифката. Была ли скидка у пользователя, когда он купил товар? Был ли этот товар в продаже в ринципе?

Второй временной аспект заключается в том, что к компьютерным системам отлично подходит срванение с едущим на полном ходу автомобилем, который на ходу доделывают его пассажиры, мало того, сервис развивается в жесткой связке с данными. Если взять код годовалой давности, он просто не заведется с текущей моделью данных. Обычно изменения делают по очередь - то код, то данные, чтобы не сломать обратную совместимость. Следствие из этого - и в коде, и в данных постоянно есть части находящиеся в переходном состоянии. Какие-то пользователи еще используют ваше старое api, какие-то пользователи не смигрировали со старого аккаунта на новый.

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

cat with many words

c++

Читаю сейчас Beginning c++ from Novice to Professional, впечатления невероятные. C++ оказался именно таким языком, каким я его и представлял по обрывочным впечатлениям там и сям. До реально сложных вещей я еще не дошел, сейчас глава про references (как их там по-русски), но предыдущего введения уже хватило, чтобы составить впечатления. Интереса ради отмечаю в книге места, где автор предупреждает об очередном месте, где можно выстрелить себе в ногу.

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

Например:

  • Есть три разных способа инициализации переменной, часть с приведениями типа, часть нет
  • При передаче массива в качестве аргумента, теряется возможность узнать его размер, при этом объявить желаемую размерность можно. Если массив двумерный, то у второго измерения размер узнать или указать можно, будет работать.
  • Строки надо использовать std::string, они вроде бы конкатенируются через плюс, но не всегда, чтобы работало и литералами, нужно, чтобы один из аргументов был std::string, а то сломается.

Например,

"this" + "that" + some_str

по словам автором должно сломаться, т.к. литералы будут типа char*, и их сложение не определено. А вот так, например, работать будет

"this" + ("that" + some_str)

  • Строки можно складывать и с символами, но и тут есть засада. Если сделать так:

str += ',' + ' ';

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

  • Ссылку на переменную надо очищать с помощью delete, ссылку на массив - с помощью delete[], но т.к. во многих местах массив даже передается как ссылка на элемент, точасто просто невозможно узнать, какой именно вызов делать, а перепутать нельзя.

Я уверен, что каждый опытный c++ мигом отделает меня как бог черепаху и расскажет, почему каждый из этих пунктов имеет абсолютно понятный и четкий смысл - легаси, эффективное управление памятью, наследие С и так далее. Я был в такой ситуации, но с другими технологиями и также рассказывал, почему все сделано, так как сделано, и в той ситуации, в какой технология оказалась, эти объяснения имели смысл.

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

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

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

Также понятно, почему ценят и любят опытных c++-программистов - уметь быстро и беспроблемно писать код на подобном языке действительно достойно всяческих похвал и уважения. Пока что кажется, что процесс похож на рубку леса ужасно эффективной бензопилой, придерживая ее за острие при работе. Вроде все нормально идешь, даже начинаешь улыбаться, а потом вдруг - хуяк! И нет руки.

cat with many words

Ada

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

  • Компилятор продается. Есть бесплатная версия, но она под GPL и каким-то образом, видимо через стандартную библиотеку распространяет GPL на все продукты компиляции. Есть еще и FSF версия без этих недостатков, но та отстает от первых двух и наверняка чем-то убога.

  • IDE есть, но ставить его надо через определенное напряжение сил, из debian и как следствие ubuntu пакеты вообще выбросили из-за жутких сложностей со сборкой. Казалось бы, вот он момент, чтобы упаковать эту прелесть в snap, нo, вероятно, клиенты adacore просто заставляют своих разработчиках сидеть на нужных операционках.

Есть расширение для vscode, но документация в районе нуля.

И это все у языка, который на минуточку с восьмидесятых активно развивается и используется.

Прямо пот на лбу выступил, как на common lisp похоже.

cat with many words

Про программирование, выпуск 6

Корректность

На самом деле корректный код писать довольно просто, если придерживаться нескольких правил:

  • Проверка данных на входе
  • Правильная модель данных
  • Понимание инвариантов и корретных состояний

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

Говоря об ошибках, главная ошибки - это возвращать одну и ту же ошибку по разным поводам (в этом случае сложно сделать правильную обрбаботку в зависимости от случая), а так же просто пробрасывать ошибки вверх по стеку. Наверняка у каждого было - запускаете приложение, а оно валится с чем-то невнятным типа "file not writable". Потом окажется, что это какая-то левая подсистема в лог не могла написать.

Правильная модель данных - это то, что отличает нормальный код от лапши, в которой никто и никогда не разберется. Что значит правильная? Это значит, что в ней можно описать все состояния предметной области, и в ней не представимы состояния, которые в этой области невозможны. Это чрезвычайно помогает, т.к. часто в коде надо все возможные состояния отрабатывать (если не отрабатывать, то неуловимые баги начнутся почти сразу). Во время написания кода во время написания любого условия стоит задуматься, а что будет в противном случае? Может ничего, а может надо разбить сложное условие и отработать отдельные случаи если часть условия не выполняется. Просто сам факт рассмотрения возможных вариантов сразу повышает качество кода.

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

С корректными состояниями еще проще - система всегда должна быть в понятном состоянии. Хуже нет слуаев, когда данные есть в одном месте, но отсутствуют в другом, или статус разный, т.к. нет возможности понять, где правда. Любое место, где может произойти рассинхронизация, нужно изолировать и обложить мониторингом.

cat with many words

Про программирование, выпуск 5

Код

Код должен быть простым и понятным, как автомат Калашникова. Каждая новая абстракция добавляет сложность и делает код менее читаемым. Еще важно понимать инварианты - свойства, которые всегда должны выполняться для тех или иных сущностей в тех или иных условиях. Например, если есть сущность поставщик, то у него 100% есть телефон. Можно, конечно, в каждой функции проверять - вдруг нет? Но если есть возможность этот инвариант поддерживать без проверок, то код становится невероятно проще. Самое лучшее, если инварианты получается задавать средставми самого языка. Например, есть у вас поле в структуре и его нельзя задать как null. Готово, ну уровне языка у вас есть гарантия, что если код компилируется, то это поле есть, и в нем что-то есть. Конечно, конечно, там может быть мусор, но часто точек инициализации не так много (вы, конечно, контроллируете, как создаются ваши объекты, да?).

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

Обычно аргумент за подобные хешики - их легкость. Действительно, в языках типа Java, где есть конвенция - один тип = один файл, каждый новый тип - это действительно ненулевое усилие. Не успеешь оглянуться, как у тебя уже 100500 файлов, большая часть из которых не делает ничего. Если вгзлянуть на Go, то там этой конвенции нет, и определять типы настолько проще, что делаешь это, не задумываясь.

cat with many words

Про программирование, выпуск 4

Миграции

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

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

Статус

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

cat with many words

Про программирование, выпуск 3

CSS / Шаблонизаторы

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

Второй момент - чем менее локализованно работают те или иные технологии, тем сложнее с ними что-либо сделать. Клинический случай - это CSS.

Почему? Как известно, CSS - это язык декларативный. Файл стилей - это набор правил, каждое правило определяет элементы, к которым оно относится, с помощью селектора, некоторые правила наследуются некоторыми дочерними элементами. Все, ядерная смесь перед глазами. Самая популярная проблема с CSS - его очень сложно чистить или рефакторить, потому как в общем случае вообще невозможно понять, к каким элементам правило относится, и что случится, если правило удалить. Для ясности я тут не говорю о домашней страничке, а о большом сайте с кучей страниц и логики. Вы можете возразить, но тут я вам скажу div div span a, и каждый фронтенд разработчик сразу перенесется в то старое доброе время, когда из-за этого селектора переопределять стили для каждого элемента на страницу и, прости господи, рассыпать !important то тут то там, заражая кодовую базу еще больше.

Кроме этого каждый может вспомнить, как из-за какого-нибудь класса в одном из элементов вверху страницы (body или рядом) и опять таки россыпи общих селекторов, от него отталкивающихся, что-то рефакторить опять невозможно, а из-за стилей, определенных на нем, некоторую верстку просто не сделать. В мою бытность в букинге таким был #bodyconstraint, но до сих пор в разметке еще есть. Для него определена максимальная ширина, а также определен разный джаваскрипт, из-за которого тело страницы должно сидеть внутри тега. Как результат - любые дизайны, которые выходили за эту ширину, реализовывались огромной болью и загаживали код самыми разными хаками.

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

Прочитав это, сразу становится понятно, откуда растут ноги у техник типа BEM. Эти ребята уже наелись. Суть подхода - использовать только самые простые селекторы .class, которые будут применяться к минимально возможному количеству тегов. Грубо говоря, стили применяются только к элементам с классами, если класс больше нигде не встречается, стили можно спокойно грохать. Чтобы было проще, классы еще называли не .menu, а что-нибудь монструозное вроде .top-header-main-menu с целью снизить шанс того, что стили применятся где-то еще. Мало того, почти все хитрые css селекторы (nth-element или что там еще) совсем не нужны, достаточно классов в нужных местах раскидать.

Как видите, разница между двумя подходами в локализации изменений.

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

HTML

Сейчас время уже не то, и никто не стесняется из реакта получать бороду из div тегов с произвольными стилями, и это правильно. Все, что имеет значение - отзывчивость интерфейса для пользователя, ну еще SEO, на остальное можно положить. Лет десять назад было много разговоров про семантику, где header использовать, а где список, и много людей, включая меня, серьезно на это велось, даже в стандарт все эту дурь затащили. А эти чудные дискуссии - h4 или h5 поставить в этом маленьком блочке, чтобы структура документа сохранялась? Даже инструменты были, которые строили outline документа.

Как же я рад, что все это закончилось. По мне так в html должно быть не больше десятка тегов - html, body, head, meta, script, link, div, span, a, style, все остальное выбросить и забыть. Для пользователя нет никакой разницы, для программиста только меньше проблем.

cat with many words

Про программирование, выпуск 2

Граф зависимостей

Здесь все порой просто и очевидно, иногда менее заметно. Проще всего программировать, когда программа представляет собой дерево зависимостей: вверху главный модуль/main, который в свою очередь создает нужные объекты, которые зовут что-то еще уровнем еще ниже с минимальным количеством взаимосвязей между кодом на одном уровне и уж тем более без спорадических эвентов из любого места в программе, которые меняют логику где-то еще.

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

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

Именно из-за этого раньше в эпоху отсутствия модулей и засилия jquery было трудно делать сложные проекты. Грав зависимостей остуствовал, изоляции не было, все в одном index.js, и все, надежды нет. Только палочные наказания и расстрелы.

И именно поэтому redux нашел такое широкое применение. И я тут про подход, а не про свзку с реактом. Граф зависимостей выпрямился, и внезапно стало получаться просто рассуждать о вещах, о которых раньше даже думать вразумительно было невозможно.

Деплой

Тут все просто, он должен быть простым и быстрым. Есть прямая зависимость качества продукта и счатья программистов от скорости деплоя (и роллбека, конечно). Быстрый деплой означает, что программисты будут выкатывать код сто раз на дню безо всяких последствий. Тестировать будет легко и ловить баги будет легко, т.к. изменения минимальные.

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

Децентрализация

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

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

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

cat with many words

Про программирование, выпуск 1

Неохота писать абстрактное, поэтому решил написать о том, про что душа болит. Хочется описать то, что по моим наблюдениям почти наверняка работает одним способом (всегда плохо или всегда хорошо). Начнем с такого.

Один код для разных целей

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

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

Другой классический пример - одна константа на два случая. Определили вы, скажем, что ALPHA = 500, а потом эту константу используете как для количества товаров на странице, так и для количества товаров в имейл-рассылке. Все чудно и здорово во время разработки, но я прямо вижу, как к вам подходит пм и говорит, что 500 для рассылки много, дава 10, а у вас эта константа уже по всему коду распихана, и никто уже не вспомнит, что именно и для чего.

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

Самодокументируемый код

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

Например, мы футер будем добавлять только для бананов.

hasFooter := productKind == 'bananas'

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

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

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

Читаете вы код, а там вдруг без объявления войны:

bla.ToString()

Что это значит? В сообщении к коммиту об этом написано не будет. Вы же не помните уже наверняка, что когда-то дебажили библиотеку Х версии 1.2.3, и в ней есть внутренный кеш, который можно так заполнить. И как переменную не называй, ничего не поможет, только правильно составленный комментарий спасет. Причем не только в стиле // fill the cache for library x, а развернутый - dima: we're using library x to send emails. To make it faster we need to warm up library to generate all emails faster. Имя поможет тем, кто будет медитировать над этим кодом через 22 ребейза и три хард пуша.

cat with many words

Весь опенсорс в паре тредов.

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

Начав рыться, я быстро понял, что вообще говоря проблема не с моими наушниками конкретно, а с поддержкой нужных кодеков в pulseaudio. Еще круче, также требовались определенные изменения в ядре. И, на минутку, вопрос затрагивает bluetooth, один стандарт которого тянет на 1000 страниц, и он настолько кудрявый, что одного понимание его работы дорогого стоит.

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

Этот тредик отражает основные проблемы опен-сорса. Если нет корпорации, которая стояла бы за продуктом, то:

  • Разработчики будут работать над тем, что им нравится, а не то, что нужно пользователям
  • Пользователи по инерции будут думать, что им кто-то что-то должен
  • Изменения не будут мерджиться годами
  • У самого популярного проекта может быть близкое к нулю количество мейнтейнеров

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

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

Чтобы было понятно, что приведенный пример - не частность, упомяну еще парочку из тех, которые когда-то затрагивали меня. Ветераны помнят, что когда-то, в эпоху mp3 файлов в рунете, во многих из них названия треков записывались в кодировке windows-1251. В винде все отображалось прекрасно, под linux - бито. Почти ко всем клиентам появились патчи с исправлениями - хотя бы настройкой с выбором кодировки, но в большом количестве клиентов эти изменения не принимались, так как по стандарту в тегах должен быть unicode, и ничего больше. И все.

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

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

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

Стоит отметить, что есть еще и два разных мира открытого ПО с разной идеологией - веб ориентированное по и все, что связано с настольными системами. Об этом в другой раз.