Какие навыки необходимы хорошему разработчику
Всем привет. Меня зовут Владислав Фурдак, я .NET-техлид и работаю c платформой .NET около 10 лет. Ранее писал на DOU на темы карьеры, а также технические статьи: «Асинхронность в C#», «Эволюция .NET-стека», «Как стать Full Stack разработчиком».
В этом материале мы поговорим о тех навыках, знаниях и инструментах, которые выходят за рамки конкретных языков программирования, стеков и фреймворков. Статья будет в большей степени полезна бэкенд- либо фулстек-разработчикам, независимо от технологий.
Сетевое взаимодействие
Понимание компьютерных сетей
Если вы не системный администратор, глубоко разбираться в сетях вам не требуется. Однако бывает, что для решения каких-то проблем все же нужно выяснить, что не так, или помочь членам команды. Я выделил минимальный набор того, что необходимо для перекрытия этих рисков:
- Базовое представление про модель OSI, а также протоколы, которые имплементируют эти уровни:
- IP — адресация, маски, маршрутизация;
- TCP — сокеты и порты, для дебага можно использовать ping/telnet;
- HTTP — передача текста по TCP, далее о нем будет подробней;
- SSL — хендшейки, OpenSSL;
- DNS — resolve доменных имен;
- что такое NAT.
- Умение пользоваться Wireshark/tcpdump для дебага сетевых взаимодействий локально и удаленно.
- Понимание работы Proxy, VPN.
- SSL/TLS, сертификаты.
- Сетевые утилиты (Windows):
- arp;
- netstat;
- ping;
- traceroute/tracert.
- PuTTY.
- Firewalls.
- Понимание прикладных протоколов: SMTP, HTTP, SFTP, LDAP etc.
Приведу пример, где могут понадобиться подобные знания разработчику. Вы хотите настроить анализатор трафика для отладки общения локального бэкенда с мобильным приложением в физическом мобильном телефоне. Вы нашли статью, как это делается, но после запуска прокси-сервера Charles, установки соединения через роутер с прокси в локальной домашней сети у вас ничего не работает. Как искать проблему?
Для начала убедитесь, что прокси Charles открыл сокет локально, для этого используем netstat. Далее, что ваш телефон находится в локальной сети. Через утилиту arp (Windows), если уже были запросы. Либо же можно пропинговать IP-адрес телефона с ПК. Потом, если все хорошо, проверить, а доходят ли пакеты из роутера к ПК. Для этого используем Wireshark. Проблемы могут скрываться на любом из этапов прохождения пакетов. Либо что-то не так с приватностью сети и для нее настроены правила фаервола блокировать соединения, либо же ваш роутер работает в режиме «изоляции точки доступа».
Работа с HTTP
Понимание, как анализировать и дебажить проект напрямую без интерфейса через HTTP, является базовым навыком любого разработчика, работающего с Web. Тут могут помочь такие навыки:
- Умение работать с Chrome DevTools (или любым другим инструментом из браузера). Мне нравится скорость работы и возможности Chrome, также там можно заниматься профайлингом, выстраивать сложные правила отладки JS-кода, работать с контекстом из консоли и многое другое.
- Fiddler/Charles или Mitmproxy на ваш выбор. Более продвинутый инструментарий для захвата трафика. Можно дебажить как веб, так и любые другие системы, работающие по HTTP. Полезными могут быть: отладка мобильных приложений, случаи, когда вы не успеваете посмотреть, что произошло, из-за быстрых перенаправлений в браузере, а также запись сессий.
- Анализ мобильного трафика через локальную домашнюю сеть/через прямое подключение — опять-таки об отладке связи с устройствами.
- Postman или аналогичный софт для автоматизации HTTP-запросов. В Postman можно настроить удобную систему быстрых смен окружений, добавить поддержку переменных в полях запроса, сохранять данные, упростить получение токена через запись его в контекст Postman, из которого можно пробросить в заголовки других запросов.
- Curl — кроссплатформенная утилита для создания запросов любых протоколов прикладного уровня.
Хорошо знать техники клиент-серверного взаимодействия: AJAX, Comet, WebSockets.
Технологии браузеров:
- Кеширование содержимого веб-страниц со стороны браузеров.
Чтобы проектировать API своих приложений, стоит знать:
- HTTP-протокол: заголовки и методы;
- концепцию REST;
- о существовании альтернатив для API, что построены на элементах REST, это gRPC, GraphQL, OData, устаревший JSON-RPC;
- механизмы аутентификации и авторизации: cookies, basic authentication. Можно также упомянуть о JWT/Bearer токенах, хотя они и не являются частью HTTP-протокола.
Безопасность и уязвимости
Для веб-разработки необходимо знать хотя бы базовые возможные уязвимости и методы борьбы с ними. Как правило, во всех фреймворках или серверах уже есть готовые средства, чтобы предотвратить риски.
Популярные возможные веб-уязвимости:
- OWASP Top 10;
- CORS. Если вкратце, механизм защиты веб-сайта от открытия под чужим доменом.
Кроме того, надо немного знать о хешировании MD5/SHA и ключах шифрования.
3rd party интеграции
Протоколы использования сторонних поставщиков аутентификации (Google, Facebook):
- OAuth2;
- OpenID Connect;
- SAML.
Что позволит быстро подключить любой сторонний поставщик аутентификации на основании мануала от самого поставщика либо же использовать готовый мидлвар для этого.
Глубоко изучать протоколы не стоит, но общее понимание не помешает.
Архитектура
Паттерны проектирования
Сами по себе шаблоны проектирования несут несколько функций:
- Это язык, который дает возможность одним разработчикам показать концепцию поведения другим разработчикам. При поиске решения первично само решение, а не попытка применить шаблоны проектирования в слепую.
- Шаблоны показывают, каким образом можно решить типичные проблемы. Более того, дают этому решению имя (предыдущий пункт).
- Любые шаблоны, архитектурные/имплементации являются выделением определенных ответственностей и их сегрегацией.
Можно выделить такие группы паттернов:
- Паттерны GoF, довольно универсальные вне зависимости от языков. Вот хороший ресурс для их понимания.
- Архитектурные паттерны, их много, и они специфичны для области применения и языка. Например, для UI-разработки это либо вариации MVC/MVP/MVVM, работающие на привязках данных, либо же FLUX-подобные, где поток данных однонаправленный.
- Паттерны функционального программирования.
Для бэкенд-разработки все сложней, есть ряд паттернов, задающих общий дизайн системы: монолиты, SOA, микросервисные паттерны, а также конкретные реализации в рамках одного сервиса (модуля):
- N-Layers;
- модульная архитектура;
- Onion, Hexagonal, Clean architecture;
- DDD;
- CQS/CQRS подходы;
- Event-based архитектура;
- Event Sourcing;
- модель акторов;
- паттерны построения Cloud-решений;
- антипаттерны, показывающие, как делать не надо и что за это будет.
Принципы проектирования
Это скорее методологии, чем конкретные паттерны, они придуманы для того, чтобы иметь внутреннюю опору при принятии тех или иных решений.
Понимание инфраструктурных элементов архитектур распределенных систем
Эта тема актуальна только для бэкенд-специалистов. Каждый разработчик должен быть немного архитектором. Распределенные системы, которые могут быть как объединением монолитов, так и микросервисами, имеют средства организации инфраструктуры, помогающие всей системе работать.
Сейчас большинство распределенных систем либо хостятся в облаке и используют разные сервисы, предоставляемые самим облаком, либо являются cloud-agnostic, без привязки, где команды сами поднимают инфраструктуру в контейнерах для себя же.
Однако следует заметить, что использование контейнеров часто необоснованно. Если приложение не
Можно выделить самые популярные элементы инфраструктуры для распределенных систем:
- Очереди/брокеры сообщений (Queues, Message Brokers). Могут быть как отдельно установленными системами (RabbitMQ, Kafka, etc), так и предоставляться Cloud-провайдером, например Azure Service Bus.
- Балансировщики нагрузки.
- Логгеры, например cloud-agnostic ELK-стек, либо сервисы, специфичные для конкретного клауд-провайдера. Например, в Azure есть Application Insight. Однако бывает, что ELK-стек ест ресурсов больше, чем сам проект. Удовлетворительная безопасность есть только в платной версии.
- Serverless functions. Куски кода, которые могут быть вызваны в определенное время либо по определенному поводу. Хостятся в инфраструктуре облака.
На самом деле любой Cloud-провайдер предоставляет уйму сервисов, которые дублируют функционал установленных вручную либо дают какой-то уникальный, перечислить их всех будет сложно.
Понимание масштабирования систем
Масштабирование — процесс увеличения возможности системы обслуживать большее количество запросов клиентов.
Существует две основных техники масштабирования: вертикальное и горизонтальное. Вертикальное — это наращивание мощности конкретного сервера, добавление CPU и памяти, в зависимости от потребностей. Горизонтальное — увеличение количества самих серверов/развертывания какого-то из типов контейнеров.
Инструментарий повышения производительности посредством потребления памяти или CPU:
- Кеши второго уровня: Redis, Memcached.
- Движки полнотекстового поиска: Lucene, Solr, Elastic Search.
- Техники репликации: повышают устойчивость и доступность кластера.
- Техники шардинга: это разнесение таблиц/коллекций на шарды по ключу шарда в разных базах. Повышает производительность запросов по данным в рамках части таблицы.
Базовое понимание развертывания систем
- CI/CD Pipelines, декларативный стиль через написание кода скриптов деплоймента. Для этих целей используют популярный GitLab с его пайплайнами. Но, к примеру, в Azure есть альтернатива — Azure DevOps Service.
- Контейнеризация, например Docker & Dockerfile, Docker Compose. Для разработчика часто достаточно знать основы Docker и уметь запустить контейнер.
- IaaC-тулы: Terraform, ARM (Azure), CloudFormation (AWS). Это больше для инженеров в DevOps-практике.
- Виртуальные машины, hypervisor.
Оркестрация контейнеров
Для масштабирования и автоматического управления множеством контейнеров используют оркестраторы.
Хотя это больше работа системных инженеров в DevOps, но все же вещи вроде Kubernetes (K8s) & Docker Swarm нужно понимать концептуально. K8s может быть развернут как в клауде (как сервис), так и on-premise, если есть такая необходимость с точки зрения compliance & legal.
Умение читать UML-диаграммы
Иногда сложные участки реализации программ изображают концептуально в виде UML. Так это делают, даже если не следуют формальным спецификациям методов схематизации.
Работа с данными
СУБД
Понимать, что существуют реляционные/нереляционные, документные, колоночные БД, базы данных на графах.
Для реляционных баз универсальное мерило хорошего дизайна — следование нормальным формам при проектировании. Чаще всего достаточно
Также для реляционных баз, которые построены как имплементация ACID, существуют уровни изоляции транзакций.
Форматы передачи и хранения данных
Форматы, которые используют для написания конфигурации файлов, общения по HTTP, хранения данных:
- XML;
- JSON;
- CSV;
- BSON;
- YAML;
- WSDL (устаревший).
Форматы передачи, не предназначенные для чтения вручную:
- Protobuf — передача данных по сети, по сути, быстрый бинарный сериализатор;
- AMQP — формат сообщений для шин данных.
А также языки микроразметки:
- BBCode;
- Markdown.
Работа с ОС
Базовые знания по администрированию вашей системы
Сам работаю с Windows, но все то же самое применимо к Linux:
- настройка сетей/устройств;
- системный лог ошибок;
- использование Perfmon или похожих средств для поиска утечек памяти;
- для Linux может быть полезным знание Iptables.
Знание языка автоматизации работы с объектами операционной системы
Этот навык может пригодиться, если ваш солюшн требует каких-то дополнительных инструментов, которые довольно быстро меняются и имеют скромный функционал: дернуть пару-тройку команд, очистить папку, скопировать файлы и так далее. Также на них вы можете писать степы для
Для Windows это либо batch-файлы (.bat, .cmd, .btm), либо PowerShell (.ps1). Для Linux — shell-скрипты (Bash). Также нужно уметь создавать юниты для systemd и понимать, как писать приложение, чтобы оно могло работать с systemd.
Полезно знать о существовании более продвинутых средств автоматизации управления состоянием системы:
- Ansible;
- Puppet;
- Salt.
Понимание системного программирования
- Многозадачность:
- вытесняющая;
- кооперативная.
- Многопоточность и объекты синхронизации ядра:
- мьютекс;
- семафор;
- спин-блокировка.
- Объекты синхронизации среды, более высокоуровневые:
- монитор.
- Race condition.
- Асинхронность в разных контекстах исполнения.
Микроязыки
Работа и текстом:
- Регулярные выражения (regular expressions, regexp). Используются для поиска заданного шаблона в тексте либо замены по шаблону. Поддерживаются практически всеми языками программирования.
- Wildcards — более простая альтернатива регулярным выражениям, используется в основном для поиска файлов.
Работа с датами и временем:
- Cron expressions — универсальный язык описания времени повторяющихся действий. Многие библиотеки, отвечающие за запуск регулярных действий, могут использовать cron-выражения в качестве параметра.
Работа с XML:
- XPath — язык запросов элементов из
XML-документов. Как частный случай — парсинг HTML. Последний раз я работал с ним, когда в системах вроде Sitecore/Umbraco необходимо было запрашивать элементы дерева контента, которое было представлено в виде XML. - XSLT — язык написание преобразований
XML-документов. Сейчас встречается редко, внутри использует также XPath. - XQuery — более свежая альтернатива XSLT.
- XSD — язык описания схем
XML-документов.
Работа с контейнерами. Например, для Docker существует синтаксис Dockerfile, описывающий старт контейнера.
Работа с поиском информации. Нужно уметь пользоваться операторами поиска в Google для уточнения поисковых запросов. Также есть хорошая альтернатива гугловскому поисковику — DuckDuckGo. Имеет другие алгоритмы поиска и выдачи информации, дает немного иную поисковую выдачу. Здесь тоже есть операторы поиска.
В языках программирования и фреймворках можно обойтись и без знания микроязыков, но знать об их существовании стоит.
Информатика
Сложность алгоритмов и O-нотации
«О» большое и «о» малое в целом являются универсальными методами, которые в том числе применимы к оценке сложности алгоритмов. Когда привыкаешь мыслить в таких категориях, при написании программ больше думаешь о производительности, если это необходимо.
Максимум, что вам будет полезно для понимания сложностей алгоритмов работы со структурами данных, можно прочесть в оригинале Big-O Complexity Chart (есть на русском).
Структуры данных
Каждая структура данных создана в результате решения какой-то задачи оптимизации поиска либо хранения информации.
Существует множество разных подвидов описанных структур, одних деревьев можно насчитать пару десятков. Но главное понимать базово, что это и зачем нужно. Вот основные:
- списки, массивы (List, Array);
- связанные списки/двусвязные списки (Linked list/Doubly linked list);
- множества (Set);
- хеш-таблицы (Hash tables, Dictionary);
- матрицы (Matrix);
- бинарные деревья/бинарные деревья поиска (Binary tree/Binary search tree);
- N-арные деревья (tree);
- графы (Graph);
- очереди (Queue);
- стек (Stack);
- дек (Deck);
- кортежи (Tupple).
Полезно знать алгоритмы работы со структурами данных, в целом все они сводятся к таким:
- обход структуры данных (например, для бинарного дерева это поиск в глубину и в ширину);
- поиск и замена элементов в структуре данных;
- приведение структуры данных к какому-то виду, своеобразные сортировки.
Стоит прочесть: «Алгоритмы и структуры данных в C#», 8 Common Data Structures every Programmer must know.
Заучивать алгоритмы наизусть не нужно, достаточно понимать, какие структуры данных какую задачу решают.
Базовые понятия дискретной математики
Эту понятийную базу можно использовать в самых разных контекстах работы разных языков программирования, протоколов и систем.
- Множества, операции с множествами.
- Предикат.
- Булевы операции.
- Идемпотентность.
- Транзитивность.
- Конечные автоматы (стейт-машины).
Организация разработки
Умение работать с текстовыми редакторами
Любые инструменты повышения производительности при работе с текстом. Например, во фронтенд-разработке есть плагины, помогающие писать верстку быстро, по ключевым словам. Для C# есть Rider/Resharper, позволяющий значительно ускорить тривиальные действия и навигацию по коду.
Умение работать с Git & Gitflow
Подсказка по Gitflow. Кроме базовых commit/pull/push/merge, можно освоить rebase, cherry pick, работу с сабмодулями.
Методологии тестирования
Можно выделить такие подходы к мануальному тестированию:
- Smoke testing;
- Sanity testing;
- Regression testing.
Подходы к автоматизации тестирования:
- Unit Test и AAA-методология.
- Integration test (интеграционные тесты).
- UI-test (автотесты).
Методологии разработки
- Гибкие методологии, построенные как следствие фундаментального Agile Manifesto.
- Waterfall-методология, классика для построения сложных систем с заранее прописанными жесткими требованиями.
- Экстремальное программирование. Одна из полезных техник — парное программирование. Вдвоем проще решать сложные задачи либо обмениваться опытом. Парное программирование может помочь новичкам начать быстро приносить ценность на проекте.
Понятие SDLC и его артефакты, такие как: SysRS, SRS, Traceability Matrix, матрица RACI.
Методологии оценки проектов
Предлагаю прочесть неплохую статью по общим принципам. Самой же техникой может быть, например, Scrum poker.
UI/UX
Будет полезно для фулстек- либо фронтенд-разработчиков, работающих с готовыми UI-китами или библиотеками.
Фундаментальная книга по UX — «Интерфейс. Новые направления в проектировании компьютерных систем». Дает базовое понимание, как строить интерфейс машины для человека и какими принципами руководствоваться для его проектирования.
В заключение
Эту статью можно рассматривать как некий роадмап для закрытия пробелов в знаниях. Или хотя бы для понимания, какие средства и подходы для этого существуют.
Если у вас есть чем дополнить статью — не стесняйтесь, пишите в комментарии, буду благодарен.
Кроме того, если вы начинающий .NET-разработчик, вступайте в мое телеграм-комьюнити. Если же вы опытный сеньор-разработчик/техлид, можете написать мне, я добавлю вас в закрытый телеграм-канал для обмена опытом и обсуждения сложных технических вопросов.
С вопросами, пожеланиями или замечаниями пишите мне на фейсбук.