Sunday, May 11, 2008

Оценка уровня программиста

В недавнем разговоре с моим другом мы подняли интересный вопрос, с которым наверняка сталкивался каждый senior и lead при приеме нового человека на работу, в команду или даже просто в своей команде: как оценить реальный уровень программиста. Мой друг высказал интересную, но все же шуточную идею: junior хочет все переписать заново, middle и выше уже начинают понимать, что переписыванием заново проблема не решается, а за само переписывание клиент/руководство деньги просто так платить не будет. Однако в каждой шутке, как известно, лишь доля шутки: я сам работал с ребятами, которые хотели переписать весь проект или какую-то его часть за несколько недель или дней, аргументируя это тем, что их вариант будет работать лучше. Я на собственном опыте не раз убеждался, что навыков у подобных junior/middle людей просто не хватит на реализацию задумки, а предложение переписать возникает лишь за отсутствием других навыков, кроме написания кода с нуля. Люди посильнее никогда не стремятся переписать все. Они более трезво оценивают сложность задачи, свой уровень и уровень команды в целом, и, что самое важное, обладают навыками рефакторинга, которыми еще не обладают junior'ы и многие midlle'ы. То есть они могут, при необходимости, просто изменить нужную часть приложения, причем, как правило, в процессе имплементации новой функциональности, чтобы а) не напрягать никого оплатой/продажей отдельных тасков на рефакторинг, б) протестировать измененный функционал в комплексе вместе с тестированием нового. Второе, конечно, не всегда возможно, так как изменения могут быть глубоко в ядре, но тогда на помощь приходят unit-тесты, о которых эти люди, опять же, знают и умеют применять.

Итак, к чему это длинное вступление? К тому, что оценка уровня программиста очень сложная штука и очень сложно загнать кого-то в существующие рамки junior, middle, senior, lead, architect, etc. У меня есть свое видение данного вопроса, которое я сейчас изложу, но наверняка у читающих этот пост людей будет свое, дополняющее или опровергающее мое, и мне будет интересно его услышать.

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

В данный момент в различных фирмах существуют разные подходы к оценке. Где смотрят лишь на технические знания, заставляя сотрудников сдавать тесты, где опираются на мнение руководителя, где проводят комплексную оценку, опрашивая сотрудников, руководителя и подчиненных по различным пунктам. Но практически везде забывают одну важную вещь, которая вроде бы лежит на поверхности, но ведет себя как потерянные очки, которые потом оказываются на носу: в программировании, как и во многих других сферах деятельности, нельзя давать единственную оценку уровню человека, можно давать лишь среднюю, выведенную определенным образом из менее общих оценок. Это как в английском языке: человек с reading и listening на уровне upper-intermediate может иметь pre-intermedite в общении и vocabular’е. Такого человека и обучать нужно соответствующим образом: с большим упором на менее развитые области. То есть, алгоритм оценки должен выглядеть приблизительно следующим образом: разбиваем необходимый набор знаний/умений на группы (критерии), оцениваем независимо каждый критерий и затем собираем все воедино в соответствии с необходимой формулой, используя те или иные коэффициенты усиления для критериев различной степени важности.

Второй ошибкой является сам набор критериев оценки. Почти всегда в таких случаях рассматривают лишь знание человеком различных технологий, паттернов, подходов, методологий, на оценку чего направлены различные тесты. В то время как оценивать нужно не знание, а понимание этих вещей. Хороший программист может не знать технологии JSP или JSF, т.к. он никогда в глаза не видел Java, но при этом, хорошо понимая принципы web-программирования и имея опыт ASP.NET или PHP, он с легкостью сможет разобраться со сложной проблемой и изучит новую технологию или язык очень быстро. Это как в школе: щелкать однотипные задачки может научиться практически любой, а вот понимать предмет на уровне, достаточном для решения нестандартных олимпиадных задач, могут единицы. То есть если человек знает, что есть определенный набор событий в жизненном цикле ASP.NET-страницы, это хорошо, но это junior уровень. Middle уже должен не просто использовать эти события, но и понимать, что происходит до них, и что их вызывает и с какой целью (что такое http-запрос и http-ответ, как они выглядят, что такое конвейер и что такое класс страницы вообще). Задача senior'а же уметь видеть полный поток выполнения запроса, знать особенности, понимать на более глубоком и абстрактном уровне все процессы, происходящие здесь, чтобы суметь в случае надобности разобраться со сложной проблемой. Именно на уровне понимания, на мой взгляд, и проходит одна из важнейших границ оценки специалиста.

