Как стать автором
Обновить

6 правил, которые пригодились бы мне, когда я осваивал программирование

Время на прочтение5 мин
Количество просмотров35K
Всего голосов 52: ↑45 и ↓7+38
Комментарии51

Комментарии 51

Код пишется для читателя. Себя, спустя пол-года, или другого программиста. Все, кто всего лишь "решает задачу" с помощью кода обречены на страдания при его чтении.

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

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

Если код понятный, но неправильный, его с лёгкостью поправят.

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

Именно это автор и описывал - код должен решать задачу.

Для кого он должен решить задачу? Если для вас самого (найти всё и поправить) - ок, ок. Если же вы этот код сохраните в git, то утверждение о том, что это "разовый скрипт" во-первых противоречит концепции коммита, во-вторых является предсказанием будущего о том, чего его потом никто не будет редактировать.

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

"Сохранить код в git" - это может быть частью задачи, а может и не быть.

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

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

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

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

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

Но непонятность про которую я говорю, она проще. Допустим, у вас есть функция, которая оный эйгенвектор вычисляет. Вы можете её заинлайнить (физически) с использованием переменных, похожих на имена перменных в учебнике линейной алгебры Aij, k_ij.

Вот кусок откуда-то из интернетов:

        for l in range(k + 1, n - 1):

            A[(l + 1) :, l] = (
                A[(l + 1) :, l] - v[l] * z[(l + 1) :] - v[(l + 1) :] * z[l]
            )
            A[l, (l + 1) :] = A[(l + 1) :, l]
            A[l, l] = A[l, l] - 2 * v[l] * z[l]

А можете написать:

eigenvectors = calculate_eigenvectors(...)

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

И вот если у вас 300 строк вот такой ахинеи как сверху, без названий и объяснений, то даже если оно работает, то этот код принесёт больше несчастий, чем если бы у вас была багованная версия с eigenvectors = calculate_eigenvectors(...)

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

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

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

Да, пожалуйста, пожалуйста, пишите сколько хотите. Просто следующему человеку больно будет.

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

Если вы не используете функцию больше 1 раза, не делайте ее. Хороший коммент > раздутой переменной.

Строго наоборот. Комментарии гниют, код не гниёт (потому что он и есть своя документация).

Например, в обработке метрик очень часто можно увидеть что-то такое:

return (foo.request('/metrics').json()["metrics"][0][0]).values()[0]  # any

Сравните с:

metrics = foo.request('/metrics').json()["metrics"]
master_metrics = metrics[0]
self_metrics = master_metrics[0]
redundant_probes = self.metrics.values()
return redundant_probes[0]

Во втором даже комментарий не нужен, и вы можете примерно представить себе, что в этом json'е лежит. Первое.. ну, [0][0].values()[0] - всё ж понятно!

Если вы не используете функцию больше 1 раза, не делайте ее.
Спорный момент. Добавление «одноразовых» функций может улучшить читаемость. Что-то вроде
public void MoveToDifferentAddress(oldAddress, newAddress, qty)
{
    this.reduceQty(oldAddress, qty);
    this.increaseQty(newAddress, qty);
    this.recalculateTotal();
}

private void reduceQty(address, qty)
{
}

private void increaseQty(address, qty)
{
}

private void recalculateTotal()
{
}

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

Код пишется для читателя. Себя, спустя пол-года, или другого программиста. Все, кто всего лишь "решает задачу" с помощью кода обречены на страдания при его чтении.

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

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

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

Бывают крайние задачи оптимизации tight loop, но их - ничтожное количество. Алгоритмические оптимизации обычно оказываются важнее языковых (сравните o(1) на бейсике с o(n) на ассемблере), а понятность написанного важнее, чем то, что получит процессор. Потому что мы точно знаем что нужно процессору и можем легко проверить, что он получает то, что нужно, а вот проверить, что мы написали понятно мы можем с большим трудом и только ретроспективно.

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

Взгляните на это со стороны заказчика или пользователя - если программа тормозит и некорректно работает, то оправдание - "зато код понятно написан" вы считаете адекватным?

Алгоритмические оптимизации обычно оказываются важнее языковых (сравните o(1) на бейсике с o(n) на ассемблере)

Оптимизации с учетом использования кешей процессора и правильного обращения к памяти на практике обычно оказываются еще важнее, так как эти O(x) оценки лишь асимптотические.

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

Легенда про "заказчика" которому один раз написали программу и забыли - это что-то из времён раннего внедрения. Внедрили office 95, и вот, в 2021 оно работает.

