Работа в реальном проекте: советы начинающим программистам

Обложка поста

Рассказывает Олег Меринов, Senior Development TeamLeader в DataArt

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

Я решил рассказать о некоторых важных моментах, которые приходится обсуждать едва ли не с каждым, кто пока не занимался никакими проектами, кроме учебных. Я специализируюсь на .NET, но эти советы вполне применимы к любому языку, хоть к Java, хоть к Python. Ведь все мы должны сделать одно и то же: написать, протестировать, зарелизить и поддерживать.

Оценка требований

Вспоминаю себя студентом: едва получив задачу, я садился кодить. Думаю, это нормально, а уж для студента просто естественно — кидаться в бой, как только вручили условие.

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

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

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

Когда вы уяснили задачу и даже нашли примерное решение — поделитесь им, расскажите алгоритмы, которые пришли вам в голову. Реакция старшего коллеги сразу подтвердит или опровергнет вашу догадку, даст почву для дальнейшего исследования. Вообще делитесь своими идеями. Это тоже противоречит школьному стереотипу: отличникам категорически нельзя давать списывать. И многие молодые инженеры по привычке боятся рассказать, что они придумали. Но только получив отзыв на свой вариант решения, вы расширяете картину мира — возможно, это позволит посмотреть на задачу с другой, как раз нужной вам, стороны.

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

Ещё один совет: делайте блок-схемы. Признайтесь, вы ведь их не рисуете? Я знаю, многие уверены, вся эта сортировка «пузырьком» — просто глупости. На самом деле, в будущем это поможет вам, поскольку схематичное описание решения позволит очень быстро донести до коллег вашу идею.

Что проще: изобразить схему с тремя блоками и связями между ними или исписать половину листа А4? К тому же, картинку проще воспринимать, а читать длинные тексты никому не хочется. Обратите внимание на UML — язык, на котором можно писать и физические модели базы данных, и концептуальные модели, и диаграммы последовательности вызовов, и многое другое.

Оценка сложности

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

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

Разработка

Главный вопрос: как писать? Один проджект-менеджер выразился довольно точно: «надо писать без багов всегда». И здесь самое главное: naming convention и code style.

Naming convention (соглашение об именах) необходимо, чтобы код было удобно читать. Это может быть не совсем понятно в случае с лабораторной или курсовой, но обычно работать приходится в команде. И кодом владеют все разработчики, а не только тот, кто сейчас пилит отдельный компонент системы. А соглашение об именах позволяет легко понять, что написал твой коллега.

Той же цели служит и Code style (стандарт оформления кода) — стиль оформления кода, необходимый для унификации. Программный код, разработанный разными людьми, должен читаться так, как будто его написал один программист. Поэтому, придя в проект, в первую очередь, нужно понять, какие naming convention и code style здесь используют. Помните, что строгое следование им — ещё и знак уважения к коллегам, который они обязательно оценят.

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

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

В своих примерах Microsoft продаёт велосипеды, а я буду считать налоги.

Пишите простой код! Элементарный совет, следовать которому очень сложно. Если инженер не до конца продумал решение задачи, не смог сделать декомпозицию (не разбил задачу на составные части) — в методе мы видим 500 строк кода. Это не так страшно, но важно вернуться назад и подумать над декомпозицией ещё раз.

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

Чтобы код стал проще, нужно ввести слабую связанность компонентов.

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

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

Но можно ввести дополнительные элементы, например, интерфейс для класса taxEvaluator для employee.

Что такое IoC?

Этот паттерн называется Inversion of control. В микросервисах слабая связанность приводит к масштабированию системы. Когда у нас есть интерфейс, мы можем изолировать наш основной класс с логикой и протестировать его.

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

Проверяйте аргументы — это частая проблема молодых инженеров: они уверены, что всё написали чётко и в проверках написанное ими не нуждается. Но это не так!

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

Вообще исключение — это особая тема. Чтобы понять, что с ним делать, можно почитать «Программист — прагматик» Дэйва Томаса и Энди Ханта. Книга старая, но очень интересная, там хорошие и здравые идеи, когда выбрасывать, когда нет, когда считать, что это ошибка бизнес-, а не программного уровня. Но у нас tax evaluator = null — это ключевая функциональность и без неё мы работать не можем, поэтому выбрасываем исключение.

Когда к нам приходит пустой объект с работником — employee — то мы вновь ничего не можем сделать, так как на этом завязана вся логика.

Исключения надо обрабатывать

«Try catch» необходимо использовать либо с типизированными исключениями, либо когда мы не знаем, какое исключение прилетит. Надо залогировать, но ни в коем случае не возвращать такие конструкции.

Мы «глотаем» исключения, и поэтому никогда не увидим их в логах. И как будто всё хорошо и работает, но если будет проблема, мы не сможем её поймать. Исключения нужны, но используйте их очень аккуратно.

Можно убрать «try catch» и обработать исключение как бизнес-кейс и логировать. Записывайте в логи ход выполнения ваших алгоритмов и программ, потому что во время разработки ваш софт доступен через дебаггер и вы всегда можете посмотреть, что происходит. Но когда исключение уходит туда, куда у вас нет доступа, то только логи могут вам помочь.

Unit test

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

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

Сборка, деплой, конфигурация

Что мы делаем, после того как написали что-то? Мы делаем сборку, потом собранные элементы где-то храним, затем деплоим.

Это цикл жизни от момента создания до деплоя, и этот код будет использовать конечный пользователь. Я написал, какие инструменты могут быть использованы: создать автоматическую сборку можно с помощью PowerShell и msbuilt; хранить — в ProGet, и дальше мы можем деплоить полученные пакеты. Это немного сложно.

Работа над ошибками, изменение требований

Мы всё поняли, всё запрограммировали, протестировали, отдали, а заказчик говорит: всё не то.

Что делать? Возвращаться к самому началу и спрашивать: что не то? Если изменились требования — уточнить их и прорабатывать дальше.

Что почитать?

  • Брайан У. Керниган, Деннис М. Ритчи «The C Programming Language» — достаточно старая. Она произвела на меня большое впечатление. Во многом не про язык программирования, а про верный майнд-сет.
  • МакКоннел «Code Complete»— маст рид.
  • Дэйв Томас, Энди Хант «The Pragmatic Programmer».
  • Альфред Ахо «Data Structures and Algorithms» — занудная, всегда, когда читаю, засыпаю. Да, она читается сложно, но она очень классная.
  • Джон Влисидис, Ральф Джонсон, Ричард Хелм, Эрих Гамма «Design Patterns» — книга для тех, кто планирует писать на объектно-ориентированных языках программирования. Она тоже задаёт правильный майнд-сет. Когда я читал, то ничего не понял, но когда начал работать, перечитал, и книга начала помогать.
  • Мартин Фаулер «Catalog of Patterns of Enterprise Application Architecture» — про архитектуру приложений. Фаулер внёс огромный вклад в индустрию, написал разные паттерны, на основе которых создано много софта, те же ORM (object relation mapping).