Русский
Русский
English
Статистика
Реклама

Legacy

И снова о Legacy. Вечная боль техдира

27.07.2020 20:17:32 | Автор: admin

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


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


Техдир пришёл к ним, поздоровался и спросил: Ребята, скажите честно, какой аццкий зверь меня ждёт в этом проекте? Потому что стейкхолдеры рассказали только о единорогах с радужными хвостами и розовых пони? Legacy, да?


Legacy, ..., грустно ответили разработчики.


Сказка закончилась. Началась работа и непростые решения.



Cитуация. Первый извечный вопрос русской интеллигенции Кто виноват?


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


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


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


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


И погнали. Оно работает с помощью каких-то негров с опахалами, шамана, бивня мамонта, летающей китайской крысы и панголина.


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


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


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


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


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


Проблема. Второй извечный вопрос русской интеллигенции Что делать?


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



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


А бизнес вообще не знает, что проблема есть. Бизнес вообще не понимает: Ну как так, MVP же работает?. Работает. А почему новую фичу нельзя вот прям счаз воткнуть? И с чем сталкиваются многие технические управленцы, они не могут объяснить, в чем конкретно проблема и самое тяжелое они не могут показать в метрике, измеримой бизнесу, чтобы они понимали, что в текущем состоянии разработка фичи стоит 100 рублей, а в оптимизированном, например, 10 рублей.


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


Решение проблемы. Ломать нельзя рефакторить. Или уходя гасите всех


И мы переходим к решению проблемы. Существуют различные попытки решить проблему.


Решение номер раз. Помножить на ноль


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


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


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



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


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


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


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


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


Это один из таких способов, но он подразумевает, что какое-то время продукт не будет никак развиваться. У меня была реальная ситуация, когда ко мне пришёл за консультацией генеральный директор, у которого реально дергался глаз оказалось 14 месяцев назад команда сказала, что ей нужен рефакторинг, мол, иначе всё умрёт. И за эти 14 месяцев она ничего не сделала, точнее как, продукт не развивался а что происходило в рефакторинге никто не знает. Там ящик Шрёдингера и что там с кошкой, можно понять только по запаху.


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


Решение номер два. И давайте тут чуть-чуть починим


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


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


Что у нас получается? А у нас получается, что команда ввела так называемый налог на непонятно что, формально называется налог на исправление технического долга. Но как он там исправляется, если бизнес придет и спросит А что там и как? Что у вас? Бизнесу, конечно, объяснят, но он не поймет. В чем заключается технический долг с точки зрения технаря, понятно.


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


Во втором примере новой концепции нет и это реально проблема.


Решение номер три. Золотая середина. Микроверсия нового продукта


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


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


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


И теперь важная тема. В книге Фредерика Брукса приводится приводится пример того, как раньше строили храмы и там был пример храма Temple Expiatori de la Sagrada Famlia в Барселоне, строящегося на частные пожертвования начиная с 1882 года, знаменитый проект Антонио Гауди.



Суть в том, что Sagrada Famlia придумал Гауди и он выработал архитектуру, каким храм должен быть, но так как проект огромный, его строили много поколений и он еще недостроен, его достраивают еще.


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



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


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


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


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


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


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


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


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


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


О проблеме, когда сталкиваются технический директор и Legacy, рассказал CTO Дмитрий Симонов, основатель канала Техдирские заметки. Так как сам испытал и не раз эту извечную боль техдира.

Подробнее..

Перевод Положение дел у Windows сколько разношерстных уровней UI в Windows 10?

08.02.2021 14:10:06 | Автор: admin

Все мы слышали байку: если в Windows 10 копнуть достаточно глубоко, можно найти элементы, относящиеся еще ко временам Windows 3.x. Но так ли это на самом деле? В этой статье мы узнаем, сколько уровней пользовательского интерфейса присутствует в Windows и когда они были впервые представлены.

Для этого эксперимента я выбрал последнюю сборку Windows 10 Insider Build (по состоянию на 6 февраля 2021 г.), Windows 10 21301.

Итак, с места в карьер!

Уровень первый: Fluent Design.

Начнем мы с новейшего и прекрасного Fluent Design. Анонсированный в 2017 году и представленный с обновлением Windows 10 1803 Fluent Design представляет собой серьезную переработку Modern Design Language 2 (MDL2), направленную на привнесение таких элементов, как свет, глубина, движение, материальность и масштаб. Также появился эффект подсвечивания и акриловый полупрозрачный фон.

На данный момент большинство встроенных UWP-приложений были обновлены с использованием элементов Fluent такие, как элементы вроде меню "Пуск", "Центра уведомлений" и экрана входа в систему.

Хотя Fluent Design получил высокие оценки, большинство энтузиастов сочли этот шаг слишком незначительным и запоздалым, поскольку новый стиль используется лишь в небольшой части системы.

Уровень 2: Metro.

Если мы немного углубимся в ОС, то увидим элементы, которые не обновлялись со времен Windows 8/8.1.

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

Другими элементами Metro, хотя и не такими заметными, являются загрузочный экран (который скоро будет заменен на более новый) и WinRE.

Знаете ли вы, что впервые вращающиеся точки были представлены в Windows 8, билд 7989?

Так, ладно, перейдем к третьему уровню: к элементам Windows 8 Win32.

Как и Windows 10, Windows 8 также страдала от проблем с целостностью (лучше или хуже). Однако в Windows 8 были внесены существенные улучшения в основные пользовательские элементы такие, как проводник Windows и диспетчер задач. Хотя в последующих обновлениях Windows 10 они получат некоторые качественные улучшения, изменения будут минимальными.

Кроме того, важным изменением с выходом Windows 8 стала переработка диалоговых окон передачи файлов.

Некоторые из этих изменений начались в Windows 7, что подводит нас к четвертому уровню: элементам пользовательского интерфейса Windows 7

Windows 7, без сомнения, одна из самых любимых версий Windows всех времен, которую хвалят за большие улучшения по сравнению с Windows Vista. Она принесла много новых функций, которые, хотя и не были столь значительными как те, что предлагает Vista, сделали Windows 7 очень надежной ОС настоящим преемником Windows XP. Однако, одним из самых печально известных изменений, привнесенных Windows 7, является ленточный интерфейс, пришедшим из Office 2007. Paint и Wordpad были первыми приложениями, которые его получили.

Хотя в какой-то момент Microsoft решила отказаться от классического Paint в пользу нового Paint 3D (представленного в Windows 10 Creators Update), после негативной реакции они отменили свое решение.

Другие функции, которые были обновлены в Windows 7 и с тех пор остались прежними: Windows Media Player 12, подключение к удаленному рабочему столу и некоторые диалоговые окна с файлами.

Теперь перейдем к 5-му уровню пользовательского интерфейса: Windows Vista.

Релиз Windows Vista имел огромную важность, принесшим столь необходимую модернизацию платформы. Почти все основы ОС были так или иначе улучшены, от загрузчика до модели драйвера. Однако, как мы все уже знаем, Windows Vista станет одним из худших выпусков Windows за всю историю, с самого начала страдающего от проблем. Однако одной из немногих расхваленных функций был пользовательский интерфейс. В нем были переработаны некоторые основы, которые не обновлялись со времен Windows 95. Одним из главных способствующих факторов этого изменения было введение так называемых мастеров "Aero Wizards", пришедших на смену предыдущему стандарту мастеров, Wizard97.

Другие функции, которые были переработаны в Windows Vista, стали в основном все те же, что и в Windows 10: панель управления, программа поиска, факсы и сканирование Windows.

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

Теперь перейдем к 6-му уровню: Windows XP.

Вы не поверите, но в Windows 10 встроено не так много элементов XP. Вероятно, это связано с тем, что большинство основ уже обновлены к Windows 2000. Однако Windows 10 содержит некоторые диалоговые окна файлов из XP, которые видны при установке драйвера.

Уровень 7: Windows 2000.

Windows 2000 стала важной вехой в линейке операционных систем Microsoft NT. Это также была ступенька, которая ознаменовала начало перехода к новому унифицированному видению Windows. Однако Windows 2000 по-прежнему оставалась ОС, ориентированной на корпоративный сектор, а это значит, что она принесла много новых функций, разработанных для специалистов.

Консоль MMC стала одной из наиболее значительных дополнений, элементы которого с тех пор практически не изменились.

Еще одна функция, представленная по умолчанию в Windows 2000, установщик Windows, который по-прежнему имеет все тот же значок, когда впервые был представлен!

Еще один элемент пользовательского интерфейса, который не изменился (кроме фирменного стиля, конечно), это winver, дизайн которого был представлен в Windows 2000, билд 1946.

В то время, как Windows 2000 представила множество функций, предназначенных для опытных пользователей, Windows 95, вероятно, является самым знаковым релизом Windows на сегодняшний день. Он установил фундаментальные парадигмы, которые действуют и по сей день: меню "Пуск", контекстные меню, панель задач и корзину. Хотя эти функции, конечно, обновлялись в течение многих лет, некоторые из них остались почти такими же.

Теперь о восьмом уровне: элементы Windows 95/NT 4.0

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

Еще один поразительно похожий элемент это поле "Выполнить".

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

А есть и множество других элементов пользовательского интерфейса, которые не менялись со времен Windows 95. Это ли не пример дизайна, над которым время не властно? Судите сами.

Уровень 9: Windows 3.1 и DOS. В общем-то

Что ж, на самом деле это не "уровень пользовательского интерфейса", так как я не смог найти никаких элементов интерфейса, предшествующих Windows 95 (хотя у меня есть ощущение, что они, безусловно, есть). Однако в Windows 10 есть специфический файл moricons.dll, который содержит множество старых значков времен DOS. Сами поглядите:

Ну вот и все. Как вы, возможно, уже знаете, с выходом "Sun Valley" Microsoft планирует модернизировать пользовательский интерфейс Windows, целью которого является унификация дизайна ОС. Однако, как мы видим, Windows это гигантская операционная система. Увенчаются ли успехом их усилия по созданию единого пользовательского интерфейса? Время покажет.

Подробнее..

Статический анализ baseline файлы vs diff

25.06.2020 12:16:27 | Автор: admin

В статических анализаторах рано или поздно приходится решать задачу упрощения интеграции в существующие проекты, где поправить все предупреждения на legacy коде невозможно.


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



baseline или так называемый suppress profile


Этот метод имеет несколько названий: baseline файл в Psalm и Android Lint, suppress база (или профиль) в PVS-Studio, code smell baseline в detekt.


Данный файл генерируется линтером при запуске на проекте:


superlinter --create-baseline baseline.xml ./project

Внутри себя он содержит все предупреждения, которые были выданы на этапе создания.