Реалистично софт надо поддерживать: адаптировать под новые стандарты и требования бизнеса. Если вам отгрузили in-house софт, который другая компания или свои программисты не могут адаптировать, потому что не понимают, это мёртвая программа. Легендарный "легаси аппликейшн", с которым все борятся.

Продажный же софт (как коробки так и saas'ы) в первую очередь должен быть адекватно сопровождаем, потому что будут постоянные подстройки под рынок.

Повторю, подход "отлили в бронзе и не трогаем" работает крайне редко, в основном в районе махрового эмбедда.

Насчёт кешей в борьбе между o(1) и o(n) вы меня реально рассмешили. Я хотел написать живой пример, но, боже, оптимизация обращений памяти как замена перевода алгоритма с o(n) на o(1)...

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

Насчёт кешей в борьбе между o(1) и o(n) вы меня реально рассмешили. Я хотел написать живой пример, но, боже, оптимизация обращений памяти как замена перевода алгоритма с o(n) на o(1)

Может в данном случае, это не лучший пример, но ничего прям смешного я тут не вижу. Может быть вообще такое, что подобной оптимизацией вы только сделаете хуже. Например, вы решили поменять обычный массив o(n) на хеш таблицу o(1). Но обращение к данным у вас в программе идет последовательно с множеством попаданий в кеш. Теперь получается, что большинство обращений будут cache miss, так как обращение к данным в хеш таблице уже не последовательно. В итоге производительность может упасть в 10-100 раз и это не покроет разницу в асимптотическом выигрыше. Это просто пример того, что не все так однозначно.

Почему странно? Например, любой компилятор/интерпретатор - вполне себе довольно требовательный читатель, который потом правильно сообщит процессору что надо делать. Гораздо удобней, если код понимает не только компилятор/интерпретатор, а и программист (не обязательно автор), который с этим кодом в данный момент работает.

Это очевидно, но это можно и опустить. Никому не нужны программы, которые не компилируются, очевидно, что они не считаются программами.


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

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

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

Если код понятный, но неправильный, его с лёгкостью поправят.

Если бы. Есть целый пласт плавающих багов, где код понятен, но поиск ошибки с "легкостью" растягивается на несколько месяцев.

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

Yep, but... если понятный код работает не так, как вы его себе представляете, то для вас это непонятный код и любые изменения, не приводящие к его исправлению, это "авось, сработает". Это примерно то, о чем и говорит автор.

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

  • 20 часов?

  • Качественно и с тестами?

  • Да

  • Ок, вперед. (Или если во время не укладываемся) Ладно выпустим в следующем релизе.

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

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

Может, все же дело не в том КАК вы учили, а в том, ЧТО?

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

А нет такого же, но про Python? Будем искать..

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

З.Ы. говорю за кровавый энтерпрайз-бекенд. Что там у веб-студий на пхп/питоне не представляю.

Вы производите примерные вычисления и говорите: «Мне нужно двадцать часов».

Продакт-менеджер недоволен вашим ответом. Поэтому он спрашивает: «Справитесь за десять часов? Нам очень нужна эта фича к следующему релизу продукта!»

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


А теперь правильный ответ:
Вы производите примерные вычисления, добавляете немного на случай непредвиденных ситуаций (~25%), делаете поправку на любителей торговаться (100%) и говорите: «Мне нужно пятьдесят часов».

воистину

Я обычно утраиваю. Ну тупо потому, что знаю себя, и знаю что а) склонен выдавать оптимистичные оценки б) склонен не учитывать другие работы, как-то тестирование, документирование и т.п., т.е. выдаю оценку своей работы, тогда как нужна как правило общая. Ну и потом, практика показывает, что непредвиденные ситуации могут отъесть сколько угодно, поэтому 25% на них — это тоже оптимистично.