Еще одним важным умением, которое приходит лишь с повышением уровня и может рассматриваться как некоторый критерий этого уровня, является умение перемещаться между уровнями абстракции. Junior-программисты часто не видят дальше своей маленькой задачи и куска кода, который они сейчас пишут. Из-за этого их код и отличается некоторой непродуманностью и их часто приходится поправлять, просить перенести тот или иной код в другой класс или даже на другой уровень приложения. С опытом, программист учится выходить на более высокие уровни абстракции: сначала на уровень понимания класса, потом на уровень взаимодействия между классами и объектами, как правило, при этом на ходу изучая паттерны проектирования. Затем приходит видение слоев и частей приложения, взаимодействия между ними и, наконец, умение видеть архитектуру и дизайн приложения в целом, с высоты птичьего полета. Если оценивать очень грубо, я бы сказал, что на этом этапе программист выходит уже на уровень middle+ или даже senior. Самое важное здесь: умение быстро перемещаться с уровня высокоуровневой архитектуры до уровня какого-нибудь куска кода и обратно, комплексная видимость кода приложения. Конечно, в крупных и даже средних приложениях очень сложно знать весь код, но это и не нужно – достаточно просто понимать, что делает тот или иной модуль или слой, а лезть ниже стоит лишь тогда, когда это действительно нужно. С этим сильный программист справляется без особого труда. Кроме того, умение видеть приложение в целом, пусть даже без особой степени детализации – это одно из самых важных умений lead'а и architect'а, без него далеко не уедешь.

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

Еще один важный навык – умение писать качественный и продуманный код. Этот навык включает в себя целый комплекс других умений: знание и применение объектно-ориентированного дизайна и архитектуры, паттернов проектирования (естественно, в меру), рефакторинга, best patterns and practices в той или иной технологии, умение читать код глазами и смотреть наперед, предупреждая возможные ошибки и предусматривая дальнейшее расширение приложения. Все это приходит с опытом и желанием учится и в разной степени развито у программистов всех уровней, начиная от junior'а и заканчивая lead'ами и architect'ами.

Также нельзя оставлять в стороне и понимание процесса разработки. Процесс разработки серьезного ПО – это в 99% случаев командная работа, которой нужно управлять. Неуправляемые проекты очень часто превращаются в проекты разной степени безнадежности (привет всем «камикадзе»). Выбор правильной методологии, планирование работ в соответствие с ней – задача программистов не всех уровней, это работа людей уровня senior+, но понимание этой методологии, своей роли и задач в разработке очень полезно. Если мы сейчас пишем код, значит, мы пишем код, если фиксим баги, значит, фиксим баги, а не кто в лес, кто по дрова. В слаженно работающей по определенному плану команде, как правило, здоровая рабочая атмосфера и авралы случаются очень редко. По уровню данного понимания также можно оценить уровень специалиста.

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

