HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-21
1 <p><a>#статьи</a></p>
1 <p><a>#статьи</a></p>
2 <ul><li>21 апр 2021</li>
2 <ul><li>21 апр 2021</li>
3 <li>0</li>
3 <li>0</li>
4 </ul><p>Не ошибается тот, кто ничего не делает.</p>
4 </ul><p>Не ошибается тот, кто ничего не делает.</p>
5 <p>: solen feyissa / unsplash</p>
5 <p>: solen feyissa / unsplash</p>
6 <p>Журналист, коммерческий автор и редактор. Пишет про IT, цифровой маркетинг и бизнес. Сайт:<a>darovska.com</a>.</p>
6 <p>Журналист, коммерческий автор и редактор. Пишет про IT, цифровой маркетинг и бизнес. Сайт:<a>darovska.com</a>.</p>
7 <p>Самая известная история про баг, который привёл к катастрофе, - о том, как американский комплекс противоракетной обороны<a>Patriot</a>умудрился пропустить удар по собственной базе в Саудовской Аравии. Он должен был отслеживать объекты, движущиеся по определённой траектории, но из-за ошибки в коде с каждой минутой работы комплекса увеличивалась погрешность расчёта траекторий. На одной из баз система простояла включённой 100 часов и совсем ослепла. В результате курс атакующей ракеты был рассчитан неправильно и погибло 28 человек. Патч появился только на следующий день.</p>
7 <p>Самая известная история про баг, который привёл к катастрофе, - о том, как американский комплекс противоракетной обороны<a>Patriot</a>умудрился пропустить удар по собственной базе в Саудовской Аравии. Он должен был отслеживать объекты, движущиеся по определённой траектории, но из-за ошибки в коде с каждой минутой работы комплекса увеличивалась погрешность расчёта траекторий. На одной из баз система простояла включённой 100 часов и совсем ослепла. В результате курс атакующей ракеты был рассчитан неправильно и погибло 28 человек. Патч появился только на следующий день.</p>
8 <p>От багов страдали и в NASA -<a>потеряли</a>в космосе спутник Mars Climate Orbiter. Причина банальная: подрядчик забыл преобразовать футы и фунты в единицы метрической системы. Пункт управления задавал двигателю силу в ньютонах, а прошивка думала, что это фунт-силы. В результате аппарат за 125 млн долларов оказался слишком близко к поверхности Марса и вышел из строя. Миссия провалилась. Вот вам и "Лё Биг Мак",<a>if you know, what I mean</a>.</p>
8 <p>От багов страдали и в NASA -<a>потеряли</a>в космосе спутник Mars Climate Orbiter. Причина банальная: подрядчик забыл преобразовать футы и фунты в единицы метрической системы. Пункт управления задавал двигателю силу в ньютонах, а прошивка думала, что это фунт-силы. В результате аппарат за 125 млн долларов оказался слишком близко к поверхности Марса и вышел из строя. Миссия провалилась. Вот вам и "Лё Биг Мак",<a>if you know, what I mean</a>.</p>
9 <p>Мы собрали поучительные истории из практики опытных разработчиков и сделали краткий гайд о том, как минимизировать вероятность появления багов и обезопасить себя от их последствий.</p>
9 <p>Мы собрали поучительные истории из практики опытных разработчиков и сделали краткий гайд о том, как минимизировать вероятность появления багов и обезопасить себя от их последствий.</p>
10 <p><a><strong>Алексей Некрасов</strong></a><strong>,</strong><strong></strong>лидер направления Python в МТС, программный директор направления Python в Skillbox</p>
10 <p><a><strong>Алексей Некрасов</strong></a><strong>,</strong><strong></strong>лидер направления Python в МТС, программный директор направления Python в Skillbox</p>
11 <p>Когда я только пришёл в профессию, то увлекался функциональным программированием - и взялся решать очередную задачу с помощью этой парадигмы. Хотя на проекте уже использовали объектно-ориентированную модель. Задача была примерно такой:</p>
11 <p>Когда я только пришёл в профессию, то увлекался функциональным программированием - и взялся решать очередную задачу с помощью этой парадигмы. Хотя на проекте уже использовали объектно-ориентированную модель. Задача была примерно такой:</p>
12 <ol><li>Инициализировать список объектов (10 шт).</li>
12 <ol><li>Инициализировать список объектов (10 шт).</li>
13 <li>Сформировать из них случайную выборку.</li>
13 <li>Сформировать из них случайную выборку.</li>
14 <li>Получить все возможные комбинации.</li>
14 <li>Получить все возможные комбинации.</li>
15 <li>Для каждой перестановки посчитать определённые свойства.</li>
15 <li>Для каждой перестановки посчитать определённые свойства.</li>
16 <li>Отсортировать полученные свойства.</li>
16 <li>Отсортировать полученные свойства.</li>
17 <li>Взять из них топ-10.</li>
17 <li>Взять из них топ-10.</li>
18 <li>Вывести результат в виде словаря, где ключ - это имя свойства, а перестановка - значение.</li>
18 <li>Вывести результат в виде словаря, где ключ - это имя свойства, а перестановка - значение.</li>
19 </ol><p>Код получился такой:</p>
19 </ol><p>Код получился такой:</p>
20 import itertools import random from typing import List class FakeObject(object): def __init__(self): self.red = random.randint(0, 255) self.blue = random.randint(0, 255) self.green = random.randint(0, 255) def __str__(self): return f"r: {self.red}, b: {self.blue}, g: {self.green}" def fake_feature(fakes: List[FakeObject]) -&gt; int: red, blue, green = 0, 0, 0 for index, i_fake in enumerate(fakes): red = (red + index * i_fake.red) % 255 blue = (blue + index * i_fake.blue) % 255 green = (green + index * i_fake.green) % 255 return red + blue + green print( dict( sorted( map( lambda x: (fake_feature(x), list(map(str, x))), itertools.permutations( filter( lambda x: random.random() &gt; 0.5, map(lambda x: FakeObject(), range(10)) ) ) ), key=lambda x: -x[0] )[0:10] ) )<p>Когда я разрабатывал решение, всё казалось вполне ясным. Но через месяц меня позвал руководитель - и попросил разобраться в этом коде. Мы минут 30 пытались понять, что тут написано и где вкралась ошибка. Возможно, ситуацию спасли бы комментарии к коду - так я быстрее вспомнил бы, что имел в виду. Но их тоже не было. В итоге пришлось всё переписать.</p>
20 import itertools import random from typing import List class FakeObject(object): def __init__(self): self.red = random.randint(0, 255) self.blue = random.randint(0, 255) self.green = random.randint(0, 255) def __str__(self): return f"r: {self.red}, b: {self.blue}, g: {self.green}" def fake_feature(fakes: List[FakeObject]) -&gt; int: red, blue, green = 0, 0, 0 for index, i_fake in enumerate(fakes): red = (red + index * i_fake.red) % 255 blue = (blue + index * i_fake.blue) % 255 green = (green + index * i_fake.green) % 255 return red + blue + green print( dict( sorted( map( lambda x: (fake_feature(x), list(map(str, x))), itertools.permutations( filter( lambda x: random.random() &gt; 0.5, map(lambda x: FakeObject(), range(10)) ) ) ), key=lambda x: -x[0] )[0:10] ) )<p>Когда я разрабатывал решение, всё казалось вполне ясным. Но через месяц меня позвал руководитель - и попросил разобраться в этом коде. Мы минут 30 пытались понять, что тут написано и где вкралась ошибка. Возможно, ситуацию спасли бы комментарии к коду - так я быстрее вспомнил бы, что имел в виду. Но их тоже не было. В итоге пришлось всё переписать.</p>
21 <p>Какие советы я мог бы дать:</p>
21 <p>Какие советы я мог бы дать:</p>
22 <ul><li>Старайтесь придерживаться единого стиля, иначе ваш проект со временем превратится в помойку.</li>
22 <ul><li>Старайтесь придерживаться единого стиля, иначе ваш проект со временем превратится в помойку.</li>
23 <li>Не показывайте свою крутизну, используя сложные решения, - через какое-то время вы сами не сможете прочитать свой код. А если при этом рядом будут другие разработчики, получится вообще не круто.</li>
23 <li>Не показывайте свою крутизну, используя сложные решения, - через какое-то время вы сами не сможете прочитать свой код. А если при этом рядом будут другие разработчики, получится вообще не круто.</li>
24 <li>Не занимайтесь преждевременной оптимизацией.</li>
24 <li>Не занимайтесь преждевременной оптимизацией.</li>
25 <li>Давайте переменным понятные имена: спустя три месяца трудно вспомнить, за что именно должна отвечать переменная.</li>
25 <li>Давайте переменным понятные имена: спустя три месяца трудно вспомнить, за что именно должна отвечать переменная.</li>
26 </ul><p><strong>Михаил Корнеев,</strong><strong></strong>тимлид в BestDoctor и автор YouTube-канала "<a>Хитрый питон</a>"</p>
26 </ul><p><strong>Михаил Корнеев,</strong><strong></strong>тимлид в BestDoctor и автор YouTube-канала "<a>Хитрый питон</a>"</p>
27 <p>Я делал прототип для одного проекта и в какой-то момент пропустил букву в очень неочевидном месте. Эта маленькая ошибка обернулась двумя днями дебаггинга - моё приложение стало периодически обрывать соединение. Пришлось копаться в "кишках" кода на Python и настройках nginx.</p>
27 <p>Я делал прототип для одного проекта и в какой-то момент пропустил букву в очень неочевидном месте. Эта маленькая ошибка обернулась двумя днями дебаггинга - моё приложение стало периодически обрывать соединение. Пришлось копаться в "кишках" кода на Python и настройках nginx.</p>
28 <p>Чтобы поиск ошибки занял меньше времени, надо было ещё до запуска в прод разбить код на более мелкие блоки и протестировать каждый из них. Но это была не основная рабочая задача, а я хотел сделать прототип максимально быстро. Я с трудом разобрался, где именно поселился баг, - он проявился на стыке нескольких разных систем.</p>
28 <p>Чтобы поиск ошибки занял меньше времени, надо было ещё до запуска в прод разбить код на более мелкие блоки и протестировать каждый из них. Но это была не основная рабочая задача, а я хотел сделать прототип максимально быстро. Я с трудом разобрался, где именно поселился баг, - он проявился на стыке нескольких разных систем.</p>
29 <p>Как обезопасить себя от появления таких проблем:</p>
29 <p>Как обезопасить себя от появления таких проблем:</p>
30 <ul><li>Помнить, что ошибки будут всегда, - поэтому надо писать код так, чтобы потом было проще находить проблемные места.</li>
30 <ul><li>Помнить, что ошибки будут всегда, - поэтому надо писать код так, чтобы потом было проще находить проблемные места.</li>
31 <li>Разобраться с тестированием и обязательно писать тесты.</li>
31 <li>Разобраться с тестированием и обязательно писать тесты.</li>
32 <li>Проверять, как работает код: например, запускается или нет. Большая часть ошибок - это опечатки. Если есть тесты, вы их увидите. Но если их нет, а вы всё-таки запустили проверку, то наверняка обнаружите другие проблемы. Я неоднократно видел, как начинающий разработчик закрывает задачу, не проверив код, - в итоге тот просто не работает.</li>
32 <li>Проверять, как работает код: например, запускается или нет. Большая часть ошибок - это опечатки. Если есть тесты, вы их увидите. Но если их нет, а вы всё-таки запустили проверку, то наверняка обнаружите другие проблемы. Я неоднократно видел, как начинающий разработчик закрывает задачу, не проверив код, - в итоге тот просто не работает.</li>
33 <li>Обязательно отдавать проект на код-ревью. Это полезная практика.</li>
33 <li>Обязательно отдавать проект на код-ревью. Это полезная практика.</li>
34 <li>Если программируете на Python, стоит разобраться с типизацией. И помнить, что явное лучше неявного. Это позволит отловить часть ошибок ещё во время написания кода.</li>
34 <li>Если программируете на Python, стоит разобраться с типизацией. И помнить, что явное лучше неявного. Это позволит отловить часть ошибок ещё во время написания кода.</li>
35 <li>Делать резервные копии базы данных и разных версий кода на случай, если всё поломается. А это происходит не так уж редко. Если что-то пошло не так, но у вас есть резервная копия, ничего страшного не случится. План восстановления - обязательный пункт для любого проекта.</li>
35 <li>Делать резервные копии базы данных и разных версий кода на случай, если всё поломается. А это происходит не так уж редко. Если что-то пошло не так, но у вас есть резервная копия, ничего страшного не случится. План восстановления - обязательный пункт для любого проекта.</li>
36 </ul><p><strong>Алексей Фирсов,</strong><strong></strong>руководитель Python-практики в компании<a>S7 TechLab</a></p>
36 </ul><p><strong>Алексей Фирсов,</strong><strong></strong>руководитель Python-практики в компании<a>S7 TechLab</a></p>
37 <p>Я работал в отделе биллинга одной известной компании. Одна из программ должна была подсчитывать бонусные проценты. Мы обсудили решение, и разработчик его реализовал. Но, выполняя свою задачу, он поправил один из модулей в старом коде и никому об этом не сказал. Поэтому тестировщики проверяли только новый код.</p>
37 <p>Я работал в отделе биллинга одной известной компании. Одна из программ должна была подсчитывать бонусные проценты. Мы обсудили решение, и разработчик его реализовал. Но, выполняя свою задачу, он поправил один из модулей в старом коде и никому об этом не сказал. Поэтому тестировщики проверяли только новый код.</p>
38 <p>Редактируя старый модуль, программист ошибся - использовал float. А его нельзя было использовать для подсчёта денег из-за плавающей точки. В результате модель стала начислять бонусы сверх нормы, компания понесла большие убытки. Виноваты оказались двое: разработчик, который никому не сказал о правках в старом коде, и руководитель, который недостаточно внимательно провёл ревью. Чтобы снизить риски появления таких багов, программистам неплохо бы писать, какую именно часть кода они меняют, чтобы QA могли протестировать все новые части программы.</p>
38 <p>Редактируя старый модуль, программист ошибся - использовал float. А его нельзя было использовать для подсчёта денег из-за плавающей точки. В результате модель стала начислять бонусы сверх нормы, компания понесла большие убытки. Виноваты оказались двое: разработчик, который никому не сказал о правках в старом коде, и руководитель, который недостаточно внимательно провёл ревью. Чтобы снизить риски появления таких багов, программистам неплохо бы писать, какую именно часть кода они меняют, чтобы QA могли протестировать все новые части программы.</p>
39 <p>Опасные баги возникают по двум основным причинам:</p>
39 <p>Опасные баги возникают по двум основным причинам:</p>
40 <ol><li>В базу попали данные, которые не должны туда попасть. Это происходит из-за плохо проведённого анализа: разработчик не понимает системы, того, как и какие именно данные в ней хранятся. Такие баги время от времени уходят в продакшн.</li>
40 <ol><li>В базу попали данные, которые не должны туда попасть. Это происходит из-за плохо проведённого анализа: разработчик не понимает системы, того, как и какие именно данные в ней хранятся. Такие баги время от времени уходят в продакшн.</li>
41 <li>Плохая коммуникация. Что-то изменилось на уровне одного отдела, а другой отдел этого не знает - и продолжает отрабатывать старые методы, которые утратили актуальность.</li>
41 <li>Плохая коммуникация. Что-то изменилось на уровне одного отдела, а другой отдел этого не знает - и продолжает отрабатывать старые методы, которые утратили актуальность.</li>
42 </ol><p>Ещё довольно распространённые, хотя и не такие критичные баги связаны с внезапными проблемами сети. Например, однажды отдел безопасности отключил доступ в интернет и не сказал об этом. В итоге в назначенное время у нас не запустился нужный сервис. Но такие баги быстро исправляются и их легко определить.</p>
42 </ol><p>Ещё довольно распространённые, хотя и не такие критичные баги связаны с внезапными проблемами сети. Например, однажды отдел безопасности отключил доступ в интернет и не сказал об этом. В итоге в назначенное время у нас не запустился нужный сервис. Но такие баги быстро исправляются и их легко определить.</p>
43 <p>Часто ошибки в системах возникают при интеграции. Они легко исправляются откатом или кодфиксом. Например, мы интегрировали свой сервис с платёжными системами, у которых нет тестовой среды. Поэтому код невозможно было проверить заранее, тестировали всё уже в продакшне. В таких случаях надо заранее продумать, как не пускать трафик в систему, пока ты её тестируешь.</p>
43 <p>Часто ошибки в системах возникают при интеграции. Они легко исправляются откатом или кодфиксом. Например, мы интегрировали свой сервис с платёжными системами, у которых нет тестовой среды. Поэтому код невозможно было проверить заранее, тестировали всё уже в продакшне. В таких случаях надо заранее продумать, как не пускать трафик в систему, пока ты её тестируешь.</p>
44 <p>Встречаются и архитектурные баги. Например, у меня в одном из проектов - стартапе без выделенного QA - был бот, который шёл по определённому сценарию. После каждого шага нужно было указывать следующий. Мы выкатили этот проект в продакшн, и оказалось, что сценарий ссылался сам на себя, - в итоге цикл замыкался до бесконечности. Естественно, всё упало.</p>
44 <p>Встречаются и архитектурные баги. Например, у меня в одном из проектов - стартапе без выделенного QA - был бот, который шёл по определённому сценарию. После каждого шага нужно было указывать следующий. Мы выкатили этот проект в продакшн, и оказалось, что сценарий ссылался сам на себя, - в итоге цикл замыкался до бесконечности. Естественно, всё упало.</p>
45 <p><strong>Александр Дученчук,</strong><strong></strong>геймификатор и Product Manager</p>
45 <p><strong>Александр Дученчук,</strong><strong></strong>геймификатор и Product Manager</p>
46 <p>Я был свидетелем забавной истории с пасхалкой от разработчика, которую не выпилили из кода. Это было нецензурное откровение про фаундера проекта с подробным описанием всех его ошибок и неправильных поступков. По мнению оставившего это послание разработчика, основатель стартапа плохо относился к команде и инвесторам, не умел выстраивать процессы.</p>
46 <p>Я был свидетелем забавной истории с пасхалкой от разработчика, которую не выпилили из кода. Это было нецензурное откровение про фаундера проекта с подробным описанием всех его ошибок и неправильных поступков. По мнению оставившего это послание разработчика, основатель стартапа плохо относился к команде и инвесторам, не умел выстраивать процессы.</p>
47 <p>Код вместе с этой пасхалкой отдали инвестфонду для оценки стартапа. Фонд провёл ревью и отказался вкладываться в проект, намекнув, что основателям надо внимательнее изучить свой код. Только тогда это послание и обнаружили.</p>
47 <p>Код вместе с этой пасхалкой отдали инвестфонду для оценки стартапа. Фонд провёл ревью и отказался вкладываться в проект, намекнув, что основателям надо внимательнее изучить свой код. Только тогда это послание и обнаружили.</p>
48 <p>Мораль простая: отдаёшь код на ревью, сначала проверь его сам.</p>
48 <p>Мораль простая: отдаёшь код на ревью, сначала проверь его сам.</p>
49 <ol><li>Применять сложные решения, когда есть простые.</li>
49 <ol><li>Применять сложные решения, когда есть простые.</li>
50 <li>Выдавать проект единым полотном, не дробя на логические блоки.</li>
50 <li>Выдавать проект единым полотном, не дробя на логические блоки.</li>
51 <li>Давать переменным непонятные имена.</li>
51 <li>Давать переменным непонятные имена.</li>
52 <li>Не проводить внутреннее код-ревью.</li>
52 <li>Не проводить внутреннее код-ревью.</li>
53 <li>Использовать нестандартную парадигму.</li>
53 <li>Использовать нестандартную парадигму.</li>
54 <li>Не обмениваться информацией со смежными отделами.</li>
54 <li>Не обмениваться информацией со смежными отделами.</li>
55 <li>Не писать чёткие и понятные комментарии.</li>
55 <li>Не писать чёткие и понятные комментарии.</li>
56 <li>Не сообщать об изменениях в коде QA и команде.</li>
56 <li>Не сообщать об изменениях в коде QA и команде.</li>
57 <li>Не делать резервных копий.</li>
57 <li>Не делать резервных копий.</li>
58 </ol><p>Хотите прокачать свои навыки в профессии, писать более чистый и красивый код и делать меньше ошибок? Пройдите курс "<a>DevOps-инженер PRO</a>". На этом курсе для джунов и мидлов вы освоите DevOps-практики и научитесь применять Docker и GitLab, чтобы оптимизировать и автоматизировать тестирование, доставку кода и запуск приложений на серверах.</p>
58 </ol><p>Хотите прокачать свои навыки в профессии, писать более чистый и красивый код и делать меньше ошибок? Пройдите курс "<a>DevOps-инженер PRO</a>". На этом курсе для джунов и мидлов вы освоите DevOps-практики и научитесь применять Docker и GitLab, чтобы оптимизировать и автоматизировать тестирование, доставку кода и запуск приложений на серверах.</p>
59 <a>Научитесь: Профессия DevOps-инженер Узнать больше</a>
59 <a>Научитесь: Профессия DevOps-инженер Узнать больше</a>