При этом есть еще и такой «лайфхак», если угодно — если вы оценили работу в 50 часов, то и промазать с оценкой вы можете примерно на те же 50 часов (а это, между прочим, больше недели, потому что неделя это обычно 40). Чтобы оценить работу более-менее точно, нужно ее декомпозировать на мелкие куски, потому что точность оценки при этом повышается. Ну а итоговые оценки порядка 40 часов и более стоит уже перевести в дни, с учетом праздников, отпусков и прочего. В общем, навыки оценки трудозатрат и сроков — это даже не софт скиллы, а совсем отдельное искусство, которому тоже нужно учиться (но мало где учат).
Только сегодня в ФБ прочитал:
На одном из самых прекрасных собеседований мне задали кейс: представь, говорят, что тебе программисты посчитали фичу, вышло две недели. Сейчас допустим 1-ое декабря. Сколько времени займёт реализация?
— Год, — говорю.
Удивились. Как год? Почему год? А хрен знает. Интуитивно. Ну в общем походили мы вдоль да около этого года, повертели так и сяк, потом я в свою очередь переспрашиваю:
— Ну признайтесь, — говорю, — это же у вас реальный кейс из проекта. Сколько в реальности заняло внедрение?
— 14 с половиной месяцев, — отвечают.
— Точняк! — Хлопаю себя по лбу. — Деплой на продакшен забыл посчитать!
Источник: www.facebook.com/dobryakov/posts/5245952098800255

Почему год? А хрен знает. Интуитивно. 

И

Деплой на продакшен забыл посчитать!

== умение переобуваться в прыжке :)

Меганавык для социальных скиллов ;-)

НЛО прилетело и опубликовало эту надпись здесь
Ага. И кстати знаете что, там же:

>люди, на которых я подписался (и считал их 10X-инженерами) на самом деле знают не очень многое.
При этом эти люди умеют решать задачи, которые тому кто умеет «выравнивать по вертикали» просто недоступны. То есть, знания CSS для их решения недостаточно совсем, и производительность этих людей на таких задачах будет просто несравнима — на порядки выше.

А где главная тайна? Уметь воровать код Уметь читать 'маны' и искать решения для похожих задач? 99% с чем сталкиваешься кто то когда то делал, сложнее всего найти где он/она это делал и когда. 1% значит тебе повезло ты напишешь что то новое.

вся команда потеряет дополнительно тридцать часов на этот рефакторинг

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

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

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

Это я так, чтобы какое-то непопулярное мнение тоже озвучить и минусов собрать.

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

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

Не согласен. Сошлюсь на свой опыт: примерно 20 лет назад (понимаю, что с той поры JS изменился и усложнился) учил JS дома. Сидел в удобном кресле, прихлебывал горячий чай, читал учебник (уже не помню автора). Периодически возникало желание посмотреть, как работает очередной пример. Тогда я вставал и садился за ПК. ИМХО очень комфортно. И продуктивно: я у себя на home page карточный пасьянс и еще несколько игрушек сделал через две недели такого изучения JS.

PS ИМХО важнейшее и универсальное правило при изучении всего (от ЯП до матана): найти для себя способ расслабляться. Нужно сказать себе, что за мной никто не гонится с палками, арбалетами и винтовками. Что если я не понял очередной абзац, то меня не поставят к стенке. Удобное кресло способствует расслаблению, но друзья говорили, что для расслабляться лезут в душ. Кто-то садится за ПК машинки погонять или пострелять инопланетных захватчиков. Бывает, что минут через 10- 40 понимание непонятого абзаца само приходит. Этому объяснение — подсознание. Но стоит подумать: важен ли этот абзац? — Авторы, даже, очень хороших учебников не идеальны.

НЛО прилетело и опубликовало эту надпись здесь

Программирование — это не про кодинг. Программирование — это о решении задач при помощи кодинга.

Жаль, что очень многие этого не понимают

По-моему статья неправильно названа, там пропущено слово "коммерческое".

Когда я (да и, думаю, многие) осваивал программирование, имея в распоряжении листок бумаги и раз в неделю, на 5-10 минут, доступ к микрокалькулятору где я мог проверить работу написанной программы - для меня главным был именно кодинг, а не всё что написано в статье.

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

Когда я, доделывая демо к Funtop'98, провёл за компом трое суток с редкими перерывами на час-два сна и изредка на еду - я бы как минимум рассмеялся в лицо человеку, который бы предложил мне делать перерывы каждые полчаса.

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

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

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

Короче хобби для души, а на работе деньги зарабатывают. И желательно, чтобы не ценой здоровья.

Да, обзавёлся и начал продавать свой труд за деньги.

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

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

Зачем менять чьи то коды, если умеешь печатать свои. У каждого кодера/программера своя методика составления алгоритмов, синтаксиса.

  1. Место в банке памяти,

  2. Количество решаемых задач,

  3. Скорость работы приложения

Отвечаю на вопрос выше. Программирование это составление программы (плана, последовательности), как правило на компьютере.

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

Довольно простые и банальные истины. Но как часто бывает, чем проще - тем лучше. Спасибо автору!

Зарегистрируйтесь на Хабре, чтобы оставить комментарий