11 comments:

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

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

    В каких-то случаях это может приводить к:
    1) Незадокументированым изменения. В свою очередь это приводит к:
    а) Разсогласованию тесткейсов, деплоймент скриптов и так далее
    б) Скрытые ошибки основанные на допущения о предыдущей версии
    в) Рискам, нучтенным во время эстимирования, к рискам по списку из первого пункта
    2) Нарушению атомарности изменений, это же пирводит к:
    а) Осложнение коде ревью. Ревью метода который считает дату, отличаеться от ревью возможных сайдеффектов изменений в ядре.
    б) Осложнение учета, тут и отсутвие ссылки от таска на измененный код и в обратную сторону.

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

    В оффлайн, я тебе могу расказать одну страшную историю по теме про компанию в которой ты работал ;).

    ReplyDelete
  2. Хорошая статья, Саш :)
    Пару спорных, на мой взгляд, моментов безусловно присутствует... Я бы не стал говорить, что junior не видит дальше своих задач, а уже middle программер сможет сделать все на более высоком (в плане абстракции) уровне. Такое, как правило происходит лишь в небольших проектах. В средних и крупных очень часто проблема решаетася как раз множеством частных путей, и лишь при накоплении какого-то числа подпорок делается рефакторинг, который все это прилизывает.
    Ну, а вообще здорово :) Молодца, отлично изложил

    ReplyDelete
  3. Миш, согласен полностью :) Ты не совсем правильно понял смысл фразы, которую я писал. Я и не призываю делать изменения под подушкой, чтобы никто не видел. Есть разные типы рефакторингов: некоторые можно провести без особых проблем усилиями одного человека (причем явно, можно с отдельным таском, можно без, но чтобы все знали), для некоторых нужны отдельные большие таски, полностью проанализированные командой и одобренные клиентом. Основной же смысл был в том, что нужно не идти на поводу у юношеского максимализма, а рассматривать и другие варианты, кроме "переписать все заново". Хотя, безусловно, есть и ситуации, когда определенные модули или даже все приложение проще переписать заново. К каждой проблеме нужно подходить индивидуально.

    Жду рассказа ;)

    Спасибо, Андрей :)

    ReplyDelete
  4. С точки зрения программирования я в основном согласен. Но на мой взгляд этого критерия достаточно только для того, чтоб охарактеризовать человека с точки зрения J/M/S, другими словами насколько он полезен команде разработчиков в процессе создания приложения. (Короче не знаю как лучше написать это предложение, но я думаю публика меня поймет :) )

    Но есть как минимум одна вещь, которая отличает человека категории L+/A от категории J/M/S - это понимание (в той или иной степени) финансовой и "политической" сторон проекта.

    Я считаю, что в данной статье более уместно говорить о т.н. категории S+, т.к. не каждый Senior становится Lead'ом.

    P.S. Еще пиши ;-)

    ReplyDelete
  5. Спасибо за идею, Толик. Согласен, что здесь почти не рассмотрены отличительные навыки уровней lead и architect. Там в ход идут уже не только умение понимать business needs, но также лидерские качества и целый комплект менеджерских навыков. Я старался рассмотреть только общие для всех уровней умения и отойти в сторону от менеджмента и личных качеств вообще. Личные качества оттачивать сложнее, чем просто приобрести навык, но это тоже вполне реально, если человек хочет этим заниматься. У меня уже есть еще две идеи для расширения этого поста, возможно, это туда войдет :)

    ReplyDelete
  6. Согласен с Толиком - не важно какого уровня человек, но он должен быть в первую очередь полезным для проекта. Ведь бывают люди и с пониманием абстрактной модели, и с умением "видеть" проект целиком и всем тем, о чем ты написал. Но, при этом, если он полагает, что багфиксинг не для него, а имплиментация классов меньше 2000 строк кода - ниже его достоинства. То толку от этого человека будет меньше чем от Junior'a. Поэтому при оценке любого кандидата необходимо в первую очередь обращать внимание на то, насколько его умения, опыт и отношение к делу помогут проекту выжить. А так, полностью согласен ;)

    ReplyDelete
  7. На мой взгляд нельзя разделять программистов на новичок, бывалый и т. д. Пример в книге "Как пасти котов" Следует разделить программистов на категории: Архитектор, кодер, лидер проекта... а затем выбирать по каждой категории: новичок,...
    Но в целом статья 5+

    ReplyDelete
  8. "Архитектор", "лидер проекта", "кодер" - это роли на проекте, они практически никак не отражают уровень программиста. То есть можно поставить senior'а кодером, а junior'а - архитектором, только далеко мы так не уедем. Распределение людей в команде на роли является как раз следствием нашего понимания, что этот человек лучше справится с этой работой, чем все остальные, а другой, например, лучше справится с другой работой. Я не скажу, что я сам в восторге от подобного разделения на junior'ов, middle'ов, senior'ов и т.д. Как я уже написал, эта оценка довольно сложна, так как содержит множество факторов/критериев, а людей, которые удовлетворяют все эти критерии одновременно, в природе меньше, чем панд, которые знают кунг-фу :) Но тем не менее, данная шкала есть и она пользуется повсеместной популярностью, поэтому за неимением лучшей приходится подстраиваться под эту. Но если уж подстраиваться, то с умом :)

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

    ReplyDelete
    Replies
    1. Этот коммент выдает в вас джуниора :)

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

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

      Delete