Как все мы знаем, привычки определяют нашу жизнь. Тому, кто хочет вырасти над собой в сфере программирования, нужно попытаться сформировать у себя соответствующие привычки.
Предлагаю поговорить о шести привычках, которые стоит постараться сформировать у себя тому, кто хочет выделяться из серой толпы.
1. Наводите порядок в коде, с которым работаете
Любому программисту полезно сформировать у себя привычку улучшать код, который ему когда-либо приходится менять. При этом неважно, идёт ли речь об исправлении единственной строки кода, или о добавлении в существующий проект целой новой подсистемы.
Роберт Мартин высказал одну ценную идею по этому поводу. Он называет это «правилом бойскаута». Звучит это так: «Всегда оставляйте код, который вы редактируете, в более чистом состоянии, чем он был до вас».
Вы будете поражены тем, как много всяких мелочей вы можете улучшить, когда просто читаете какой-то код. Изменения, которые вы вносите в код, могут быть весьма незначительными — вроде переименования переменной или функции. Просто старайтесь всегда, когда это возможно, улучшить хоть что-то. В результате код после вас будет выглядеть лучше, в нём будет меньше явных проблем.
Эту привычку крайне полезно иметь из-за того, что она означает постоянное обучение. То, что мы считали хорошим вчера, уже сегодня можно улучшить, переделав это каким-то новым, более удачным, способом. Со временем код имеет свойство «портиться», поэтому забота о коде чрезвычайно важна для сохранения его в таком состоянии, в котором его удобно поддерживать.
2. Заботьтесь о тех, кто будет работать с вашим кодом после вас
Когда бы вы ни писали фрагмент кода, вам следует думать о том, что увидит кто-то другой, взглянувший на этот код.
Пишите код, настроившись на то, чтобы он получился бы читабельным, чтобы его было бы легко понять. Соотношение времени, которое уходит на чтение и на создание кода — это значительно больше, чем 10 к 1. Это значит, что вы, в долгосрочной перспективе, можете сэкономить массу человеко-часов, просто прилагая больше усилий к тому, чтобы писать читабельный код.
Программируя, не стремитесь ко всяческим «выкрутасам». Пишите простой код, который будет понятен любому, кто станет его читать. Согласитесь, обычно нет реальной необходимости пользоваться таинственными однострочниками, скопированными со Stack Overflow, которые вы и сами толком не понимаете.
3. Делайте то, что нужно, но не более того
У разработчиков встречается своеобразная привычка к ненужному усложнению и расширению того, чем они занимаются. Большинство разработчиков, сталкиваясь с задачей по реализации некоей возможности, сделают, «на всякий случай», что-то сверх того, что должны.
Это то, что называют «оверинжинирингом» — «искусством перебарщивания». Код делают более надёжным или более сложным, чем нужно. Оверинжиниринг — это то, у стремления к чему нет ни одной веской причины.
Чаще всего в основе причин, по которым разработчики создают более сложные программы, чем требуется, лежат догадки. Например, разработчик может добавить в проект код, который, возможно, может оказаться полезным в будущем. Делается это только на основании предположений данного разработчика. Этот дополнительный код попадает в кодовую базу проекта, но он, вполне возможно, так никогда никому и не пригодится.
Оверинжиниринг может привести к появлению кода, который спроектирован в настолько общем виде, что в нём будут потеряны признаки основной задачи, для выполнения которой он был изначально предназначен. В результате таким кодом не только будет сложно пользоваться. Такой код будет ещё и очень непонятным.
4. Планируйте работу над кодом
Настоящие программисты любят заниматься одним и только одним делом: программированием. Вас не должно это удивлять. Учитывая это, очевидно то, что большинство программистов, когда им дают задание, тут же принимаются за своё любимое дело. Они сразу же начинают писать код.
Поначалу идея уйти в код с головой может показаться восхитительной. Но за это «восхищение», вполне возможно, придётся платить временем. Когда программист, без раздумий, бросается писать код, он, в итоге, перестаёт видеть общую картину.
Прежде чем начинать писать программу, нужно всё спланировать и организовать. Стоит подумать о сложностях, которые могут встретиться на пути, и о том, как их решать. Полезно поразмыслить о структурировании кода, о том, почему планируется реализовать ту или иную возможность проекта.
Всё это — отличные вопросы, которыми стоит задаться до начала работы над кодом. Эти вопросы дадут вам возможность осознать то, что перед тем, как писать код, можно и нужно о многом поразмыслить.
5. Документируйте свои проекты
Знаю — документирование кода — не самая привлекательная привычка в этом списке. Но это — очень и очень хорошая привычка. Писать документацию — это очень важно.
Попадался ли вам когда-нибудь репозиторий, в котором нет никаких сведений о том, как всё правильно настроить, или о том, как должно работать приложение, находящееся в этом репозитории?
После того, как вы проведёте пару часов, читая код, хранящийся в таком репозитории, велика вероятность того, что вы ни в чём так и не разберётесь. Вот тогда-то вы и ощутите ценность документации.
Абсолютный минимум документации, которым я порекомендовал бы оснащать любой проект, это адекватный файл
readme.md
, в котором рассказывается о том, для чего предназначен этот проект, и о том, как его правильно настроить и запустить.В сфере документирования программных проектов есть одно замечательное явление. Оно заключается в возможности документирования кода в процессе его написания. Дайте себе некоторое время на то, чтобы придумать описательные имена переменных. Это себя окупит. Выбор хороших имён для переменных, методов и классов требует времени. Но хорошие имена позволят сэкономить больше времени, чем нужно на их выдумывание.
Если вас интересует вопрос подбора осмысленных имён для различных сущностей — взгляните на этот материал.
6. Никогда не прекращайте учиться
Айзек Азимов сказал: «День, когда вы перестанете учиться, это день, когда вы начнёте деградировать». Эти слова особенно справедливы для мира компьютерных технологий, в котором всё меняется очень быстро.
Невозможно поспеть за всем, что меняется, и даже если кто-то на такое способен, я не советовал бы к этому стремиться. Не стоит доводить подобное стремление до крайности, но полезно время от времени осваивать новый фреймворк или язык программирования.
Это не значит, что необходимо становиться экспертом во всех таких фреймворках или языках. Полезно экспериментировать с чем-то новым для того чтобы узнать, нравится ли это вам.
Изучая новое, программист видит, как различные задачи решаются с помощью инструментов, о которых он раньше не знал. Это помогает ему профессионально расти.
Итоги
Тот, кто стремится к тому, чтобы стать выдающимся программистом, может идти к этой цели, развивая у себя множество различных привычек. Мы здесь разобрали шесть привычек, которых нет у большинства разработчиков.
Вот приведённые здесь советы, касающиеся формирования полезных программистских привычек:
- Наводите порядок в коде, с которым работаете.
- Заботьтесь о тех, кто будет работать с вашим кодом после вас.
- Делайте то, что нужно, но не более того.
- Планируйте работу над кодом.
- Документируйте свои проекты.
- Никогда не прекращайте учиться.
Постарайтесь развить у себя эти привычки. Не спешите, развивайте их у себя постепенно, по одной. Помните о том, что за один день вам ими не обзавестись. Для того чтобы развить привычки, нужно время и постоянство.
Какие привычки хороших программистов вы добавили бы к тем, о которых шла речь в этой статье?
berez
Сомнительный совет.
Любая правка — это автоматически ненулевой шанс внести ошибку. Люди, знаете ли, не автоматы, и довольно часто ошибаются в простых казалось бы вещах.
А то, что затронутый код не нужен для решения вашей текущей задачи, автоматически означает, что и тестировать его вы вряд ли будете так же качественно, как основные правки. И вот тут — внимание, большой вопрос: стоит ли заниматься таким «улучшайзингом» в системе, если от нее зависит прибыль всей конторы (или жизни людей, или и то, и другое)?
LunaticRL
Ну, если не учитывать конкретную ситуацию и здравый смысл, то в принципе любой совет можно назвать сомнительным при определенных условиях. Но это не значит что совет плох.
Разумеется, заниматься «улучшайзингом» стоит с учетом покрытия тестами, зоны ответсвенности, и того, насколько код горячий, либо грешит неочевидными последствиями
v1000
Классика
Iqorek
Поспорю, это прекрасный совет. По моим наблюдениям основная причина багов, это то, что программист не совсем понимает код, вторая причина — невнимательность, вследствие усталости. Баги от рефакторинга, это большая редкость, ну если вы не рефакторите вручную конечно.
Сам процесс рефакторинга очень помогает разобраться в деталях, ведь что бы все пересобрать «как надо» и очистить, нужно понять, как оно вообще работает.
Далее, пересобранный и очищенный код легче понять, следовательно в нем меньше багов, его легче поддерживать и вносить изменения.
Ну если такой код не покрыт тестами на 1000%, то это как с бэкапами, «люди делятся на 2 типа, на тех кто еще не делает бэкап...» и так далее.
edogs
Тому кто рефакторит — безусловно помогает. Т.к. рефакторинг даже будучи сделанный по гайд-лайнам, все равно несет в себе индивидуальный отпечаток.
Помогает и новичкам, при условии что после рефакторинга код действительно стал именно лучше, а не просто стал другим — такое тоже бывает.
А вот старой команде, которой был привычен старый код — необходимость разбираться в новом, пусть и более качественном коде, не обязательно поможет.
Тут немного есть ассоциация с анекдотом, где мысль в том, что жена прибралась в гараже у мужа и теперь он ничего не может найти.
Ни разу не видели код покрытый тестами хотя бы на 80%.
Как по нам с рефакторингом ситуация простая — «работает — не трогай»©
Просто «для искусства» можно рефакторить свои пет-проекты на досуге, благо это процесс бесконечный, как ремонт.
AnthonyMikh
В SQLite 100% branch coverage. Правда, на практике это не особо помогает.
lumini
Думаю, тут имелась в виду коммерческая разработка. Все компании на собеседованиях говорят, что «да, конечно, мы юнит-тесты практикуем». На деле тестами покрыт максимум самые мишшн-критикал куски кода, которые, внимание, редко меняются. Так как в них зашита логика базовых бизнес-процессов компании, которые, понятно, не могут резко поменяться. А править нужно ту самую утилиту, написанную два года назад в спешке, что всё это время отлично работала и вдруг сломалась — и такие места обычно имеют ровно 0% code coverage.
Жизнь…
VolCh
Есть хорошая привычка: при фиксе любого бага сначала воспроизвести его с помощью теста, а потом фиксить.
AnthonyMikh
В этой ветке остро не хватает Дедфуда.
smind
Я из тех кто раньше делал бакабы теперь в коробках дежат cd, dvd, mini-dv кассеты (а ведь их перематывать надо) hdd от 100мб до 1гб, теперь уже и не подключить часть из них ide.
Короче я перестал делать бакапы их невозможно хранить, т.е. носители отмирают слишком быстро.
Все что мне нужно или на гугл-фото или на гитхабе, остальное вероятно никому-никогда не понадобится.
edogs
Даже сейчас — mini-dv кассету — на автомате можно слить, поставил оно качается, в зависимости от камеры можно даже 4х скорость сделать. Да, менять руками придется. А h264/h265 ужмет некисло и быстро на современном железе.
cd/dvd до сих пор живы, даже ноуты с ними можно найти.
Для ide устройств продаются недорогие usb адаптеры, тоже не проблема.
У нас была куча фоток сделанных еще хз когда, когда много ходили с фотиком и снимали все подряд. Думали уже — никто никогда все это не разберет и на фиг надо.
Ан нет.
Благодаря относительно недавнему появлению качественного софта по сортировке и объемным современным дискам — удалось загнать всё на пару хдд и большУю часть разложить по датам (данные с exif или имя файла там где оно не dsc000), людям (распознавание лиц), географии съемки (снятые объекты + привязка по времени соседних фоток) и заодно избавиться от некачественных дублей на автомате (там где снимаешь серию, но 9 из 10 со смазом).
Некоторые вещи которые уже и забыли что они где-то есть — неожиданно и приятно всплыли.
alekciy
А что за софт?
PendalFF
Присоединяюсь, название софта в студию, пожалуйста)
vchslv13
+1 к просьбе подсказать имя софта :)
bondarenkod
А что за софт? На каком-то NAS?
alekciy
Особенно интересна тема распознавания лиц. Из того софта что я лично переюзал на линухе осталось в целом неудовлетворительное ощющение. Потому что вроде нормально, но начинаешь использовать и начинается: то одной фичи нет, то другой, то интерфейс отвратный.
DesolatoR
тоже интересно, что за софт такой ) такая же проблема назрела
alekciy
Все прекрасно делается. Поднимите RAID-1 хотя бы на террабайтниках и пишите туда.
lobotomic
Согласен с тем, что это — сомнительный совет. Но в основном не из-за ошибок. Если уж вы рефакторите кусок кода, то либо он уже покрыт тестами, либо это ваша обязанность перед рефакторингом.
Но сомнительный он из-за возможных изменений в тех частях кода, которые не связаны с вашей текущей задачей. Это вносит большую неразбериху в систему контроля версий. Тот, кто после вас будет разбираться с тем, как вы решили задачу, увидит, например, что вы изменили 10 файлов вместо одного, в котором содержался баг. Как ему найти собственно исправление бага?
edogs
kloppspb
Нет, две ветки. Практически во всех проектах, с которыми имел дело, было так, даже если нужно отформатировать какое-то legacy в соответствии с coding style, приструнить случайно затесавшиеся табы или убрать виндовые переводы строк. И только после код ревью, тестов и влияния первого в мастер — новые правки.
vep
Это был ритуал? Или какое-то обоснование такой практике озвучивали?
powerman
Обоснование очевидно любому, кто делает ревью таким PR.
lumini
Да, ревью кода, где намешаны изменения логики работы и рефакторинг — это ад. Visual Studio с ее предложениями изменения синтаксиса в С# особенно прекрасна. Смотришь мёрж реквест, вникаешь в изменения и тут бац, заменённый синтаксис case на новый модный в двадцати файлах проекта. Посылаешь лучи добра автору кода.
У нас, например, есть четкое правило: заметил говнокод — заводи отдельный таск в джире с типом «рефакторинг» и делай все изменения в его ветке. Если позволяет время спринта, он вносится асапом и выполняется до таска с изменениями логики. Если нет — ну сорян, надо работать с тем, что есть, а рефакторить после (зависит от критичности таска, конечно).
MaxKot
А если исправление маленькое? Завести задачу, завести ветку, а потом ещё раз описать изменение в коммите — звучит чересчур громоздко для, например, исправления опечатки в имени переменной. Не получается ли в результате, что на мелкие исправления просто забивают? Или "протаскивают" их в несвязанных по смыслу коммитах, за что потом шлются лучи добра?
lumini
Если переменная используется в пределах одного метода, то да, разумеется заводить багу отдельную никто не будет. Но если например ошибка в имени класса, который используется в десятках других классов, то даже только ради удобства ревью я бы предпочел это видеть отдельной задачей. А вдруг эту самую библиотеку, в которой делаются правки, кто-то импортит из другого проекта и в следующий импорт код внезапно сломается.
Или, скажем, мы видим очепятку на сайте, вносим никому не сказав правки. В том числе не предупредив людей, отвечающих за контент сайта. В следующий раз они пришлют правки текстов снова с этой очепяткой и другой программист тупо заменит пофиксенные тексты на сайте на пришедшие с оставшейся в них опечаткой.
Общая идея, что с одной стороны бюрократия — зло, но с другой лично у меня заведение типовой задачи в джире + сделать ветку в гитхаб десктоп занимает ну секунд 30 времени. Зато потом всем проще.
khim
Хороший пример того, как простая опечатка правилась несколько лет: в libxml кто-то завёл поле childs в структуре. Ну не слишком хорошо знаком разработчик знает английский.
Проблема в том, что вся эта библиотека, сверху донизу и снизу доверху — построена вокруг работы с этой структурой. Банальная правка привелабы к тому, что перестали бы собираться тысячи программ у десятков тысяч разработчиков…
В результате переименования
childs
вchildren
пришлось ждать несколько лет — до выхода версии libxml 2.vep
В чём принципиальная разница между отдельной веткой и отдельным комитом со стилевыми правками в фича-ветке? При ревью можно же взглянуть на правки конкретных комитов.
powerman
Если коммитов в ветке два — на первый взгляд никакой, их действительно несложно посмотреть отдельно. Но первая проблема в том, что их почти никогда не два — дальше начинаются правки по замечаниям ревью и количество коммитов растёт, а вторая в том, что на ревью замечания пишутся на весь PR, т.е. на ветку, а не на коммит. Аппрув ставить и мержить так же имеет смысл раздельно рефакторинг и изменения функционала.
TheGodfather
Правки по замечаниям ревью обычно амендятся в тот коммит, к которому они относятся, итого было 2 коммита в первой версии PR — осталось два коммита в финальной версии PR. Разных коммита, ну да.
Тут зависит от того, как процесс построен. Если команда понимает и обсудила workflow, то проблем никаких. И да, я определенно согласен с автором комментария, что заводить отдельную(!) таску(!!) в джире(!!!) на рефакторинг, который может быть произведен «на лету» без последствий (и когда время, затраченное на, собственно, рефакторинг, много меньше времени, затраченного на создание тасок, лишней ветки, времени ревьюверов) — это какой-то оверкилл.
В то же время, если рефакторинг затрагивает внешнее API, или затрагивает сотню файлов проекта, или это не тупое переименование переменных а именно смысловое написание кода, то в этом случае, конечно, отдельная таска и планирование имеют место быть.
powerman
Это требует несколько большей аккуратности от разработчиков, чем в большинстве команд реально добиться. Я пришёл к тому, что разрешаю в своей команде коммиты в PR делать сколько и как им угодно, но при мерже этот PR squash-ится с корректным (по conventional commits) сообщением. Это даёт и чистую историю, и не перегружает команду формальными требованиями к процессу.
Кроме того, мы не практикуем никакое переписывание истории после git push, а ревью определённо начинается уже после git push.
TheGodfather
Ок, понятно. У нас в команде наоборот — у нас был Gerrit еще год-полтора назад, поэтому привычка «писать нормальные коммиты и сообщения коммитов» у всех есть, во время Геррита за кривые коммиты по рукам били и не аппрувили ревью :). И с переездом на Gitlab она не изменилась, посему и merge policy у нас — rebase-only, fast-forward, no squash, no merge commit. Т.е. если автор PR сам хочет, он, конечно же, может засквошить свои коммиты при мерже, но обычно все вливается «как есть». И да, force push в своих ветках (где разработчик один работает) — абсолютно нормальное и каждодневное явление, поддерживает чистую историю на протяжении всей жизни PR/бранча.
lobotomic
Так мы в конце концов и договорились делать в команде.
tongohiti
Никто не призывает рефакторить вообще везде (см. совет про перебарщивание). Выносите рефакторинг отдельным PR, если там много изменений. А совет отличный.
Jogger
Мне в связи с этим вспоминается комментарий в одном changelog'е (слава богу, я на том проекте не работал) — «версия законченная, но неработоспособная». Так и тут — код чистый и хороший, но не работает.
vlti
Читайте совет полностью. Он предлагает улучшить код, например, в том же классе, в который вы вносите правки. А не переделывать всё подряд под себя, потому что не нравится.
А если совсем не заниматься «улучшайзингом», то система в скором времени скатится в «Big ball of mud» — для чего есть очевидные предпосылки — первоначальный дизайн никогда не удовлетворит все будущие требования.
berez
Читайте комментарий полностью. Я нигде не утверждаю, что «улучшайзингом» надо заниматься сразу по всей кодовой базе.
Читайте комментарий полностью. Я нигде не утверждаю, что «улучшайзингом» вообще не надо заниматься.
TL;DR: Я утверждаю, что смешивать рабочий код с «улучшайзингом» соседнего кода — плохо.
Совет плох из-за того, что предлагает смешать два различных вида деятельности в один. Это вносит неразбериху в систему контроля версий: вместе с кодом задачи программист коммитит и не относящиеся к задаче правки. В результате найти концы («кто добавил эту логику?») становится затруднительно: git annotate покажет не автора, а «я только табы подправил».
Ну и про недостаточно тщательное тестирование правок в «не своем» коде я уже писал. «Собирается — и ладно, что там может сломаться?». Автотесты — это прекрасно, но далеко не везде они покрывают 100% кода (а в большинстве проектов, которые я видел, они вообще покрывают произвольно выбранные клочки кода — то, что автор посчитал «сложным кодом»).
Посему во многих проектах такая деятельность прямо запрещена гайдами. Для рефакторинга — отдельная таска. Обнаружил ошибочный код при решении своей задачи? Если он не входит в область видимости задачи — создавай отдельную таску. А мешать — не надо.
vlti
Согласен, что закладывать совместно и решение задачи, и что-то слабо относящееся к задаче в одном коммите это вносит неразбериху. (Хотя если следовали Single Responsibility — код в одном классе будет всё-таки связан с задачей или багом. А если не следовали, то фикс для бага — хороший повод провести улучшение кода — всё равно придётся анализировать код в процессе фикса.)
И тут, конечно, могут быть свои стайл гайды — вплоть до отдельной таски или отдельной ветки. Но всё это не нарушает совет — главное оставить код лучше, чем он был — хоть немного.
ncr
Я видел проект, несколько лет разрабатываемый по принципу «работает — не трожь» или «патч должен быть минимальным».
— Код встречается в 20 разных местах? Нет, в функцию выносить не надо, правь все 20 мест как есть.
— Надо добавить параметр в функцию? Дай ему значение по умолчанию, чтобы не править все вызовы, даже если оно там бессмысленно.
— Код зависит от глобальных переменных? Нет, не надо ничего переделывать, просто добавь еще одну. Тестов у нас все равно нет.
— Что-то больше не используется? Ну и что, пусть будет. В крайнем случае закомментируй.
И так далее и тому подобное, повторенное многократно.
В результате получается прекрасная, компактная история в контроле версий, где все по делу.
Правда, непосредственно код при этом почему-то превращается в спагетти, правка багов требует медитации и телепатических способностей, а от предложений новых фич случается нервный смех и дергается глаз.
sumanai
Битрикс так больше десяти лет разрабатывается, и при этом коммерчески успешен. Работать с ним правда невозможно.
TheGodfather
В целом полностью согласен с вами, но не могли бы вы развернуть конкретный пункт?
Понятно, что через несколько итераций имеет смысл пересмотреть и, быть может, переписать функцию, но конкретно сейчас «ага, вот у нас есть функция, нам надо добавить выбор формата, допустим. Добавим параметром, по умолчанию оставим текущее поведение» — я в упор не вижу проблемы, что не так? Если условный параметр на самом деле принадлежит этой функции, то почему бы и нет?
Kanut
Не так там последняя часть. А именно «даже если оно там бессмысленно».
shamash
зачастую пишется, черновой алгоритм в виде одной большой процедуры, а переложить его в функции при повторении, людям уже лень. А потом ты смотришь на процедуру в 1000 строк, которая делает 19 вариантов, одного и того же действия. И не можешь ничего с ней делать, поскольку проще ее переписать, чем если бы изначально человек после выполнения, первого варианта вынес действие в функцию. Это базовый пример.
puyol_dev2
Золотое правило сисадминов, но и программистов — работает, не трогай! «Улучшательство» ради «улучшательства» может привести к ошибкам во всей системе. И выставлению санкций «улучшателю» само собой
Kanut
Какая-то странная аргументация. Любое изменение может привести к ошибкам. Так что теперь код вообще не трогать?