При запуске статического анализатора с baseline.xml, все предупреждения, которые содержатся в этом файле, будут проигнорированы:


superlinter --baseline baseline.xml ./project

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


Обычно, мы хотим достичь следующего:


  • На новый код выдаются все предупреждения
  • На старый код предупреждения выдаются только если его редактировали
  • (опционально) Переносы файлы не должны выдавать предупреждения на весь файл

То, что мы можем конфигурировать в этом подходе это какие поля предупреждения формируют хеш (или "сигнатуру") срабатывания. Чтобы уйти от проблем смещения строк кода, лучше не добавлять номер строки в эти поля.


Вот примерный список того, что вообще может являться полем сигнатуры:


  • Название или код диагностики
  • Текст предупреждения
  • Название файла
  • Строка исходного кода, на которую сработало предупреждение

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


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


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


Эмпирически проверено, что с этим признаком можно ослабить поле имени файла и хранить только базовое имя вместо полного пути. Это позволяет перемещать файлы между директориями без инвалидации сигнатуры. В языках, типа C#, PHP или Java, где название файла чаще всего отражает название класса, такие переносы имеют смысл.


Хорошо подобранный набор признаков увеличивает эффективность baseline подхода.


Коллизии в методе baseline


Допустим, диагностика W104 находит вызовы die в коде.


В проверяемом проекте есть файл foo.php:


function legacy() {  die('test');}

Предположим, используются признаки {имя файла, код диагностики, строка исходного кода}.


Наш анализатор при создании baseline добавляет вызов die('test') в свою базу исключений:


{  "filename": "foo.php",  "diag": "W104",  "line": "die('test');"}

Теперь добавим немного нового кода:


+ function newfunc() {+   die('test');+ }  function legacy() {    die('test');  }

По всем используемым признакам новый вызов die('test') будет распознаваться как игнорируемый код. Совпадение сигнатур для потенциально разных кусков кода мы и называем коллизией.


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


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


Здесь нам на помощь приходит счётчик сигнатур с коллизиями. Таким образом мы можем определить, что внутри функции ожидалось одно срабатывание, а получили два или более все, кроме первого, нужно сообщать.


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


Метод, основанный на diff возможностях VCS


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


Утилита revgrep принимает на stdin поток предупреждений, анализирует git diff и выдаёт на выход только те предупреждения, которые исходят от новых строк.


golangci-lint использует форк revgrep как библиотеку, так что в основе его вычисления diff'а лежат те же алгоритмы.

Если выбран этот путь, придётся искать ответ на следующие вопросы:


  • Как выбрать окно коммитов для вычисления diff?
  • Как будем обрабатывать коммиты, пришедшие из основной ветки (merge/rebase)?

Вдобавок нужно понимать, что иногда мы всё же хотим выдавать предупреждения, выходящие за рамки diff. Пример: вы удалили класс директора по мемам, MemeDirector. Если этот класс упоминался в каких-либо doc-комментариях, желательно, чтобы линтер сообщил об этом.


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


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


diff режим в NoVerify


NoVerify имеет два режима работы: diff и full diff.


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


Full diff запускает анализатор дважды: один раз на старом коде, затем на новом коде, а потом фильтрует результаты. Это можно сравнить с генерацией baseline файла на лету с помощью того, что мы можем получить предыдущую версию кода через git. Ожидаемо, этот режим увеличивает время выполнения почти вдвое.


Изначальная схема работы предполагалась такая: на pre-push хуках запускается более быстрый анализ, в режиме обычного diff'а, чтобы люди получали обратную связь как можно быстрее. На CI агентах полный diff. В результате время от времени люди спрашивают, почему на агентах проблемы были найдены, а локально всё чисто. Удобнее иметь одинаковые процессы проверки, чтобы при прохождении pre-push хука была гарантия прохождения на CI фазы линтера.


full diff за один проход


Мы можем делать приближенный к full diff аналог, который не требует двойного анализа кода.


Допустим, в diff попала такая строка:


- class Foo {

Если мы попробуем классифицировать эту строку, то определим её как "Foo class deletion".


Каждая диагностика, которая может как-то зависеть от наличия класса, должна выдавать предупреждение, если имеется факт удаления этого класса.


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


Переименования не требуют дополнительной обработки. Мы считаем, что символ со старым именем был удалён, а с новым добавлен:


- class MemeManager {+ class SeniorMemeManager {

Основной сложностью будет правильно классифицировать строки изменений и выявить все их зависимости, не замедлив алгоритм до уровня full diff с двойным обходом кодовой базы.


Выводы


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


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


baseline diff
+ легко сделать эффективным + не требует хранить файлов
+ простота реализации и конфигурации + проще отличать новый код от старого
- нужно решать коллизии - сложно правильно приготовить

Могут существовать гибридные подходы: сначала берёшь baseline файл, а потом разрешаешь коллизии и вычисляешь смещения строк кода через git.


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

Подробнее..

Мёртвый код найти и обезвредить

19.08.2020 14:16:03 | Автор: admin


Меня зовут Данил Мухаметзянов, я работаю бэкенд-разработчиком в Badoo уже семь лет. За это время я успел создать и изменить большое количество кода. Настолько большое, что в один прекрасный день ко мне подошёл руководитель и сказал: Квота закончилась. Чтобы что-то добавить, нужно что-то удалить.

Ладно, это всего лишь шутка он такого не говорил. А жаль! В Badoo за всё время существования компании накопилось больше 5,5 млн строк логического бизнес-кода без учёта пустых строк и закрывающих скобок.

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

Эту тенденцию заметил не только я. В Badoo поняли: наши высокооплачиваемые инженеры постоянно тратят время на мёртвый код.



С этим докладом я выступал на Badoo PHP Meetup #4

Откуда берётся мёртвый код


Мы начали искать причины проблем. Разделили их на две категории:

  • процессные те, что возникают в результате разработки;
  • исторические легаси-код.

В первую очередь решили разобрать процессные источники, чтобы предотвратить возникновение новых проблем.

A/B-тестирование


Активно использовать A/B-тестирование в Badoo начали четыре года назад. Сейчас у нас постоянно крутится около 200 тестов, и все продуктовые фичи обязательно проходят эту процедуру.

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

Решение проблемы пришло быстро: мы начали автоматически создавать тикет на выпиливание кода по завершении А/В-теста.


Пример тикета

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

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

С помощью такого нехитрого механизма мы избавились от большого пласта работы.

Многообразие клиентов


В нашей компании поддерживаются несколько брендов, но сервер один. Каждый бренд представлен на трёх платформах: веб, iOS и Android. На iOS и Android у нас недельный цикл разработки: раз в неделю вместе с обновлением мы получаем новую версию приложения на каждой платформе.

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

При достижении софт-лимита (когда вышло уже три-четыре новые версии, а приложение всё ещё не обновлено), пользователь видит скрин с предупреждением о том, что его версия устарела. При достижении хард-лимита (это порядка 10-20 пропущенных версий в зависимости от приложения и бренда) мы просто убираем возможность пропустить этот скрин. Он становится блокирующим: пользоваться приложением с ним нельзя.


Скрин для хард-лимита

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

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

Отдельное решение мы придумали для случая, когда прекратилась поддержка Windows Phone. Мы подготовили скрин, который сообщал пользователю: Мы тебя очень любим! Ты очень классный! Но давай ты начнёшь пользоваться другой платформой? Тебе станут доступны новые крутые функции, а здесь мы уже ничего сделать не можем. Как правило, в качестве альтернативной платформы мы предлагаем веб-платформу, которая всегда доступна.

С помощью такого простого механизма мы ограничили количество версий клиентов, которое поддерживает сервер: приблизительно 100 разных версий от всех брендов, от всех платформ.

Фиче-флаги


Однако, отключив поддержку старых платформ, мы не до конца понимали, можно ли полностью выпиливать код, который они использовали. Или платформы, которые остались для старых версий ОС, продолжают пользоваться той же функциональностью?

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

У нас было два типа фиче-флагов. Расскажу о них на примерах.

Минорные фичи


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

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

Аппликейшен-фичи


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

Такие фичи мы назвали аппликейшен-фичами. Они более тяжёлые, поэтому их у нас меньше, но всё равно достаточно: больше 300.

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

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


Скрин дашборда

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

Автоматизировать процесс не так удобно, но, в принципе, и не нужно достаточно просто ставить задачу и периодически смотреть на дашборд. В первой же итерации нам удалось выпилить 200 с лишним флагов. Это почти четверть флагов, которые мы использовали!

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

Что делать с легаси-кодом


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

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

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

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

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

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

Собираем список методов


Впрочем, собрать полный список методов получилось достаточно быстро. Мы просто взяли парсер Никиты Попова, скормили ему наш репозиторий и получили всё, что имеем в коде.

Остался вопрос: как собрать то, что исполняется на продакшене? Нас интересует именно продакшен, потому что тесты могут покрывать и то, что нам совсем не нужно. Недолго думая, мы взяли XHProf. Он уже исполнялся на продакшене для части запросов, и потому у нас были семплы профилей, которые хранятся в базах данных. Было достаточно просто зайти в эти базы, спарсить сгенерированные снепшоты и получить список файлов.

Недостатки XHProf


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

И тут мы убедились, что XHProf для нас неудобен.

  • Он требует изменения PHP-кода. Нужно вставить код старта трейсинга, закончить трейсинг, получить собранные данные, записать их в файл. Всё-таки это профайлер, а у нас продакшен, то есть запросов много, нужно думать и о семплировании. В нашем случае это усугубилось большим количеством кластеров с разными entry points.
  • Дублирование данных. У нас работала оптимизация для файлов. Вместо того чтобы получать список методов на каждый реквест, мы просто опрашивали OPCache. Реквестов много: если использовать XHProf, то нужно на каждый реквест записать некое количество данных и используемые методы. Но большая часть методов вызывается из раза в раз, потому что это core-методы или использование стандартного фреймворка.
  • Человеческий фактор. У нас произошла одна интересная ситуация. Мы запустили XHProf на кластере обработки очередей. Запустили в облегчённом режиме (через опции XHProf): выключили сбор метрик потребления CPU, памяти, потому что они были бесполезны и только нагружали сервер. По сути, это был эксперимент, который мы не анонсировали до получения результатов. Но в какой-то момент мейнтейнер XHProf aggregator (наш внутренний компонент на базе XHProf с официальным названием Live Profiler, который мы выложили в open-source) это заметил, подумал, что это баг, и включил все обратно. Включил, проанализировал и сообщил: Ребята, кажется, у нас проблемы, потому что потребление CPU выросло на этом кластере, так как мы включили профилирование для большого числа запросов, о чём Live Profiler не знал. Мы, конечно, быстро заметили это и всё пофиксили.
  • Сложность изменения XHProf. Данных собиралось много, поэтому нам хотелось автоматизировать их доставку и хранение. У нас уже был процесс доставки логов для ошибок и статистики. Мы решили использовать ту же самую схему вместо того, чтобы плодить новые. Но она требовала изменения формата данных: например, специфичной обработки переводов строк (стоит отметить, как правильно заметил youROCK, этого не требует lsd, но так было удобнее для поддержки единой обертки над ним). Патчить XHProf это не то, что нам хотелось делать, потому что это достаточно большой профайлер (вдруг что-нибудь сломаем ненароком?).

Была и ещё одна идея исключить определённые неймспейсы, например неймспейсы вендоров из композера, исполняющиеся на продакшене, потому что они бесполезны: мы не будем рефакторить вендорские пакеты и выпиливать из них лишний код.

Требования к решению


Мы ещё раз собрались и посмотрели, какие решения существуют. И сформулировали итоговый список требований.

Первое: минимальные накладные расходы. Для нас планкой был XHProf: не больше, чем требует он.

Второе: мы не хотели изменять PHP-код.

Третье: мы хотели, чтобы решение работало везде и в FPM, и в CLI.

Четвёртое: мы хотели обработать форки. Они активно используются в CLI, на облачных серверах. Делать специфическую логику для них внутри PHP не хотелось.

Пятое: семплирование из коробки. По факту это вытекает из требования не изменять PHP-код. Ниже я расскажу, почему нам было необходимо семплирование.

Шестое и последнее: возможность форсировать из кода. Мы любим, когда всё работает автоматически, но иногда удобнее вручную запустить, подебажить, посмотреть. Нам нужна была возможность включать и выключать все прямо из кода, а не по рандомному решению более общего механизма модуля PHP, задающего вероятность включения через настройки.

Принцип работы funcmap


В результате у нас родилось решение, которое мы назвали funcmap.

По сути funcmap это PHP extension. Если говорить в терминах PHP, то это PHP-модуль. Чтобы понять, как он работает, давайте посмотрим, как работает PHP-процесс и PHP-модуль.

Итак, у вас запускается некий процесс. PHP даёт возможность при построении модуля подписываться на хуки. Запускается процесс, запускается хук GINIT (Global Init), где вы можете инициализировать глобальные параметры. Потом инициализируется модуль. Там могут создаваться и выделяться в память константы, но только под конкретный модуль, а не под реквест, иначе вы выстрелите себе в ногу.

Затем приходит пользовательский реквест, вызывается хук RINIT (Request Init). При завершении реквеста происходит его шатдаун, и уже в самом конце шатдаун модуля: MSHUTDOWN и GSHUTDOWN. Всё логично.

Если мы говорим об FPM, то каждый пользовательский реквест приходит в уже существующий воркер. По сути, RINIT и RSHUTDOWN просто работают по кругу, пока FPM не решит, что воркер своё отжил, пора его пристрелить и создать новый. Если мы говорим о CLI, то это просто линейный процесс. Всё будет вызвано один раз.


Принцип работы funcmap

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

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

Дальше мы инициализируем таймер. О нём я расскажу ниже, пока просто запомните, что он есть, важен и нужен.

Второй хук MSHUTDOWN. Хочу заметить, что именно MSHUTDOWN, а не RSHUTDOWN. Мы не хотели отрабатывать что-то на каждый реквест нас интересовал именно весь воркер. На MSHUTDOWN мы берём нашу хеш-таблицу, пробегаемся по ней и пишем файл (что может быть надёжнее, удобнее и универсальнее старого доброго файла?).

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

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

Конфигурация


Как это конфигурировать, не изменяя PHP-код? Настройки очень простые:

  • enabled: включён он или нет.
  • Файл, в который мы пишем. Здесь есть плейсхолдер pid для исключения race condition при одновременной записи в один файл разными PHP-процессами.
  • Вероятностная основа: наш probability-флаг. Если вы выставляете 0, значит, никакой запрос записан не будет; если 100 значит, все запросы будут логироваться и попадать в статистику.
  • flush_interval. Это периодичность, с которой мы сбрасываем все данные в файл. Мы хотим, чтобы сбор данных исполнялся в CLI, но там есть скрипты, которые могут выполняться достаточно долго, съедая память, если вы используете большое количество функционала.

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

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

Накладные расходы


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

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

Мы включили наше расширение последовательно на 25%, 50% и 100% и увидели вот такую картину:



Пунктир это количество реквестов, которое мы ожидаем. Основная линия количество реквестов, которое приходит. Мы увидели деградацию ориентировочно в 6%, 12% и 23%: данный сервер начал обрабатывать практически на четверть меньше приходящих реквестов.

Этот график в первую очередь доказывает, что нам важно семплирование: мы не можем тратить 20% ресурсов сервера на сбор статистики.

Ложный результат


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

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

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

Но всё равно оставались методы, которые вызываются редко и про которые было неясно, нужны они или не нужны. Мы добавили хелпер, который помогает определить факт использования таких методов: если семплирование уже показало, что метод вызывается редко, то можно включить обработку на 100% и не думать о том, что происходит. Любое исполнение этого метода будет залогировано. Вы будете об этом знать.

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

Мы создали интерфейс, в котором видно, какие методы используются (они на белом фоне), а какие потенциально не используются (они на красном фоне). Здесь можно и промаркировать нужные методы.

Скрин интерфейса


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

Мы сделали плагин для PhpStorm, который загружает всю базу неиспользуемых методов и отображает, используется данный метод или нет. Более того, в интерфейсе можно пометить метод как используемый. Это всё отправится на сервер и станет доступно остальным контрибьюторам кодовой базы.

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

Расширение funcmap выложено на GitHub. Будем рады, если оно кому-то пригодится.

Альтернативы


Со стороны может показаться, что мы в Badoo не знаем, чем себя занять. Почему бы не посмотреть, что есть на рынке?

Это справедливый вопрос. Мы смотрели и на рынке в тот момент ничего не было. Только когда мы начали активно внедрять своё решение, мы обнаружили, что в то же самое время человек по имени Joe Watkins, живущий в туманной Великобритании, реализовал аналогичную идею и создал расширение Tombs.

Мы не очень внимательно его изучили, потому что у нас уже было своё решение, но тем не менее обнаружили несколько проблем:

  • Отсутствие семплирования. Выше я объяснял, почему оно нам необходимо.
  • Использование разделяемой памяти. В своё время мы столкнулись с тем, что воркеры начинали упираться в запись конкретного ключа при использовании APCu (модуль кеширования), поэтому в своём решении мы не используем разделяемую память.
  • Проблемная работа в CLI. Всё работает, но, если вы одновременно запустите два CLI-процесса, они начнут конфликтовать и публиковать ненужные ворнинги.
  • Сложность постобработки. Расширение Tombs, в отличие от нашего, само понимает, что было загружено, что было исполнено, и в конце концов выдаёт то, что инвертировано. Мы же в funcmap делаем инверсию уже после (вычитаем из всего кода тот, который использовался): у нас тысячи серверов, и эти множества нужно правильно пересечь. Tombs отлично сработает, если у вас небольшое количество серверов, вы используете FPM и не используете CLI. Но если вы используете что-то сложнее, попробуйте оба решения и выберите более подходящее.

Выводы


Первое: заранее думайте о том, как вы будете удалять функциональность, которая имплементируется на короткий промежуток времени, особенно если разработка идёт очень активно. В нашем случае это были A/B-тесты. Если вы не подумаете об этом заранее, то потом придётся разгребать завалы.

Второе: знайте своих клиентов в лицо. Неважно, внутренние они или внешние вы должны их знать. В какой-то момент надо сказать им: Родной, стоп! Нет.

Третье: чистите свой API. Это ведёт к упрощению всей системы.

И четвёртое: автоматизировать можно всё, даже поиск мёртвого кода. Что мы и сделали.
Подробнее..

Войны лоббистов и развитие BIM.Часть 5 BlackRock хозяин всех технологий. Как корпорации контролируют Open source

11.04.2021 10:22:11 | Автор: admin

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

Сегодняшние лидеры САПР-индустрии: Autodesk, Hexagon, Nemetschek, Bentley, Trimble - хорошо готовятся к будущим угрозам: стандартной тактикой больших корпораций стал агрессивный захват новых рынков и поглощение возможных конкурентов на ранних стадиях развития.

В результате вся САПР-индустрия стала похожа на олигополию, в которой доминирует группа из нескольких компаний. И их положение на вершине становится всё более непоколебимым.

Содержание:

  1. BlackRock - хозяин всех технологий

  2. Олигополия на рынке САПР

  3. Autodesk идёт по стопам Oracle

  4. Почему программы не развиваются

  5. Борьба корпораций с open source

  6. Autodesk и формат данных IFC

  7. Проблема Autodesk - организация открытых стандартов - ODA

  8. В заключение

Олигополия в САПРОлигополия в САПР

В этой статье мы рассмотрим:

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

  • как происходит синхронизация политики между САПР-вендорами

  • почему компании не развивают программы, написанные в 90-е

  • как большие корпорации контролируют open source разработчиков

  • почему IFC и Dynamo - это непрозрачный open source

  • как благодаря Autodesk появился альянс ODA

  • как велась борьба за формат DWG между ODA и Autodesk

  • как сегодня развивается борьба за открытость форматов RVT и RFA

  • как BlackRock и Vangaurd создали плановую экономику на мировом уровне

BlackRock - хозяин всех технологий

Основа олигополистической структуры в строительном проектировании - это большая пятёрка САПР-вендоров: Autodesk, Hexagon, Trimble, Bentley, Nemetschek.

Эти компании выходили с середины 90-х на IPO (initial public offering), распродав большую часть своих акций среди крупнейших инвестиционных фондов Соединённых Штатов и распределив тем самым ответственность за будущее компаний среди держателей акций.

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

Главными бенефициарами (и держателями акций) от выхода САПР-компаний на биржу стали три американских инвестиционных фонда: The Capital Group, Vanguard и BlackRock, которые на протяжении последних 30 лет скупали акции технологических компаний напрямую или через свои банковские филиалы.

Акционеры крупнейших CAD-компанийАкционеры крупнейших CAD-компаний

Мало кто слышал о BlackRock, но эта фирма является крупнейшей инвестиционной компанией, под управлением которой находятся активы стоимостью в $8,7 трлн в 2021 году (в 2015 году - $4,6 трлн). На 2021 год BlackRock, штаб-квартира которой расположена на Манхэттене, имеет отделения в 100 странах, и она тесно связана с крупнейшими финансовыми регуляторами, такими как министерство финансов США, Федеральная резервная система (ФРС) США и Европейский центральный банк (ЕЦБ).

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

Например, только в Германии в 2014 году BlackRock принадлежало 4% акций BMW, 5,2% акций Adidas,7% акций Siemens, 6% акций Daimler. В целом BlackRock является акционером (почти всегда самым крупным) всех предприятий, входящих в индекс DAX (важнейший фондовый индекс Германии).Гигантская платформа Aladdin, созданная BlackRock для управления активами, ежесекундно отслеживает стоимость акций, облигаций и других активов, находящихся под управлением компании, а также рассчитывает, как влияют на их котировки различные события, такие как рост цен на нефть или алюминий.

BlackRock является мажоритарным акционером почти во всех технологических компаниях мира. Какое отношение к строительству и проектированию имеют инвестиционные корпорации BlackRock и Vanguard (Vanguard/Windsor)?

BlackRock и Vanguard принадлежат почти все САПР-компании и технологии в мире строительного проектирования и BIM решений.

Доля владения акциями BlackRock и Vanguard в компаниях САПРДоля владения акциями BlackRock и Vanguard в компаниях САПР

На графике владения акциями заметно, что особым смыслом здесь обладает цифры - 7-10%. До таких цифр инвестфонды доводят долю владения любой компанией, чего хватает, чтобы полностью контролировать целые корпорации.

На следующем графике видно похожее распределение владения акциями крупнейших компаний мира - Big 5.

Доля владения акциями BlackRock и Vanguard в компаниях Big 5Доля владения акциями BlackRock и Vanguard в компаниях Big 5

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

Степень контроля (X - сила голоса) в компании в зависимости от вечеличины пакета акций (Y - процент капитала)Степень контроля (X - сила голоса) в компании в зависимости от вечеличины пакета акций (Y - процент капитала)

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

При таком многократном перекрестном владении и при наличии долей практически во всех крупных корпорациях - как этим инвестиционным фондам удаётся следить за темой BIM или, например, развитием AR в строительстве, да и вообще за всеми технологиями мира одновременно?

Олигополия на рынке САПР

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

Доля доли BlackRock в компаниях САПРДоля доли BlackRock в компаниях САПР

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

Политолог Jan Fichtner из Амстердамского университета, исследуя этих основных финансовых игроков, утверждает: Влияние в основном осуществляется через фоновые дискуссии. Вы ведете себя на поводу у BlackRock и Vanguard, потому что знаете, что однажды вам может понадобиться их благосклонность. Для руководства компаний и корпораций рационально действовать в интересах основных держателей акций.

"Там, где есть договор, есть перочинный нож."

Шарль-Морис де Талейран-Перигор

Все, кто работает в развитии технологий строительной отрасли, постепенно попадают в жернова этой плановой экономики, созданной акулами капитализма при поддержке богатых династий запада, пенсионных фондов и печатного станка ФРС.

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

В итоге сегодня все мировые САПР (и вообще все технологические) компании принадлежат инвестиционным фондам, которые на бумаге занимаются управлением стратегией компании, а де-факто - только соблюдением формальных предписаний для отчётов, которые позже попадают в красивый PDF документ для ежегодного собрания совета директоров.

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

Бегство от свободы, Эрих Фромм

Как сегодня Trimble будет соперничать с Autodesk или Hexagon на одном рынке, если CEO этих компаний отчитываются ежеквартально перед одними и теми же инвестиционными фондами с WallStreet, которые, в свою очередь, не заинтересованы в резких изменениях на тех рынках, от которых зависят их годовые отчёты и, как следствие, их личные бонусы.

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

Если ещё десять лет назад такие крупные компании, как Autodesk, Nemetschek, Trimble имели репутацию уже не новаторов, а скорее имитаторов, когда было достаточно просто скопировать новый популярный продукт и выпустить свой клон, то сегодня необходимость в клонировании продуктов отпала. Сегодня стартапы и целые компании скупаются за любые деньги, которые предоставляют своим подопечным BlackRock и Vanguard.

Чтобы не конкурировать друг с другом на одном рынке, каждая компания из big5 САПР выбирает для себя отдельные технологические ниши и скупает постепенно программы и любые технологии в этом направлении.

Основные стартапы, приобретенные за последние 20 летОсновные стартапы, приобретенные за последние 20 лет

Для примера John Walker (будущий CEO Autodesk) предлагал Mike Riddle купить Autocad в 1982 году всего за $15 тыс. (изначально за $8 тыс.), но Mike настоял на условиях продажи Autocad за 1$ и 10% c продаж продукта. В 2020 году Revit стал самым продаваемым продуктом Автодеск, который она купила в 2002 году за 133 млн долларов. А уже в 2018 году Autodesk заплатил за Plangrid (стартап-приложение для планшета) почти миллиард долларов ($875 млн), где одним членом из совета директоров, за несколько лет до покупки, стала бывшая CEO Autodesk - Carol Ann Bartz.

Таким образом, на данный момент весь мир проектирования и вообще все технологии мира разделились на тех, кто принадлежит Blackrock и Vanguard, и тех, кого эти фонды через свои САПР-филиалы ещё купить не успели. Ни одна организация с высокими денежными показателями не имеет возможности избежать встречи с такими финансовыми гигантами, в какой бы стране она ни находилась.

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

Мы убрали с рынка всех конкурентов, но почему мы не движемся вперед?Мы убрали с рынка всех конкурентов, но почему мы не движемся вперед?

!Нельзя ни в коем случае демонизировать структуры, которые были построены BlackRock и Vanguard: любая организация и скорее всего каждый человек на земле, имея такие бесплатные ресурсы и доступ к печатному станку, воспользовались бы этим и поступили бы на месте Blackrock точно так же, скупая всё на своём пути.

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

Для чего мировым вендорам САПР нужны тысячи специалистов по базам данных, oб open source решениях, а также о решениях, над которыми работают основные вендоры САПР, поговорим в седьмой части.

Чтобы к седьмой части немного лучше понимать нового игрока на рынке САПР - Oracle, базы данных и open source, а также из-за схожести поведения двух компаний - сравним историю Oracle с историей развития Autodesk и посмотрим на то, как эти две корпорации боролись с open source движениями на своём рынке.

Autodesk идёт по стопам Oracle

История Autodesk, одного из лидеров САПР-мира, начинает всё больше походить на историю такого лидера своего времени, как Oracle. Так же, как Autodesk с Autocad была последние 30 лет мировым лидером 2D-проектирования, Oracle, в это же время, была мировым лидером баз данных - DBMS систем (database management system).

Прибыль Oracle от бизнеса, построенного на хранении данных, примерно в 10 раз больше, чем продажи лидеров САПР-отрасли: годовой оборот Oracle сегодня - $20 mlrd., а у Autodesk - всего $1,7 mlrd.. Как и во всех технологических компаниях мира, ведущими акционерами Oracle (как и Autodesk, Trimble, Apple, Microsoft и почти всех компаний на земле) являются две крупнейшие в мире инвестиционные компании - Vanguard и BlackRock.

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

Как многие основные компании, выросшие после холодной войны, обязаны своим развитием федеральным и оборонным контрактам, так и Oracle на самом деле берет свое название от кодового названия проекта ЦРУ 1977 года. И именно ЦРУ было первым заказчиком Oracle.

C середины 2000-х Oracle начинает активно интересоваться строительной отраслью. Примечательно, что Oracle стал стратегическим партнёром buildingSMART в 2019 году, за один год до того, как главный САПР-производитель Autodesk присоединился к buildingSMART в 2020 году.У Oracle есть все шансы, чтобы стать лидером BIM-технологий. Об этом и почему BIM - это базы данных, поговорим подробнее в седьмой части.

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

Как в открытых письмах лучших архитекторов мира, адресованных Autodesk, (подробнее об этом в Часть 4: Борьба CAD и BIM. Монополии и лоббисты в строительной отрасли), так и в подкасте с Еленой Слеповой - мы все отмечаем, что Autodesk почти не развивает основной продукт Revit, а занимается только дизайном и украшательством интерфейса, попутно покупая новые стартапы (Navisworks, Assemble, Vault, Civil 3D) и технологии.

Открытое письмо архитектурных бюро мира Autodesk о том что продукт Revit не развиваетсяОткрытое письмо архитектурных бюро мира Autodesk о том что продукт Revit не развивается

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

Почему программы не развиваются

Любой большой программный продукт, разрабатываемый больше пяти лет, напоминает длинный "спагетти-код". При этом только несколько главных разработчиков в компании знают, как работает (максимум) 70% кода в такой программе, как Oracle Database, Autocad, Revit или Archicad.Новые инструменты от Autodesk, Nemetschek или Oracle сегодня являются лишь попыткой скрыть накопленные проблемы от разработчиков, потому что справиться с ними стало невозможно.

Затухание активного роста в техническом плане начинается с ухода разработчиков на более высокие должности или, что происходит чаще, с Exit основных разработчиков, которые забирают деньги (после продажи стартапа или выхода компании на IPO) и сами становятся венчурными инвесторами.

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

Legacy code (от Legacy (англ.) наследство) устойчивое выражение, обозначающее старый код без каких-либо пояснений; главным его признаком является отсутствие возможности в нём разобраться.

Legacy code не проблема - если тебе не нужно поменять егоLegacy code не проблема - если тебе не нужно поменять его

На примере Oracle можно представить, в чём же состоит сложность Legacy кода и почему программы из 90-х почти не развиваются в последнее время.

Объем кодовой базы Oracle Database в период разработки версии 12.2 в 2017 году составлял 25 миллионов строк на языке C и стоит вам изменить лишь одну из этих строк, как ломаются тысячи написанных ранее тестов. За прошедшие годы над кодом Oracle Database успело потрудиться несколько поколений программистов, которых регулярно преследуют жесткие дедлайны, благодаря чему код превратился в настоящий кошмар.

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

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

Возникает вопрос: каким же образом при всем этом Oracle Database (или Revit, Archicad) до сих пор удается держаться на ногах? Секрет в миллионах тестов. Их полное выполнение может занимать от 20 до 30 часов (при этом выполняются они распределенно на тестовом кластере из 100-200 серверов), поэтому сегодня процесс исправления одного единственного бага в Oracle Database занимает от нескольких недель до нескольких месяцев.

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

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

Так как основной код был написан в конце 90-х, в Revit используется (исключая визуализацию) только одно ядро процессора, что сдерживает производительность проектирования. Например, у программы Revit уже нет возможности работать в многопоточном режиме, используя все ядра в hardware. И даже если у вас через 10 лет будет тысяча ядер в процессоре - прироста производительности в программе Revit вы не получите.

Геометрическое ядроГеометрическое ядро

Благодаря постоянной текучке кадров в дополнение к проблеме закрытой разработки кода, вокруг нас полно старых Legacy продуктов, которые написаны ужасно плохо, но при этом невероятно сложно и дорого поддерживаются сегодня на плаву. Причём переписать их уже никогда не получится, потому что они взаимодействуют с таким же ужасным кодом у пользователей продукта, и поэтому необходимо соблюдать совместимость с багами и не документированными особенностями. По этой причине многие продукты стали заложниками обратной совместимости. В том числе Windows, Microsoft Office и основные программы на рынке САПР.

У таких программ, как Revit, ArchiCAD, Microstation уже нет будущего, и возможно, сами вендоры это понимают. Поэтому все силы корпораций сегодня тратятся не на увеличение производительности геометрического ядра, а на поиск нового успешного продукта или новых уникальных разработчиков, как Leonid Raiz (Revit), Mike Riddle (AutoCAD) или Gabor Bojar (ArchiCAD).

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

Исследование Campaign for Clear Licensing, показало, что аудиты, проводимые такими поставщиками программного обеспечения, как Oracle и Autodesk (Microsoft, SAP, IBM) блокируют конкуренцию и препятствуют инновациям в ИТ-отделах компаний, где эти аудиты проводились.

Кто наименее полезный поставщик с точки зрения аудита? Oracle был признан худшим поставщиком в процессе аудита, за ним следуют IBM и Autodesk.Кто наименее полезный поставщик с точки зрения аудита? Oracle был признан худшим поставщиком в процессе аудита, за ним следуют IBM и Autodesk.

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

Основной головной болью руководителей больших корпораций Oracle, Microsoft, SAP, Autodesk, IBM к середине 2000-х становится не миллион строк спагетти кода, а новые open source продукты, стремительно набирающие популярность: Linux, GitHub, Spark, Mozilla, Gimp, PHP, WordPress, Android, Blender и тысячи других.

В случае с Oracle таким конкурентом стал молодой open source стартап из Швеции - MySQL.

Борьба корпораций с open source

Обычно любые стартапы, стоящие на пути корпораций, уже к началу 2000-х можно было купить при поддержке BlackRock, но как купить Оpen source-идею, за которой стоят сотни разработчиков со всего мира?

MySQL - open source проект, который одновременно разрабатывали сотни специалистов со всего мира. При этом код полностью бесплатен и прозрачен для дальнейшей разработки (или написания инструментов для него), благодаря чему MySQL быстро завоевал популярность на рынке баз данных.

Популярность баз данных по годам с 2013 годаПопулярность баз данных по годам с 2013 года

В борьбе за рынок Oracle начала снижать цены и предоставлять большие скидки тем компаниям, которые уже использовали или ещё только собирались использовать MySQL. Одновременно с этим Oracle, осознавая угрозу своему бизнесу, всеми способами пытался купить это быстрое, бесплатное и прозрачное DBMS решение.

В течение всего 2006 года Ларри Эллисон (глава Oracle с одесскими корнями) неоднократно предлагал выкупить MySQL, но трое друзей-шведов, основателей MySQL, постоянно отвергали предложение от империи зла Oracle, взлёт которой произошёл благодаря сотрудничеству с ЦРУ.

Стабильный Oracle c 1997 годаСтабильный Oracle c 1997 года

В итоге акционеры MySQL продали свой продукт компании Sun (отцы-основатели МySQL получили от сделки по $10 mln.) и уже в 2009 году Oracle сумел опередить IBM и заключил соглашение о покупке компании Sun (вместе с продуктом MySQL) за $7.4 миллиардов.

В 2009 MySQL ждало большое обновление: в версии MySQL 5.4 появилась поддержка 16-процессорных серверов x86, и, по некоторым тестам, производительность MySQL должна была вырасти в десятки раз. Выход MySQL 5.4 был запланирован на 21 апреля, но, по случайности, за день до того произошла сделка с Oracle.

Уже после покупки, чтобы не давать развития своему непокорному приёмному open source сыну, с 2009 г., Oracle (которая теперь являлась владельцем прав на MySQL) пыталась изнутри расшатать и замедлить открытую модель разработки знаменитой СУБД.

Таким образом, Oracle, при помощи BlackRock, расчистил рынок своему основному закрытому спагетти продукту Oracle Database на следующие 10 лет, а акционеры инвестиционных фондов теперь могли ожидать выплаты дивидендов на ожидаемом уровне в ближайшие годы.

Но open source MySQL-идею убить уже невозможно, и разработчики из комьюнити MySQL начали перетекать в другие open source проекты. В итоге все основные разработчики MySQL махнули рукой на Oracle и перешли на более быстрые и современные open source базы данных - MariaDB (форк копия MySQL), PostgreSQL и SQL-lite.

Подобные покупки постоянно происходят и на рынке САПР-решений. Все те же тренды ждут любых разработчиков САПР и BIM-решений, а сама история с MySQL похожа на историю с IFC, изначально открытым форматом.

Oracle, по сути, сделал c MySQL то же самое, что сделал Autodesk c IFC в середине 90-х, но гораздо быстрее и проще.

Autodesk и формат данных IFC

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

Так как сам Leonard Obermeyer не был программистом, эту идею он передал своему родному факультету мюнхенского университета, где дальнейшей разработкой нового открытого формата занимались Richard Junge и Thomas Liebich с командой студентов.

Идеей создателей IFC-формата было создать всемирный и свободный язык обмена данными в строительстве (несмотря на военные корни формата IFC-STEP, протокола Application Protocol 225), но в начале 90-х ещё мало было известно об open source.

Благодаря другу Leonard Obermeyer - Patrick MacLeamy (CEO of HOK) - Autodesk активно включается в развитие всемирной идеи IFC. Проходит всего несколько лет, и регистрацию и разработку IFC берёт полностью под свой контроль Autodesk.

Об этом подробнее в Часть 3: Отцы BIM технологий. Кто стоит за успехом Autodesk и openBIM?

Но к концу 90-х, не имея нормальных 3D-продуктов, сам Autodesk не смог применять нормально этот продукт в своих программах - и идея мирового 3D формата уходит под контроль картельной организации IAI (которая позже переименовывается в buildingSMART).

Для контроля над развитием IFC у руля buildingSMART остаётся Patrick MacLeamy, партнёр корпорации Autodesk по совместным проектам с компанией HOK (где McLeamy был CEO). К слову, в некоторых странах ещё сегодня представителями Autodesk и представителями buildingSMART являются зачастую одни и те же специалисты.

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

Подобным образом Autodesk выпустил на рынок open source решение Dynamo, которое используется в Revit и Civil 3D для расширения функционала. Dynamo изначально представлялся как open source продукт, который внезапно возник в 2011 году в недрах Autodesk (или точнее был разработан по заказу Autodesk). Так же, как и buildingSMART, к рождению которого приложила руку корпорация Autodesk, - код Dynamo тоже не отличается прозрачностью. Многие разработчики указывают на то, что пакеты, завернутые в библиотеки DLL, часто запрещают доступ к коду, что не позволяет пользователям исследовать ни код, ни то, как отдельные куски кода обрабатываются или анализируются в инструменте Dynamo. Что также не позволяет использовать Dynamo в продуктах, по-настоящему открытых, таких как BlenderBIM (для визуального программирования в Blender сегодня используется Sverchok).

Типы open source: совершенно свободный, с явным контролем, неявно контролируемыйТипы open source: совершенно свободный, с явным контролем, неявно контролируемый

Таким образом, Autodesk в контроле над открытыми проектами IFC и Dynamo создала конструкцию, похожую на ту, что Oracle создал с MySql. Только в мире баз данных - Oracle открыто, через Sun, купила open source - MySql, а Autodesk на расстоянии контролирует движение проектов Dynamo и buildingSMART (который, в свою очередь, старается на расстоянии общаться с европейскими вендорами openBIM движения - Nemetschek).

И если сегодня образуется по-настоящему новый open source формат или у Revit появится достойный open source конкурент, - то Autodesk пойдёт проверенным путём Oracle и, возможно, попытается выкупить права на любой продукт на самых ранних стадиях, что, скорее всего, опять продлит жизнь продуктам Autodesk ещё на одно десятилетие.

Как узнать кто уже мёртв, а кто ещё нет? Мы маленькая строительная компания.Как узнать кто уже мёртв, а кто ещё нет? Мы маленькая строительная компания.

Сегодня buildingSMART неспешно пытается устанавливать правила на рынке САПР, при этом интересы buildingSMART в основном диктуются потребностями основных игроков в этой нише - Autodesk, Bentley Systems (с 2019 Oracle).

Единственной более-менее свободной от лоббирования организацией остаётся альянс ODA (Open Design Alliance).

Проблема Autodesk - организация открытых стандартов - ODA

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

ODA создала продукты (основным из которых является Teigha) с возможностью для более чем 2000 организаций-членов работать без всякой оглядки на Autodesk, чем фактически убрал искусственные барьеры, которые сдерживали развитие всей отрасли САПР.

Альянс по Открытому Проектированию (Open Design Alliance) является некоммерческим консорциумом, нацеленным на распространение открытых форматов для обмена данными САПР. Технологическая платформа ODA обеспечивает пользователей средствами для создания широкого спектра приложений, включая средства визуализации и даже полномасштабные САПР. Платформа поддерживает файлы DWG, DGN, RFA, IFC, RVT с возможностями редактирования, импорта и экспорта в другие файловые форматы.

История ODA началась с попытки Autodesk купить компанию SoftDesk, которая в середине 90-х разрабатывала свою САПР-платформу с целью полностью заменить AutoCAD. После антимонопольного расследования суд запретил Autodesk покупать SoftDesk, который позже (после передачи прав VISIO) был выкуплен компанией Microsoft.

На основе технологий компании Softdesk и InteliCADD (позже InteliCAD) в 1998 году образуется новый альянс OpenDWG. Альянс ODA (OpenDWG Alliance) поставил своей целью уравнивать шансы всех производителей САПР-решений, вне зависимости от того, в каких отношениях с компанией Autodesk находятся эти разработчики.

Эквалайзер - урванитель САПР разработкиЭквалайзер - урванитель САПР разработки

Первый конфликт между ODA и Autodesk возник в начале 2000-х вокруг формата DWG.

В 1998 году ODA предоставила новые инструменты миллионам пользователей программного обеспечения с возможностью продолжать использовать формат файла DWG без привязки к единственному поставщику продуктов - Autodesk.

Примечательно, что сам формат файла DWG и программа Autocad были разработаны Mike Riddle и что DWG использовался в конце 1970-х в его InteractCAD, и только в 1982 году John Walker выкупает полностью продукт Autocad вместе с форматом DWG, основывая таким образом фирму Autodesk для массовой продажи DWG продукта.

Сам Autodesk после покупки программы Autocad (20 лет) не предоставлял API для доступа к файлам DWG, поэтому и ответом на такую закрытость стало появление на рынке САПР первой открытой инициативы: GNU LibreDWG, который мог читать формат DWG. Но, к сожалению, LibreDWG не мог редактировать информацию в DWG файле.

Этот барьер по изменению файла DWG смог преодолеть альянс ODA с продуктом Teigha, который позволял работать с форматом DWG в любой САПР-программе. Этот продукт уравнял шансы всех САПР-разработчиков, и именно ему обязаны своим успехом такие ныне известные компании, как бельгийская Bricsys, немецкая Graebert, французская DraftSight, китайская ZWSoft, российская NanoSoft и ряд других.

В ответ на открытые разработки Autodesk создал для сторонних разработчиков САПР инструмент - RealDWG (настоящий истинный DWG) в виде модулей экспорта и импорта, что позволяло сторонним разработчикам САПР-программ наконец встраивать в свой функционал экспорт и импорт чертежей в формате DWG.

С 2006 года на ODA посыпались судебные иски от Autodesk, которая пыталась защитить купленный ими в 1982 году продукт DWG. И с момента противостояния с ODA, чтобы усложнить жизнь конкурентам и искусственно ограничить конкуренцию, Autodesk создавала каждые несколько лет новую версию самого правильного DWG формата (при этом вставляя в формат водяные знаки Autodesk).

Иск компании Autodesk к альянсу ODA через Американский окружной суд (US District Court)Иск компании Autodesk к альянсу ODA через Американский окружной суд (US District Court)

В 2006 году компания Autodesk внедрила в обновленный формат DWG 2007 технологию TrustedDWG, которая позволяла определить, создан ли файл формата DWG в одной из программ Autodesk или в программе, использующей RealDWG. В случае, если файл DWG 2007 создан в нелицензированной программе, AutoCAD показывал сообщение, предупреждающее пользователя о возможных проблемах совместимости. Компания мотивировала своё решение заботой о пользователях.

Из-за резкого интереса конкурентов к инструментам ODA, спустя 25 лет после создания DWG, Autodesk в 2006 году решила зарегистрировать DWG как свою торговую марку. Захватив рынок CAD, Autodesk утверждала, что самый правильный DWG файл могут делать только продукты Autodesk.

Autodesk выиграл суды, и на первый взгляд показалось, что Autodesk отстоял свои права на формат DWG, но судебные запреты не стали концом света для альянса ODA.

В 2007 году иск был окончательно отозван. Стороны заключили мировое соглашение. ODA исключил код TrustedDWG из библиотек DirectDWG, а Autodesk изменил предупреждающие сообщение в AutoCAD 2008. В итоге в решениях суда речь шла только о торговой марке "DWG", при этом формат файла DWG остался общедоступным.

Информация о проигрыше в суде на официальном сайте ODAИнформация о проигрыше в суде на официальном сайте ODA

Возможно, уже сегодня подобная борьба разворачивается за форматы RVT и RFA.

Revit (и похожий продукт форк PTC - Solidworkds) и форматы RFA и RVT были разработаны Леонидом Райцем (и его учителем по PTC - Самуилом Гайзбергом) в 90-е. После покупки при помощи патентов и регистрации прав на торговые марки Autodesk пытался закрепить своё право над 3D САПР-программой Revit и её форматом.

В мае 2020 года, на пике интереса к продукту Revit и его BIM решениям (а не на закате популярности, как это было с Autocad), ODA официально выходит на рынок со своим продуктом BimRv SDK. BimRv SDK от ODA предлагает работать с данными Revit без зависимости от приложения Revit. Инструмент позволяет, например, создавать семейства (геометрию типов), не используя Revit.

За несколько лет до публикации релиза BimRv ODA становится первым вендором, который позволяет не просто читать информацию из IFС, а дает возможность создавать IFC геометрию, чего ещё ни одна САПР-компания сделать не смогла. Полный открытый IFC-набор инструментов от ODA будет представлять собой доступ к данным и к созданию объектов, интегрированный с высокоскоростной визуализацией и возможностями конвертирования IFC-данных в другие форматы, такие как .dwg.

Логично, что если инструмент, редактирующий Revit или IFC файлы от ODA, получит реальное распространение, то прибыли, которые Autodesk сегодня делает на своих продуктах, могут резко упасть.

На опыте борьбы с Softdesk и после судебных тяжб с ODA по продукту Teigha-DWG Autodesk понимает, что ODA c BimRv SDK уже продвинулась на порядок дальше в своих возможностях, и теперь ODA уже не допустит ошибок, которые были допущены в борьбе за открытость формата DWG.

Поэтому сегодня Autodesk остаётся массово скупать новые технологии на рынке стартапов или пробовать "усложнить" работу альянса ODA, который пытается незаконно (по мнению Autodesk) распространять форматы RVT и DWG и, по пути, стать тем самым возрождённым SoftDesk, который Autodesk не получилось до конца убить в самом начале развития.

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

Публий Овидий Назон

Наблюдая за успехами ODA со стороны, через несколько месяцев после того, как ODA опубликовал BimRV, Autodesk вынес волевое решение присоединиться к альянсу ODA, чтобы, возможно ближе понять все возможности альянса, который ещё не удалось купить. Autodesk указал причину присоединения к ODA: интерес к набору инструментов IFC от ODA (который обеспечивает полную и гибкую совместимость с IFC для любого настольного или веб-приложения). При этом в саму организацию buildingSMART, которая занимается не только инструментами IFC, но и разработкой непосредственно формата IFC, Autodesk вступил на один месяц позже, в октябре 2020 года.

ODA показывает BimRV SDK - Autodesk вступает в ODA - Autodesk вступает в buildingSMARTODA показывает BimRV SDK - Autodesk вступает в ODA - Autodesk вступает в buildingSMART

Из-за активности альянса ODA по раскрытию форматов RVT, RFA, начиная с 2020 года Autodesk стал активно возвращаться к управлению своим брошенным приемным сыном - форматом IFC, встраивая с версии Revit-2020 все те возможности экспорта в IFC формат, которые до этого (видимо, искусственно) тормозились или просто не развивались.

Возможно, Autodesk понимает, что закрытые форматы сегодня больше не смогут быть драйвером той бизнес-модели, которая успешно работала в 90-е годы, и поэтому сегодня Autodesk ставит для себя целью отказаться от форматов и продавать главным образом облачные решения. Одновременно с этим Autodesk спешит возглавить разработку открытых технологий в САПР-мире вслед за своими друзьями: IBM, Microsoft, Oracle, SAP, которые также заявили свои права на лидерство в open source-разработках (об этом подробнее в следующей части).

Но открытость open source плохо сочетается с той политикой, которую фирмы силиконовой долины проводили последние 30 лет.

В заключение

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

Старые корпорации, такие как Autodesk, Hexagon, Nemetschek Group, Trimble, построившие отличную инфраструктуру в 90-е, пытаются подстраиваться под быстрые изменения рынка. Разработка Legacy программ, например, Revit и Archicad, тормозится. Небольшие CAD и BIM стартапы или уничтожаются, или покупаются за пару миллионов (или как Plngrid, Aconex уже миллиардов) долларов - и уходят в бюрократическую систему дедлайнов и костылей; а к самостоятельной разработке новых идей и инструментов у корпораций, кажется, нет ни интереса, ни творческих способностей.

Олигополия в САПРОлигополия в САПР

Кризис программного обеспечения в САПР и в других технологиях носит также системный и поколенческий характер. Проблема в том, что сейчас у руля BlackRock, Vanguard, Oracle, Autodesk и других компаний стоит поколение X или Baby-Boomers, которые ещё помнят деколонизацию доминионов и карибский кризис в 60е.

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

Определение поколенийОпределение поколений

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

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

Плановая экономика тогда и сейчасПлановая экономика тогда и сейчас

Ни в коем случае нельзя обвинять в алчности структуры, построенные BlackRock и Vanguard: на их месте любая организация и возможно любой человек поступил бы точно так же. Мы можем быть благодарны им за то, что конкретно этот тупиковый путь выбрали именно они.

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

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

Тот уже не хитрый, о ком все говорят, что он хитер.

Александр Суворов

Логично, что BlackRock и Vanguard уйдут в историю со своей бюрократией и сложными закрытыми конструкциями, точно так же, как эта бюрократия и вертикальная система связей исчезла из плановой экономики Советского Союза.Для поражения BlackRock и Vanguard не хватает только сильного соперника, которым может стать сегодня децентрализированная экономика.

Благодаря прозрачности информации: журналистам, появлению камер и фотоаппаратов - в конце 20 века люди перестали убивать массово других людей. А в 21 веке, благодаря интернету и децентрализованным приложениям, на наших глазах при помощи open source кода создаётся новая децентрализованная экономика, за которой пытаются угнаться старые корпорации со своим другом BlackRock.

Эти многие западные компании и структуры в будущем ещё ждут своя перестройка и своя гласность.

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

Неизвестный автор

Остаётся надеяться на кризисы и чёрных лебедей, вроде COVID-19, благодаря которым специалисты со всего мира после 2021 года, возможно, перестанут торопиться переезжать в другие страны и искать своё место в этой, хоть и денежной, но очень забюрократизированной и устаревшей структуре. Такие новые уникальные специалисты, вроде Gabor Bojar, Mike Riddle, Samuel Geisberg, могут уже сегодня заниматься разработкой новых САПР-BIM технологий из любого доступного места.

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

Про решения Оpen source, монетизацию про то почему IFC это не open source поговорим в следующей части.


Если Вам интересна тема openSource и BIM (продукты с открытым кодом в строительстве) подключайтесь к обсуждению в группе телеграмм - bimopensource: https://t.me/bimopensource

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

Схема связей BIM программ указанных в статье в хорошем качестве доступна по ссылке.

Предыдущие статьи по теме:

Сравнение технологий в строительстве и 5D проектирование в Азии и Европе: Казахстан, Австрия, Германия, Китай, Украина

Войны лоббистов и развитие BIM. Часть 4: Борьба CAD и BIM. Монополии и лоббисты в строительной отрасли

Подробнее..

Перевод Код без тестов легаси

26.02.2021 12:14:08 | Автор: admin

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

Автор Николас Карло, веб-разработчик в Busbud (Монреаль, Канада). Специализируется на легаси. В свободное время организует митап Software Crafters и помогает с конференциями SoCraTes Canada и The Legacy of SoCraTes.

Данная статья была скомпилирована (и отредактирована) их двух статей Николаса: What is Legacy Code? Is it code without tests? и The key points of Working Effectively with Legacy Code. Показалось логичным рассказать о том, что такое легаси, а потом как с ним работать.

Что такое легаси?

Возможно, если вы задавались этим вопросом, то встречали определение от Майкла Физерса. Майкл выпустил книгу Working Effectively with Legacy Code в 2004 году, но она до сих пор актуальна. Комикс это отлично иллюстрирует.

В своей книге Майкл пишет своё определение:

Для меня легаси это просто код без тестов.

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

Это хорошее определение: чаще всего тесты отсутствуют, так что это хорошее начало. Но это ещё не всё есть нюансы.

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

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

Перейдём к моему определению легаси.

Легаси это ценный код, который вы боитесь менять.

Например, мы ищем первопричину ошибки или выясняете, куда вставить свою функцию. Мы хотим поменять код, но это трудно, потому что непонятно как не нарушить существующее поведение. Готово у нас легаси!

Но есть нюансы.

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

Хорошие тесты помогают легко менять незнакомый код. А плохие тесты не помогают. Отсюда и определение Физерса.

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

Легаси не виновато в том, что оно такое. Большая часть кода ужасна, потому что это результат работы многих людей в течение долгого времени с противоречивыми требованиями и под давлением дедлайнов. Это Рецепт Устаревшего Кода. Когда мало времени и недостаточно знаний рождаются костыли (ну вы знаете). В конце концов, мы достигнем состояния, когда каждое движение приводит к ошибке, а реализация любой функции занимает целую вечность.

А теперь один из важнейших нюансов.

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

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

В итоге мы получаем, что легаси это:

  • код без тестов;

  • который мы пытаемся понять, чтобы отрефакторить;

  • но боимся.

Что же делать?

Как же эффективно работать с легаси?

Легаси код, который мы пытаемся понять, чтобы отрефакторить. Задача рефакторинга в том, чтобы сохранить существующее поведение кода. Как без тестов мы будем уверены, что ничего не сломали? Нам нужна обратная связь. Автоматизированная обратная связь ещё лучше.

Добавить тесты, а затем внести изменения

Логично, что если добавить тесты, они помогут его прощупать и он перестанет быть устаревшим. Поэтому первое, что нужно сделать написать тесты. Только тогда мы будем в безопасности, чтобы рефакторить код.

Но чтобы запустить тесты, мы должны поменять код. Возникает парадокс легаси. Мы обречены? Нет. Поменяем как можно меньше кода для тестов:

  • Определим точки изменения швы.

  • Разорвём зависимости.

  • Напишем тесты.

  • Внесём изменения.

  • Отрефакторим.

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

Найти швы для разрыва зависимостей

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

Чтобы протестировать код, нужно разбить эти зависимости в тестах. Для этого необходимо выявить швы.

Шов место, где можно изменить поведение программы, не меняя код.

Швы бывают разные. Если это объектно-ориентированный ЯП, то обычно это объект, например, в JavaScript.

export class DatabaseConnector {// A lot of codeconnect() {// Perform some calls to connect to the DB.}}

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

class FakeDatabaseConnector extends DatabaseConnector {connect() {// Override the problematic calls to the DBconsole.log("Connect to the DB")}}

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

Напишем unit-тесты

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

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

Чтобы избежать путаницы, Майкл даёт четкое определение того, что такое НЕ unit-тест:

  • он не работает быстро (< 100ms / test);

  • он взаимодействует с инфраструктурой, например, базой данных, сетью, файловой системой, переменными;

Напишите максимум тестов, которые обладают этими 2 качествами, при этом неважно, как вы их назовёте.

Иногда трудно написать такие тесты, потому что не понятно, что код должен делать. Тогда используйте специальную технику.

Тесты для определения характеристик

Это тесты, которые формализуют фактическое поведение части кода.

Вместо того чтобы писать комплексные модульные тесты, мы фиксируем текущее поведение кода делаем снимок того, что он делает. Тест гарантирует, что это поведение не изменится!

Это мощная техника, потому что:

  • В большинстве систем то, что код делает важнее того, что он должен делать.

  • Мы можем быстро покрыть легаси с помощью этих тестов. Так мы подстрахуемся для рефакторинга.

Этот метод также называют Approval Testing (тестированием одобрения), Snapshot Testing или Golden Master.

Но обычно на всё это очень мало времени.

Когда совсем нет времени на рефакторинг

Несколько советов, если предыдущие не подходят.

Большие куски кода обладают гравитацией и привлекают ещё больше кода. Теория разбитых окон в действии: небольшой беспорядок влечёт за собой беспорядок серьёзнее. Если класс уже содержит 2000 строк, то какая разница, что вы добавите еще 3 if оператора и будете поддерживать класс длиной в 2010 строк?

Это всего лишь 3 if: тяжело себя убедить, что нужно потратить на них 2 дня, хотя и должны. Что делать, если действительно нет времени писать тесты для этого класса? Используйте техники Sprout (прорастание), Wrap (обёртывание) и скретч-рефакторинг.

Sprout

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

Рассмотрим на примере:

class TransactionGate {//  a lot of codepostEntries(entries) {for (let entry of entries) {entry.postDate()}//  a lot of codetransactionBundle.getListManager().add(entries)}//  a lot of code}

Допустим, нам нужно убрать дубли файла entries, но postEntries() трудно проверить нет на это времени. Мы можем прорастить код где-то ещё, например, в новом методе uniqueEntries(). Этот новый метод легко протестировать, потому что он изолирован. Затем вставим вызов этого метода в существующий, не проверенный код.

class TransactionGate {//  a lot of codeuniqueEntries(entries) {// Some clever logic to dedupe entries, fully tested!}postEntries(entries) {const uniqueEntries = this.uniqueEntries(entries)for (let entry of uniqueEntries) {entry.postDate()}//  a lot of codetransactionBundle.getListManager().add(uniqueEntries)}//  a lot of code}

Минимальные изменения, минимальный риск. Можете вырастить один метод, целый класс или что-то ещё, что изолирует новый код.

Wrap

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

  • Переименуем старый метод, который хотим обернуть.

  • Создадим новый с тем же именем и подписью, что и старый.

  • Вызовем старый метод из нового.

  • Поместим новую логику до/после вызова другого метода.

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

class TransactionGate {//  a lot of codepostEntries(entries) {for (let entry of entries) {entry.postDate()}//  a lot of codetransactionBundle.getListManager().add(entries)}//  a lot of code}

Ещё один способ решить эту проблему это обернуть её, поэтому мы переходим к postEntries(), списку записей, из которых мы удалили дубли.

class TransactionGate {//  a lot of codepostEntries(entries) {// Some clever logic to retrieve unique entriesthis.postEntriesThatAreUnique(uniqueEntries)}postEntriesThatAreUnique(entries) {for (let entry of entries) {entry.postDate()}//  a lot of codetransactionBundle.getListManager().add(entries)}//  a lot of code}

В тестах мы бы изменили проблему postEntriesThatAreUnique(), чтобы проверить, работает ли логика удаления дубликатов. Разница может быть ещё больше.

class TransactionGate {//  a lot of code+ postEntries(entries) {+  // Some clever logic to retrieve unique entries+  this.postEntriesThatAreUnique(uniqueEntries)+ }+ postEntriesThatAreUnique(entries) {- postEntries(entries) {for (let entry of entries) {entry.postDate()}//  a lot of codetransactionBundle.getListManager().add(entries)}//  a lot of code}

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

Скретч-рефакторинг

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

Его цель в том, чтобы ознакомиться с кодом, а не менять. Мы играем с кодом столько, сколько захотим: извлекаем функции, упрощаем, переименовываем переменные. Как только сделаем, всё, что нам нужно откатим всё обратно и начнём с правильных тестов.

Выводы

Легаси будет везде, где бы вы ни работали, в каждой кодовой базе. Можно сопротивляться и чувствовать себя плохо, когда вы застряли в нём. А можно рассматривать это как возможность. Работа со старым кодом это очень ценный навык, его надо изучать теоретически (почитайте книгу Working Effectively with Legacy Code) и практиковать в ежедневных задачах.


Похожие и интересные статьи:

Больше новостей про разработку в Додо Пицце я пишув канале Dodo Pizza Mobile. Также подписывайтесь начат Dodo Engineering, если хотите обсудить эту и другие наши статьи и подходы, а также на каналDodo Engineering, где мы постим всё, что с нами интересного происходит.

А если хочешь присоединиться к нам в Dodo Engineering, то будем рады сейчас у нас открыты вакансииiOS-разработчиков(а ещё для Android, frontend, SRE и других).

Подробнее..

Как запускается сервер UEFI

27.08.2020 18:04:37 | Автор: admin

Ранее мы уже разбирали последовательность запуска сервера на примере устаревшего Legacy. Настало время познакомиться с UEFI поближе.

Первая версия того, что сейчас известно как Unified Extensive Firmware Interface (UEFI), разрабатывалась в 90-е годы прошлого тысячелетия специально под системы на Intel Itanium и называлась Intel Boot Initiative, а позже EFI.

Желание обновить процесс загрузки было ожидаемо. PC-BIOS, именуемый ныне Legacy, предлагает работать в 16-битном real mode, адресует всего 1 МБ оперативной памяти, а загрузчик вместе с таблицей разделов должен размещаться в первых 512 байтах накопителя. Более того, PC-BIOS передает управление первому найденному загрузчику без возможности возврата назад. При этом обработку случаев с несколькими операционными системами возлагают на плечи загрузчика.

Ограничение на размер загрузчика диктует использование разметки Master Boot Record (MBR), появившийся в 1983 году. MBR не стандартизирован, однако множество производителей придерживаются сложившихся традиций. У MBR есть серьезные ограничения: по умолчанию поддерживается только 4 раздела и объем накопителя не более 2.2 ТБ.

В декабре 2000 года была выпущена первая широко распространенная спецификация EFI под версией 1.02. Спустя пять лет Intel передали EFI в UEFI Forum, добавив Unified в название, чтобы подчеркнуть изменения. Спецификация UEFI лежит в открытом доступе и состоит из нескольких документов:

  • ACPI Specification;
  • UEFI Specification;
  • UEFI Shell Specification;
  • UEFI Platform Initialization Specification;
  • UEFI Platform Initialization Distribution Packaging Specification.

Самое интересное начинается в UEFI Platform Initialization Specification, где описываются все фазы загрузки платформы.

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

Wake up, Neo!


Последовательность фаз загрузки UEFI (источник UEFI Platform Initialization Specification)
После инициации включения платформы блок питания ждет, пока не завершатся переходные процессы, и после устанавливает сигнал на линию Power_Good. И первым начинает работу не центральный процессор, а автономная подсистема Intel Management Engine (ME) или аналогичная ей AMD Secure Technology (ST). Эта подсистема проводит собственные операции, а затем подготавливает и запускает первое ядро одного процессора, именуемое Bootstrap Processor (BSP).
В соответствии с принятой терминологией ядро/поток процессора здесь и далее будет называться процессором: начальным (bootstrap processor) или прикладным (application processor).
Как и в Legacy, процессор начинает выполнять первую инструкцию в конце адресного пространства по адресу 0xFFFFFFF0. Эта инструкция прыжок на первую фазу инициализации платформы SEC.

Фаза SEC (Security)


В данной фазе должны быть решены следующие задачи:

  • обработка события включения;
  • инициализация достаточного количества памяти для следующей фазы;
  • становление корня доверия системы;
  • передача необходимой информации и управления на следующую фазу.

Процессоры x86_64 запускаются в 16-битном реальном режиме, и в процессе первичной инициализации BSP переводится в 32-битный защищенный режим. Затем происходит обновление микрокода всех доступных процессоров.

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

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

Далее происходит инициализация всех прикладных процессоров (Application Processor, AP) с отправкой им специальной последовательности межпроцессорных прерываний (Inter-Processor Interrupt, IPI). Последовательность Init IPI Start-up IPI пробуждает прикладной процессор и запускает на нем самотестирование Built-In Self-Test (BIST). Результаты тестирования записываются и передаются далее для анализа.

В конце фазы Security необходимо найти раздел Boot Firmware Volume (BFV), на котором располагается исполняемый код следующей фазы, а также по возможности найти другие, неосновные, разделы с кодом (Firmware Volume, FV).

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

В конце выполнения SEC собрана следующая информация:

  • размер и адрес Boot Firmware Volume (BFV);
  • размер и адреса других Firmware Volume (FV);
  • размер и адрес временной оперативной памяти;
  • размер и адрес стека.

После чего начинается следующий этап Pre EFI Initialization.

Фаза PEI (Pre EFI Initialization)


Фаза PEI на материнской плате SuperMicro
Задача фазы Pre EFI Initialization заключается в сборе информации о подключенных устройствах и подготовке минимально необходимого количества оборудования для запуска процесса полной инициализации.

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

Данная фаза состоит из ядра, называемого PEI Foundation, и подключаемых модулей PEI Module (PEIM). Центральной частью ядра является диспетчер модулей, PEI Dispatcher, который управляет порядком исполнения модулей, а также организует межмодульное взаимодействие (PEIM-to-PEIM Interface, PPI).

Отметим, что фаза SEC исполнялась с флэш-памяти на материнской плате, и только в начале PEI необходимый для этой фазы исполняемый код копируется во временную оперативную память.

Далее к работе приступает PEI Dispatcher. Он запускает PEI модули в конкретном порядке: сначала модули без зависимостей, затем зависящие от первых и так до тех пор, пока модули не закончатся.

Архитектура фазы PEI позволяет разрабатывать собственные модули, которые могут передавать результаты своей деятельности в следующую фазу. Передача информации происходит через специальную структуру данных Hand-off Block (HOB).

В процессе запуска PEI модулей отметим следующие:

  • CPU PEIM инициализация процессоров;
  • Platform PEIM инициализация северного (в т.ч. Memory Controller Hub) и южного (I/O Controller Hub) мостов;
  • Memory Initialization PEIM инициализация основной оперативной памяти и перенос данных из временной памяти в RAM.

Ранее из фазы SEC была получена информация о включении. Если событием включения является S3 Resume, то следом выполняется S3 BootScript, который восстанавливает сохраненное состояние процессоров и всех подключенных устройств, а после передает управление напрямую в ОС.
Состояние S3 (Suspend to RAM) это состояние сна, при котором процессор и часть чипсета отключаются с потерей контекста. При пробуждении из такого состояния процессор начинает выполнение как при обычном включении. Но вместо полной инициализации и прохождения всех тестов система ограничивается восстановлением состояния всех устройств.
При запуске из любого другого состояния управление передается в фазу Driver Execution Environment.

Фаза DXE (Driver eXecution Environment)


Инициализация механизма AHCI в фазе DXE
Задача фазы Driver Execution Environment (DXE) сводится к инициализации оставшихся устройств. К моменту старта фазы DXE процессор и основная память уже готовы к работе, а на драйверы DXE не накладываются строгие ограничения по потребляемым ресурсам.

Аналогично PEI Foundation в данной фазе есть собственное ядро DXE Foundation. Ядро создает необходимые интерфейсы и загружает три вида DXE сервисов:

  • UEFI Boot Services сервисы времени загрузки;
  • UEFI Runtime Services сервисы времени исполнения;
  • DXE Services специальные сервисы, необходимые ядру DXE.

После инициализации сервисов начинает работу DXE Dispatcher. Он находит и загружает DXE драйверы, которые, в свою очередь, завершают инициализацию оборудования.
В UEFI нет специализированной фазы, где оборудование проходит POST (Power-On Self-Test). Вместо этого каждый модуль PEI и DXE фазы проводит свой набор тестов и сообщает об этом с помощью POST-кодов пользователю и с помощью HOB в следующие фазы.
Среди множества загружаемых драйверов на процессорах x86_64 стоит уделить внимание драйверу System Management Mode Init (SMM Init). Этот драйвер подготавливает все для работы режима системного управления (System Management Mode, SMM). SMM это особый привилегированный режим, который позволяет приостановить выполнение текущего кода (в т.ч. операционную систему) и выполнить программу из защищенной области памяти SMRAM в собственном контексте.
Режим SMM неофициально считается кольцом защиты с номером -2. Ядро ОС работает на 0 кольце, а более ограниченные в правах кольца защиты имеют номер от 1 до 3. Официально нулевое кольцо считается наиболее привилегированным. Тем не менее, гипервизор с аппаратной виртуализацией условно называют кольцом -1, а Intel ME и AMD ST кольцом -3.
Дополнительно отметим модуль Compatibility Support Module (CSM), который обеспечивает совместимость с Legacy и позволяет загружать ОС без поддержки UEFI. Позднее мы рассмотрим этот модуль подробнее.

После инициализации всего оборудования наступает время выбора загрузочного устройства.

Фаза BDS (Boot Device Select)


В фазе Boot Device Select реализуется политика загрузки приложений UEFI. Несмотря на то, что это отдельная фаза, все сервисы, включая диспетчера, созданные на фазе DXE, остаются доступны.

Цель фазы BDS сводится к выполнению следующих задач:

  • инициализация консольных устройств;
  • поиск устройств, с которых можно загрузиться;
  • попытка загрузиться с найденных устройств в порядке приоритета.

PCIe BIOS карты расширения LSI
Поиском загружаемых областей на устройствах занимается Boot Manager. На некоторых картах расширения, например, на сетевых картах и RAID-контроллерах, может находиться собственный BIOS, называемый Option ROM, или OpROM. Содержимое OpROM устройств запускаются сразу после обнаружения, а после выполнения управление возвращается в Boot Manager.

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

Как отмечалось ранее, использование разметки Master Boot Record накладывает ограничения на размер разделов и их количество на накопителе, а также вызывает определенные неудобства в содержании нескольких операционных систем. Решение всех этих проблем является частью спецификации UEFI GUID Partition Table.

GPT (GUID Partition Table)


GUID Partition Table это стандартизированный формат размещения таблиц разделов, пришедший на смену устаревшей MBR.

Во-первых, GPT использует адресацию логических блоков (Logical Block Addressing, LBA) вместо адресации Цилиндр Головка Сектор (Cylinder, Head, Sector, CHS). Смена способа адресации позволяет GPT работать с накопителями объемом до 9.4 ЗБ (9.4 * 1021 байт) против 2.2 ТБ у MBR.

Во-вторых, таблица разделов претерпела изменения, и теперь в пределах одного накопителя можно создать до 264 разделов, хотя операционные системы поддерживают не более 128 в случае Microsoft Windows и 256 в случае Linux.

В-третьих, каждый раздел имеет свой идентификатор типа, который описывает назначение раздела. Так, например, идентификатор C12A7328-F81F-11D2-BA4B-00A0C93EC93B однозначно указывает на системный раздел EFI (EFI System Partition, ESP), с которого Boot Manager может попробовать загрузить приложение.

При разработке GPT не обошли стороной и совместимость с MBR. Дисковые утилиты могли не распознать GPT диск и затереть его. Чтобы избежать этого, при разметке GPT первые 512 байт заполняются защитной MBR (Protective MBR) разметкой из одного раздела на весь накопитель с системным идентификатором 0xEE. Такой подход позволяет UEFI понимать, что перед ним не настоящий MBR, а старому программному обеспечению без поддержки GPT видеть раздел с данными неизвестного типа.

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

Загрузка операционной системы


После опроса всех устройств и поиска загрузочных областей Boot Manager начинает загружать в порядке приоритета загрузки. В общем случае управление передается в UEFI-приложение, которое начинает выполнять свою логику. Однако для систем с совместимостью с Legacy режимом в списке загрузочных областей может найтись накопитель с разметкой MBR и придется обращаться к CSM, модулю поддержки совместимости.

Модуль CSM позволяет запускать операционные системы, которые не поддерживают UEFI. Для загрузки таких ОС модуль CSM эмулирует окружение, в которое попадает классическая ОС:

  • загружает Legacy-драйвер;
  • загружает Legacy BIOS;
  • переводит видеовывод в совместимый с Legacy режим;
  • создает в памяти необходимые для Legacy структуры данных, отсутствующие в UEFI;
  • загружает драйвер CompatibilitySmm для работы SMM в Legacy.

Напомним, что в Legacy-режиме загрузка ОС начинается в 16-битном режиме, в то время как в UEFI все работает в 32-битном режиме. CSM запускает Legacy-загрузчик в 16-битном режиме и при необходимости обеспечивает связь с 32-битными UEFI-драйверами.

Фаза RT (Run Time)


Начало загрузки ОС или Legacy-загрузчика приводит к началу фазы Run Time. В данной фазе все сервисы DXE (кроме UEFI Runtime Services) перестают быть доступны.

Содержимое фазы RT может быть разным. Здесь может быть привычный по Legacy загрузчик ОС например, GRUB2 или Windows Boot Manager, который переводит процессор в 64-битный режим и запускает ОС. Но могут быть и самостоятельные приложения или сразу ядро операционной системы.

Ядро Linux начиная с версии 3.3 при наличии флага CONFIG_EFI_STUB превращается в обычное UEFI-приложение и может быть запущено из UEFI без использования сторонних загрузчиков.

Как и в случае с Legacy, загрузчику или самому ядру необходимо перевести процессор в 64-битный режим, загрузить все драйвера, настроить планировщик и запустить init. Init, в свою очередь, запускает процессы в пространстве пользователя, после чего появляется окно логина в ОС.

Заключение


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

Как Вы думаете, как скоро получится полностью уйти от Legacy?
Пишите свое мнение в комментариях.
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru