В своем блоге на Хабре мы уже не раз писали о Python. Хотя бы потому, что это один из наиболее популярных в мире языков программирования. В начале этого года по версии Tiobe он занял первое место. Популярность его объясняется достаточно просто - язык можно относительно быстро выучить на базовом уровне и начать двигаться к вершинам профессии. Но какие они, эти вершины? На что способен senior, какие задачи решает middle, а какие - junior? Об этом мы поговорили с Алексеем Некрасовым (@znbiz), лидером направления Python в МТС, программным директором направления Python и спикером профессии “Python-разработчик” в Skillbox.

Начнем с того, что должен знать junior, middle и senior

Конечно, все это усредненная информация, для разных случаев и мест работы ситуация может отличаться. Но база все же более-менее общая. Важный момент - в IT чем выше позиция разработчика, тем большим объемом soft-скиллов он должен обладать. Конечно, хард-скиллы тоже никто не отменял. Вот достаточно подробный список знаний и умений специалистов разного уровня.

Junior-разработчик:

hard: знать основы ЯП (языка программирования);

hard: иметь минимальные знания стека, используемого в продукте;

hard: уметь самостоятельно решать простые типовые задачи;

soft: адекватно воспринимать критику;

soft: помимо 8 часов работы самостоятельно дополнительно обучаться 2-3 часа в день.

Middle-разработчик:

hard: знать хорошо основной ЯП, в том числе его тонкости, ограничения, best practices;

hard: знать и применять шаблоны и стандарты промышленной разработки;

hard: уметь подбирать несколько решений нужной задачи и находить оптимальный вариант;

hard: знать и уметь работать со стеком, используемым в компании;

soft: быть наставником для менее опытных коллег;

soft: находить общий язык с тем, от кого зависит решение задач: аналитик, тестировщик, DevOps и другие разработчики;

soft: понимать требования бизнеса;

soft: оценивать свои силы и трудозатраты по своим задачам;

soft: новое качество (на удаленке). Тайм-менеджмент и умение разделять работу и личную жизнь.

Senior-разработчик:

hard: уметь быстро изучить и внедрить новый инструмент в продукт;

hard: прорабатывать архитектуру новых компонентов в продукте;

hard: смотреть на продукт шире и видеть все его ограничения, узкие места и т.д.;

soft: понимать, для чего создается продукт, и задавать направление дальнейшего его развития;

soft: проводить декомпозицию задач;

soft: делегировать задачи;

soft: быть наставником для middle разработчиков;

soft: переключаться между своей ролью и другими ролями в команде, к примеру иногда быть как аналитиком, так и DevOps;

soft: видеть сильные и слабые стороны менее опытных коллег, помогать команде стать лучше;

soft: новое качество (на удаленке). Тайм-менеджмент и умение разделять работу и личную жизнь.

Теперь - о задачах

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

Junior. Если коротко, то основная задача junior разработчика - учиться и перенимать опыт у более опытных коллег. Часто обучение проходит в таком формате: брать все более сложные задачи (их даёт наставник или более опытный коллега), выполнение которых каждый раз будет требовать выходить за рамки того, что он знает.

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

  • Разработать валидацию входных/выходных данных,

  • “Причесать” код в соответствие с новым правилом из линтера,

  • Написать автотесты и т.п.

Но даже такие простые задачи проходят проверку у наставника, так как на них junior “набивает руку” и приучается к тем стилям разработки, которые используются в компании.

Вариант задачи для junior - написать тест на создание чего-либо. Например, слова:

from typing import Optional
from unittest import mock

import pytest

from app.factories import UserFactory
from app.models import Lexicon, User
from app.views import LexiconResourceList

from tests.conftest import deleted


@pytest.fixture
def user():
   user = UserFactory()
   yield user
   deleted(user)


class TestLexiconResourceList:
   f_post = LexiconResourceList().post.__wrapped__

   @mock.patch('app.views.request')
   def test_post(self, mock_request, user: User):
       data = {'value': "Word_1"}
       mock_request.json = data
       mock_request.user = user
       resp = self.f_post()

       assert resp['value'] == data['value']
       lexicon: Optional[Lexicon] = Lexicon.query \
           .filter(Lexicon.value == data['value'], Lexicon.status == Lexicon.Status.active) \
           .first()
       assert lexicon is not None

       # try again to add the word
       resp = self.f_post()
       assert 'This word already exists' in resp['errors'][0][0]

Middle-разработчик. Он - основная рабочая сила в команде, в среднем в компаниях на них приходится около 80% всех задач. Если junior делает что-то работающее, то задача middle - не просто сделать, "чтобы работало", но и выполнить свою её в оптимальный срок и качественно. Middle-разработчику чётко говорим, что нужно сделать и можно быть уверенным, что он это выполнит.

Пример задачи для middle: создать метакласс для реализации фабрик. Упрощённый вариант решения:

from typing import Union, List, Dict, Any

from faker import Faker
from app import db
from app.models import User


class ExceptionBeforeCreate(Exception):
   pass


class ExceptionAfterCommit(Exception):
   pass


class ExceptionBeforeCommit(Exception):
   pass


class ErrorCreateObject(Exception):

   def __init__(self, model, description, field_name: str = ''):
       self.model = model
       self.message = description
       self.field_name = field_name
       self.description = description
       super().__init__(self.message)


class BaseFactory:
   class Meta:
       model = None

   data = {}

   def __new__(cls, *args, **kwargs) -> Union[List[Meta.model], Meta.model]:
       new_kwargs = dict()
       new_kwargs.update(kwargs)
       fixture_data = cls.data
      
       for name, val in fixture_data.items():
           if name not in new_kwargs:
               new_kwargs[name] = val()

       try:
           new_kwargs = cls.before_create(**new_kwargs)
       except ExceptionBeforeCreate:
           pass
       new_object = cls.Meta.model(**new_kwargs)
       new_object.save(commit=False, session=db.session)

       try:
           cls.before_commit(new_object)
       except ExceptionBeforeCommit:
           pass

       db.session.commit()

       try:
           cls.after_commit(new_object, kwargs=kwargs)
       except ExceptionAfterCommit:
           pass

       db.session.commit()
       return new_object

   @classmethod
   def before_create(cls, **kwargs) -> Dict:
       """
       Executes logic before the factory starts
       :param kwargs:
       :return: named parameters for object creation
       """
       raise ExceptionBeforeCreate

   @classmethod
   def before_commit(cls, result_data: Union[List[Meta.model], Meta.model]) -> None:
       """
       Executes logic after the object is created, but before the commission in the database
       :return:
       """
       raise ExceptionBeforeCommit

   @classmethod
   def after_commit(cls, result_data: Union[List[Meta.model], Meta.model], kwargs: dict = None,) -> None:
       """
       Executes logic after data commit
       :return:
       """
       raise ExceptionAfterCommit


fake = Faker()


class UserFactory(BaseFactory):
   """
   Factory for creating users
   """
   class Meta:
       model = User

   data = {
       'first_name': lambda: fake.first_name()[0:20].title(),
   }

   @classmethod
   def before_create(cls, **kwargs) -> Dict[str, Any]:
       data_for_create_user = dict()
       data_for_create_user = cls.set_first_name(data_for_create_user, kwargs)
       return data_for_create_user

   @classmethod
   def set_first_name(cls, data_for_create_user: Dict, kwargs: Dict) -> Dict:
       name_field: str = 'first_name'
       max_len_str: int = 20
       value = kwargs.get(name_field)

       if not value:
           raise ErrorCreateObject(User, 'First name required', name_field)

       value = str(value)
       if len(value) > max_len_str:
           raise ErrorCreateObject(User, 'The first name must be no more than 20 characters long.', name_field)

       data_for_create_user[name_field] = value

       return data_for_create_user

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

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

Нужно хранить иерархическую структуру сотрудников организации. При необходимости должно быть возможно: 

  1. максимально быстро выгрузить всю структуру руководителей конкретного сотрудника;

  2. максимально быстро выгрузить всех подчинённых конкретного руководителя (не только прямых подчинённых).

Также стоит учитывать, что в данном примере используется реляционная СУБД, например, PostgreSQL.

При решении данной задачи senior может прийти к нескольким вариантам:

  1. Добавить в продукт графовую базу данных.

  2. Делать рекурсивные запросы в текущей БД при минимальных затратах на разработку сложного функционала.

  3. Реализовать специальные алгоритмы, которые могут решить данную задачу в рамках РСУБД (реляционной СУБД). Например, вложенные множества.

На каких этапах разработки продукта подключаются кодеры разных уровней?

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

В зависимости от стадии развития жизненного цикла продукта, потребности в разработчиках отличается:

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

Разработка. Создание MVP (minimum viable product - минимально жизнеспособный продукт). На этом этапе закладывается ядро продукта. Конечно, наши читатели могут сказать, что MVP нужно выкидывать и всё писать заново и правильно, но сколько вы видели случаев, когда бизнес так делал? “Ничего не бывает настолько постоянным, как временное”, в случае разработки это высказывание ну очень актуально. И именно поэтому здесь нужны senior-разработчики, которые с очень высокой степенью вероятности сразу все сделают правильно. Если нанять специалиста с более низкой квалификацией, то, скорее всего, потом придётся переписывать большую часть кодовой базы проекта.

Наш собственный кейс - сеньоры проделали львиную часть работы в разработке одного сложного продукта - платформы для проведения торгов по товарам/услугам в реальном времени между b2b, b2c, c2b и т.д. Они заложили в фундамент важные свойства availability (доступность), performance (производительность) и modifiability (модифицируемость). Ну а все остальное достроили миддлы с джуниорами.

Выпуск продукта на рынок. Стадия перехода из MVP в production - в этот момент количество задач начинает расти. Данные задачи в будущем будут частью core составляющей продукта и для их реализации желательно искать senior-разработчиков, которые смогут заранее заложить качественную архитектуру. К сожалению, здесь есть одна проблема. Дело в том, чтобы найти одного хорошего senior-разработчика, нужно потратить не менее 2-3 месяцев. Но выход есть. Так, если в команде уже есть один или два сильных разработчика, то под их начало можно привлекать middle-разработчиков, которые закроют потребность на этой стадии.

Рост продаж. Стадия быстрого роста продукта. Тут впервые сталкиваемся с highload. Если заложили подходящий фундамент в виде продуманной архитектуры, соответствующей НФТ (не функциональным требованиям), то можем усилить команду разработчиками уровня middle. В противном случае у команды будут бессонные ночи.

Зрелость (насыщение рынка). К этому времени появляется много задач по техническому долгу плюс идёт оптимизация ресурсов. Появляется возможность взять на обучение разработчиков уровня junior и вырастить их под свой стек и продукт.

Но это картинка идеального мира. В реальности senior-разработчиков часто подменяют middle-разработчиками из-за малых бюджетов, сроков, отсутствия опытных ревьюеров, способных найти подходящих senior’ов.

Завершая статью, отмечу, что за прошедшие несколько лет разрыв в плане знаний/скиллов между разными категориями если увеличился, то не сильно. Что гораздо важнее - значительно усилились требования ко всем разработчикам. Если рассматривать juinior’а, то пять лет назад можно было знать только базовую часть языка без различных фреймворков, баз данных и т.д. Сейчас же с этими знаниями тяжело даже попасть на должность стажёра куда-либо.

Комментарии (18)


  1. saipr
    19.04.2022 22:29

    Начнем с того, что должен знать junior, middle и senior

    далее по тексту.


    А вот чему учили нас в 70-х годах прошлого столетия:


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

    image


    А здесь про Python.


    1. lair
      20.04.2022 01:24
      +11

      А вот чему учили нас в 70-х годах прошлого столетия:

      Некоторые вещи все-таки устаревают. Романтизация профессий в том числе.


      1. saipr
        20.04.2022 09:34
        -2

        Некоторые вещи все-таки устаревают. Романтизация профессий в том числе.

        Без романтики, в такой профессии как программирование, никак нельзя, в противном случае это просто кодирование!


        1. lair
          20.04.2022 14:15
          -1

          Угу, а врач без романтики становится медбратом, да?


          Можно, можно в программировании без романтики. Я вот без нее работаю, а кодером так и не стал, и не планирую.


          1. saipr
            20.04.2022 15:14

            Врач не творит, а лечит! И я надеюсь делает это хорошо.
            Медбрат и врач это две разные профессии.


            Кстати, архитектору без романтики должно быть, если не тяжело, то тоскливо.


            1. lair
              20.04.2022 15:15

              Врач не творит, а лечит!

              Программист не творит, а решает задачи. И, я надеюсь, делает это хорошо.


              Кстати, архитектору без романтики должно быть, если не тяжело, то тоскливо.

              (Конкретному) архитектору без романтики прекрасно, пока есть интересные задачи.


              1. saipr
                20.04.2022 15:26

                Конкретному) архитектору без романтики прекрасно, пока есть интересные задачи.

                Значит романтик тот, кто для вас поставил задачу. Но и вы РОМАНТИК, раз по достоинству оценили как интересную поставленную вам задачу. Удачи вам. Без романтики скучно жить на этом свете!


                P.S. Я программист с 50-летним стажем и всегда творил и поставленную задачу пытался решить красиво. Посмотрите на математику, сколько в ней всего красивого. А в архитектуре!!!


                1. lair
                  20.04.2022 15:31

                  Значит романтик тот, кто для вас поставил задачу.

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


                  Но и вы РОМАНТИК, раз по достоинству оценили как интересную поставленную вам задачу.

                  Чтобы оценить задачу, как интересную, нужно быть романтиком? Тогда и кодер — романтик. Вообще, любой хоть сколько-нибудь увлеченный своим делом — романтик.


                  Я программист с 50-летним стажем и всегда творил и поставленную задачу пытался решить красиво.

                  Я боюсь, у нас с вами разное представление о красоте. Для меня, если мы говорим о прикладных задачах, form follows function.


                  А в архитектуре!!!

                  У меня вот за окном стоят весьма уродливые панельные многоэтажки. Их не архитектор проектировал?


                  1. saipr
                    20.04.2022 16:28

                    Не вижу ничего романтичного в "нашей системе необходимо импортировать банковские транзакции".

                    Так вы занимаетеся нелюбимым делом!


                    Тогда и кодер — романтик. Вообще, любой хоть сколько-нибудь увлеченный своим делом — романтик.

                    А вы этого не знали?!


                    У меня вот за окном стоят весьма уродливые панельные многоэтажки. Их не архитектор проектировал?

                    Архитектор! И он решал очень нужную и важную задачу:


                    После Великой Отечественной войны размер разрушений на территории СССР был колоссален, лишилось крова более 30 млн. человек, примерно, каждый седьмой по стране. Чернигов, Севастополь, Великие Луки, Белгород были разрушены полностью. В Сталинграде, Минске, Курске, Новгороде и многих других городах было разрушено более 90% зданий. В землянках оказались миллионы наших граждан. Строительство бараков было вынужденной и временной мерой как по расселению оставшихся без крова людей, так и по обеспечению жильем людей, прибывающих на строительство новых заводов. Так было и в Чебоксарах при строительстве Чебоксарского завода тракторных запасных частей.

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


                    1. lair
                      20.04.2022 16:34

                      Так вы занимаетеся нелюбимым делом!

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


                      А вы этого не знали?!

                      Нет, не знал, и продолжаю считать, что это утверждение лишено смысла.


                      Архитектор! И он решал очень нужную и важную задачу:

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


                      Суть в том, что они уродливые. В них нет красоты. Но они решают задачу, и этого достаточно.


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


      1. zeleniy
        20.04.2022 10:07

        А разве сейчас не романтизируется: умный, проницательный, работает удалённо в свободном графике, сидя под пальмой на Бали. И картинку ещё какую-нибудь моднейшую, а-ля вот как там всё загадочно: https://shkola-liderov.ru/obuchenie/programmirovanie/bigbanner.jpg


        1. lair
          20.04.2022 14:16

          работает удалённо в свободном графике, сидя под пальмой на Бали

          Что романтичного в свободном графике? Это уже не романтизация, это просто реклама профессии.


          умный, проницательный

          А вот проницательности я уже давно в эпитетах программистов не видел.


          1. zeleniy
            20.04.2022 14:49

            А что романтичного вы нашли в аккуратности бухгалтера? )


            1. lair
              20.04.2022 14:53

              Ничего. Но там еще и было:


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

              Ну и автор комментария выше сам подтвердил, что "без романтики [...] никак нельзя".


      1. FatherYan
        20.04.2022 12:18

        Ну не то чтобы устаревают, а скорее приближаются к жизненным реалиям. Цитата из Ершова из серии "Лучше быть молодым, богатым и здоровым, чем старым бедным и больным". Конечно было бы здорово если бы все программисты были такими. Но таковых гениев в отрасли и 1% не наберется и массово взяться им неоткуда. Так что вводим более узкую специализацию, применяем различные методики разработки и т. п. дабы сделать работающий продукт имеющимися неидеальными людьми.


  1. polearnik
    20.04.2022 10:50
    +1

    джун должен 8 часов интенсивно работать мозгами а потом еще 2-3 часа самообучатся? Чет както перебор


    1. znbiz Автор
      20.04.2022 17:11
      +1

      Если учиться только на работе (хорошо если вам попался хороший наставник), то это будет очень долгий процесс перехода из позиции junior в middle разработчика.
      Как показывает опыт мало компаний готовы годами вкладываться в человека и взамен практически ничего не получать.
      Поэтому самый оптимальный вариант для роста - самообучение.


  1. FatherYan
    20.04.2022 12:06

    Мне кажется еще существенным отличием между миддлом и сеньёром является способность решить любую проблему в зоне ответственности команды в разумный срок. Сеньёр это последний рубеж. Ему некому эскалировать дальше. Думай, экспериментируй, советуйся с коллегами, спрашивай на форумах, гугли, в общем делай что хочешь, но ты обязан решить вопрос. Не смог решить? Иди к менеджменту и сообщай, что проект силами этой команды не может быть реализован. Пусть меняют требования или ищут другую команду (вдруг найдется более крутой сеньёр, но это маловероятно).