Я программирую уже более 30 лет. И мой путь в программировании тянется от микропроцессоров Z80 и 6502 до современных машин, от таких языков программирования как BASIC, assymbly, C, C++ до Tcl, Perl, Lisp, ML, occam или arc, Ruby, Go и проч.
Вот список того, что я постиг в программировании:
0. Программирование удел ремесленника, а не ученого или инженера
Программирование больше походит на ремесло нежели на науку или инженерную дисциплину. Это комбинация навыков и опыта выраженная в умении применять инструменты. Ремесленник выбирает необходимые инструменты(а если требуется, то создает свои) и учиться применять их.
По мне так это ремесло. Я считаю, что лучшие программисты ближе скорее к часовщикам нежели к строителям мостов или физикам. Конечно, с виду это занятие напоминает науку или инженерное дело всилу использования логики и математики, но в большинстве случаев ты просто берешь инструменты в руки и что-то создаешь.
Если принять во внимание тот факт, что программирование это ремесло сразу становиться ясно насколько здесь важен опыт, твой инструментарий и интуиция.
1. Честность — лучшая стратегия
Когда ты пишешь код, иногда возникает соблазн написать костыль и заставить программу работать без подлинного понимания что же на самом деле происходит. Классический пример это, когда ты решаешь вставить вызов API просто потому, что это магическим образом устраняет баг; или когда после вставки printf программа перестает падать.
В обоих случаях налицо самообман. Ты должен спросить себя: «Понимаю ли я почему моя программа делает X?». Если нет, то жди неприятностей. Твоя задача как программиста понимать что происходит потому, что компьютер делает в точности что ему сказано, а не то, что по твоим представлениям он должен делать.
Честность требует усердия. Ты должен быть дотошным и скрупулезным когда дело касается того, что делает твоя программа и почему.
2. Упрощай, упрощай, упрощай
Тони Хоар как-то сказал: «Есть два подхода к программированию. Первый — сделать программу настолько простой, чтобы в ней очевидно не было ошибок. А второй — сделать её настолько сложной, чтобы в ней не было очевидных ошибок. Первый — куда более сложный».
Упророщай, делай рефакторинг, удаляй.
Я бы перефразировал утверждение Хоара: «Внутри каждой большой и сложной программы находиться маленькая эллегантная программа, которая делает абсолютно то же самое».
Это сродни философии "слабо связанных кирпичиков". Куда лучше разбить программу на маленькие части, которые взаимодействуют между собой, чем строить цельный монолит. UNIX например своим успехом частично обязан такому подходу.
3. Отладчики это костыли, профайлеры — нет
Я почти никогда не пользуюсь отладчиком. Я пишу свои программы так, чтобы они выводили в лог всю необходимую информацию, по которой можно понять что происходит. В большинстве случаев я могу понять что не так с кодом по лог файлу без всякой помощи отладчика.
Причина по которой я нечасто пользуюсь отладчиком в том, что он позволяет меньше думать. Большинство людей, когда находят баг открывают отладчик и погружаются в тресину брейкпойнтов, значений переменных и памяти. Что может быть проще пасть под чарами столь мощного средства, но если приложить немного ума в будущем это окупится. Если твоя программа настолько сложна, что тебе требуется отладчик стоит вновь обратиться к пункту №2.
(Впрочем один из самых уважаемых мною программистов Джон Остэрхаут похоже проводит весь день в отладчике Windows).
Что же касается профайлеров — они очень полезны если тебе нужно оценивать производительность. Ты никогда не перестанешь удивляться, какие интересные результаты дает тебе профайлер.
4. За дублирование придется поплатиться
Не повторяйся! В коде делай все лишь один раз.
Это напонимает пункт №2, но тут особый случай. Даже маленький кусок кода, который ты продублировал, в будущем приведет к проблемам, когда ты изменишь одну версию и забудешь поправить вторую.
5. Будь неразборчив в языках
Некоторые люди одержимы каким-то одним языком и думают, что этот язык подходит для чего угодно. Ошибочно так думать. Нет языка на все случаи жизни.
Главное понимать какой из языков среди своего инструментария использовать для какой проблемы. Поэтому лучше иметь побольше инструментов. Попробуй разные языки, напиши на них что-нибудь.
Например, тебе может и не придется много где использовать Python или ML, но ты поработаешь с list comprehensions и почувствуешь их мощь. Или поиграйся с Go и увидишь как работать конкурентными приложениями. Или ты поработаешь с Perl и оценишь силу по-настоящему гибкой работы со строками. Наконец научишься PHP, чтобы быстро делать динамические веб страницы.
Я ненавижу войны между языками Эти войны для неудачников потому, что, в сущности, тут не о чем спорить. Например в моих руках PHP это катастрофа, тогда как в других руках он запоет как соловей. В той же мере это относится и к C++.
6. Проще надстроить программу чем построить ее сразу
Этот пункт тесно связан с пунктом №2. Начни с малого и надстраивай. Когда ты решаешь проблему куда проще начать с маленьких блоков(возможно сделав заглушки для каких-то частей) нежели проектировать архитектуру от начала до конца.
Когда ты строишь архитектуру от начала до конца ты 1) делаешь это неверно 2) получаешь в итоге нечто большое и сложное, куда будет очень трудно вносить изменения. С другой стороны если ты используешь маленькие блоки, которые взаимодействует между собой, рефакторинг будет проще в момент, когда ты поймешь что сделал ошибку в самом начале.
Причина в том, что нет способа узнать как должна выглядеть та самая правильная архитектура. Лишь в редких случаях можно сказать какие будут внешние воздействия на программу. Ты можешь утверждать, что тебе известен характер входящего TCP трафика, который обрабатывает твой мэйл сервер, или количество пользователей, или что ты никогда не слышал про спам. Так или иначе будет нечто извне, что начисто разрушит все твои предположения, и вот если эти предположения касались большой, сильно связанной и сложной системы у тебя большие проблемы парень.
7. Изучай как устроены слои
Я полагаю, что крайне важно поднимаясь вверх от CPU до языка, который ты используешь, понимать на каком слое что происходит. Очень важно понимать слои(будь то понимание во что компилируется код на C или в случае Java понимание JVM и как она работает).
Это очень сильно помогает, когда ты имеешь дело с проблемами производительности или отладкой. В моей памяти всплывает случай, когда клиент прислал нам скриншот рухнувшего Windows 2000, на котором было видно состояние небольшого куска памяти и регистров. Зная версию программы, установленную у клиента, мы, только по этому отчету, смогли выявить проблемму с указателем на null, а главное ее причины.
8. Я не настолько молод, чтобы знать все
Мне еще столько стоит узнать. Одни языки я почти не знаю, хотя есть желание их изучить(Erlang, Clojure). Другие я использовал, но знаю их не так хорошо(JavaScript). А так же есть вещи которые я понимаю с трудом(монады).
PS Меня обвинили, что я не ничего не сказал про тестирование. Стоит добавить, что по-моему мнению тесты нужны для любого кода, с которым вам придется иметь дело какое-то время. Быть может мне надо попрограммировать еще 30 лет и я найду ответ на вопрос “Улучшают ли юнит тесты качество ПО?”. Я писал код как с- так и без юнит тестов, и я до сих пор не знаю правильного ответа, хотя больше склоняютсь к использованию юнит тестов.
Автор: netslow