Взгляд на тенденции в работе разработчиков: метаанализ опросов Stack Overflow

Взгляд на тенденции в работе разработчиков: метаанализ опросов Stack Overflow

25 октября 2022 г.

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

Например, вот несколько вопросов, на которые я хотел бы получить ответ:

* Означает ли «DevOps» и более широкое использование облака меньшее количество традиционных рабочих мест? * Означают ли такие вещи, как Firebase и Supabase, меньше внутренних заданий? * Означают ли такие вещи, как попутный ветер, меньше дизайнеров? * Мы переходим на более специализированные или более универсальные роли? * Люди все еще специализируются на администраторах баз данных?

Я собрал все ответы о занятости разработчиков из опросов Stack Overflow за последние 9 лет, чтобы начать отвечать на некоторые из этих вопросов. Если вам интересны перспективы работы для разработчиков, надеюсь, это полезные данные.

Во-первых, примечание к данным

  1. Все цифры в таблицах представляют собой процент участников опроса, которые определили себя как работу определенного типа.

2. Вопросы, которые задает SO, с годами изменились, поэтому мы должны воспринимать это с большой долей скептицизма.

3. Я нормализовал ответы. Например, "разработчик, бэкэнд" и "бэкэнд веб-разработчик" я сгруппировал как "бэкэнд".

4. После 2015 года переполнение стека позволяло людям выбирать 0-много наименований должностей, до этого они, по-видимому, ограничивались одним.

5. В некоторые годы у разработчиков было больше вариантов работы.

6. Я выбросил много не относящихся к теме вакансий, таких как "разработчик корпоративных услуг" и "выборное должностное лицо".

7. Это только данные Stack Overflow, поэтому они смещены из-за размера их пользовательской базы каждый год.

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

Веб-тенденции: полный стек, интерфейс и серверная часть

| год | полный стек | интерфейс | бэкэнд | |----|----|----|----| | 2013 | 24,5 | 4.31 | 7,88 | | 2014 | 25,72 | 5.02 | 9.3 | | 2015 | 25,93 | 4,76 | 8.07 | | 2016 | 37,88 | 5.13 | 10,82 | | 2017 | 51.05 | 2,47 | 5.08 | | 2018 | 44,87 | 35,22 | 53,92 | | 2019 | 47,5 | 29,98 | 45,75 | | 2020 | 42.08 | 28.38 | 42,24 | | 2021 | 39,42 | 21,85 | 34,84 | | 2022 | 39.17 | 21,72 | 36,99 |

В 2013 г. соотношение между разработчиками внешнего интерфейса и разработчиками полного стека составляло 15 / 85, а соотношение разработчиков бэкенда и разработчиков полного стека — 24 / 76.< /p>

Тенденция «больше полного стека, меньше специализации» сохраняется на протяжении всех десяти лет данных. Важно отметить, что в 2017/2018 г. опрос резко изменился, поэтому мы наблюдаем большие изменения в цифрах.

Интерпретация №1

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

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

Интерпретация № 2

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

Меня это на самом деле удивило, я ожидал, что с годами соотношение между фронтенд- и бэкенд-инженерами будет ближе.

Тенденции в области ИТ-операций: серверная часть, DevOps и традиционные операции

| год | бэкэнд | DevOps | операции | |----|----|----|----| | 2013 | 7,88 | 0 | 2,96 | | 2014 | 9.3 | 1,61 | 2,85 | | 2015 | 8.07 | 1,23 | 1,77 | | 2016 | 10,82 | 1,92 | 1,79 | | 2017 | 5.08 | 7,81 | 13,66 | | 2018 | 53,92 | 9,66 | 18.33 | | 2019 | 45,75 | 11.43 | 15,93 | | 2020 | 42,24 | 10.51 | 13.11 | | 2021 | 34,84 | 9,75 | 10,82 | | 2022 | 36,99 | 13.2 | 11,8 |

В своем сценарии я попытался разделить больше "традиционных ролей" на категорию "эксплуатация", а "DevOps" - на роль "DevOps". Например, «SRE» я рассматривал как «DevOps», а «системный администратор» — как «ops».

Предупреждение о данных за 2017 год

Что, черт возьми, произошло в 2017 году? Честно говоря, данные просто кажутся сломанными. Я просмотрел данные вручную, потому что, согласно веб-сайту, они утверждают, 24% веб-разработчиков заявили, что они занимаются бэкендом, а 75% респондентов заявили, что являются веб-разработчиками.

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

Интерпретация 1

Похоже, что DevOps вытесняет традиционные операции. В 2013 году никто не называл себя специалистом по DevOps, но к 2020 и 2021 году цифры выглядят очень одинаково.

Стоит отметить, что в 2016 году показатели DevOps фактически затмили показатели «операций» за один год. Насколько я понимаю, в 2016 году многие компании начали просто переименовывать свои «операционные» команды в «DevOps», чтобы выглядеть круто.

Трудно обращать внимание на эти цифры, потому что, по моему мнению, DevOps в основном выполняется неправильно. . Я не верю, что в большинстве компаний названия "эксплуатация" и "девопс" сильно различаются.

Интерпретация 2

Категория DevOps, по-видимому, в последние годы меньше всего снижается, на самом деле, в 2022 году произошел хороший скачок. Однако, если вы посмотрите на "DevOps" и "операции" вместе, то категория по-прежнему немного снижается.

Интересно, что с самого начала «эксплуатация» падала, а «бэкэнд» — вверх до 2016 года, когда тенденция изменилась, и с тех пор она снижается.

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

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

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

| год | бэкэнд | DevOps | операции | avg_jobs_per_user | |----|----|----|----|----| | 2013 | 7,88 | 0 | 2,96 | 1 | | 2014 | 9.3 | 1,61 | 2,85 | 1 | | 2015 | 8.07 | 1,23 | 1,77 | 1 | | 2016 | 10,82 | 1,92 | 1,79 | 1,89 | | 2017 | 5.08 | 7,81 | 13,66 | 2,48 | | 2018 | 53,92 | 9,66 | 18.33 | 2,79 | | 2019 | 45,75 | 11.43 | 15,93 | 2,84 | | 2020 | 42,24 | 10.51 | 13.11 | 2,59 | | 2021 | 34,84 | 9,75 | 10,82 | 2.21 | | 2022 | 36,99 | 13.2 | 11,8 | 2.27 |

Похоже, что с 2013 по 2015 год разработчикам разрешалось отправлять только один ответ, что помогает объяснить очень низкие цифры. Однако с 2019 по > 2021 года среднее количество рабочих мест на одного пользователя снижалось, что противоречит теории "большего числа универсалов".

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

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

Тем не менее, даже после просмотра этих данных я думаю, что все еще есть веские основания утверждать, что back-end разработчики будут выполнять все больше и больше задач DevOps, особенно в небольших компаниях.

Тенденции данных: наука о данных, инженерия данных и серверная часть

| год | type_data_science | data_engineer | бэкэнд | |----|----|----|----| | 2013 | 0 | 0 | 7,88 | | 2014 | 0 | 0 | 9.3 | | 2015 | 2.12 | 0,69 | 8.07 | | 2016 | 3,83 | 0,7 | 10,82 | | 2017 | 9.14 | 0 | 5.08 | | 2018 | 7.17 | 0 | 53,92 | | 2019 | 7.27 | 6,55 | 45,75 | | 2020 | 6.19 | 5,8 | 42,24 | | 2021 | 5.12 | 5 | 34,84 | | 2022 | 4,67 | 4,91 | 36,99 |

Интерпретация

Мне очень интересно, что инженерия данных действительно начала появляться в данных опросов только в 2019 году. До этого я предполагаю, что инженеры по обработке данных и специалисты по обработке данных поглотили эту роль. Эта новая специализация, безусловно, интересна.

Машинное обучение значительно выросло за последнее десятилетие, но, похоже, в 2017 году образовался небольшой «пузырь хайпа»?

Остальные данные

Я говорил о своих личных интерпретациях данных, которые мне показались наиболее интересными, но вот все данные, которые я собрал, чтобы вы могли проверить их самостоятельно:

| год | avg_jobs_per_user | полный стек | интерфейс | бэкэнд | DevOps | операции | мобильный | рабочий стол | встроенный | наука_данных | data_engineer | игра | управление | контроль качества | образование | дизайн | аналитик | маркетолог | игнорировать | |----|----|----|----|----|----|----|----|----|---- |----|----|----|----|----|----|----|----|----|---- | | 2013 | 1 | 24,5 | 4.31 | 7,88 | 0 | 2,96 | 6,48 | 9,53 | 2.16 | 0 | 0 | 0 | 7,49 | 0 | 0 | 0 | 0 | 0 | 34,7 | | 2014 | 1 | 25,72 | 5.02 | 9.3 | 1,61 | 2,85 | 7,57 | 9.43 | 2,42 | 0 | 0 | 0 | 5.9 | 0 | 0 | 0 | 0 | 0 | 30.18 | | 2015 | 1 | 25,93 | 4,76 | 8.07 | 1,23 | 1,77 | 7,28 | 6,65 | 2.33 | 2.12 | 0,69 | 0,63 | 1,44 | 0,63 | 0 | 0,57 | 0 | 0,23 | 35,66 | | 2016 | 1,89 | 37,88 | 5.13 | 10,82 | 1,92 | 1,79 | 7.39 | 6.05 | 2,26 | 3,83 | 0,7 | 0,52 | 10.04 | 0,68 | 0 | 0,59 | 1.02 | 0,21 | 98,65 | | 2017 | 2,48 | 51.05 | 2,47 | 5.08 | 7,81 | 13,66 | 16,2 | 20,3 | 6,52 | 9.14 | 0 | 3,37 | 0,5 | 2,44 | 1,42 | 3,94 | 3,69 | 0,3 | 100 | | 2018 | 2,79 | 44,87 | 35,22 | 53,92 | 9,66 | 18.33 | 19.02 | 15,99 | 4,87 | 7.17 | 0 | 4.7 | 7,99 | 6.27 | 3,68 | 12.16 | 7,65 | 1.13 | 26,63 | | 2019 | 2,84 | 47,5 | 29,98 | 45,75 | 11.43 | 15,93 | 16.54 | 19.48 | 8.15 | 7.27 | 6,55 | 4,99 | 6.34 | 7.15 | 10.18 | 10.33 | 7.08 | 1.1 | 28.37 | | 2020 | 2,59 | 42.08 | 28.38 | 42,24 | 10.51 | 13.11 | 14,71 | 18.28 | 7,37 | 6.19 | 5,8 | 4.33 | 5,54 | 6.12 | 8,67 | 8,25 | 6.24 | 1 | 30.18 | | 2021 | 2.21 | 39,42 | 21,85 | 34,84 | 9,75 | 10,82 | 11,74 | 13.23 | 5.51 | 5.12 | 5 | 2,53 | 6.37 | 4.33 | 5,56 | 5,53 | 4,54 | 0,76 | 34,51 | | 2022 | 2,27 | 39.17 | 21,72 | 36,99 | 13.2 | 11,8 | 10.42 | 13.03 | 5,35 | 4,67 | 4,91 | 2,51 | 10.44 | 4.23 | 5,78 | 5.14 | 4.37 | 0,71 | 32.06 |

Необработанные данные CSV

Вот ссылка на необработанные данные CSV в Stack Overflow.

Мой сценарий

Вот полный скрипт Python, который я использовал для обработки чисел. Извините за неряшливость кода, я не тратил кучу времени на код.

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

import csv

outpath = "csv/out.csv"

type_devops = "devops"
type_ops = "ops"
type_backend = "backend"
type_frontend = "frontend"
type_mobile = "mobile"
type_fullstack = "fullstack"
type_desktop = "desktop"
type_embedded = "embedded"
type_data_science = "data_science"
type_ignore = "ignore"
type_management = "management"
type_education = "education"
type_design = "design"
type_marketer = "marketer"
type_data_engineer = "data_engineer"
type_game = "game"
type_analyst = "analyst"
type_qa = "qa"


def main():
    files = [
        (2013, [6]),
        (2014, [6]),
        (2015, [5]),
        (2016, [8, 9, 10]),
        (2017, [14, 15, 16, 17]),
        (2018, [9]),
        (2019, [12]),
        (2020, [13]),
        (2021, [11]),
        (2022, [11]),
    ]

    out_dict = {}
    jobs_per_user_dict = {}

    for f_tup in files:
        counts = {}
        path = f"csv/{f_tup[0]}.csv"
        print(f"generating report for {path}")
        out_dict[f_tup[0]]: {}
        with open(path, "r") as csvfile:
            rows = csv.reader(csvfile, delimiter=",")
            count = 0
            rows_cpy = []
            jobs_per_user = []
            for row in rows:
                count += 1
                rows_cpy.append(row)
            for row in rows_cpy:
                try:
                    jobs = get_jobtext_from_cells(f_tup[1], row)

                    mapped_jobs = set()
                    for job in jobs:
                        mapped_jobs.add(get_mapped_job(job))
                    jobs_per_user.append(mapped_jobs)
                    for mapped_job in mapped_jobs:
                        if mapped_job not in counts:
                            counts[mapped_job] = 0
                        counts[mapped_job] += 1
                except Exception as e:
                    print(e)

            avg_jobs_per_user = 0
            for user_jobs in jobs_per_user:
                avg_jobs_per_user += len(user_jobs)
            jobs_per_user_dict[f_tup[0]] = round(
                avg_jobs_per_user / len(jobs_per_user), 2
            )

            for job in counts:
                counts[job] /= count
                counts[job] *= 100
                counts[job] = round(counts[job], 2)
            out_dict[f_tup[0]] = counts

    write_out(out_dict, jobs_per_user_dict)


def get_jobtext_from_cells(indexes, row):
    if len(indexes) == 0:
        return []
    job_texts = []
    for i in indexes:
        cell = row[i]
        cell_job_texts = cell.split(";")
        job_texts += cell_job_texts
    return job_texts


def write_out(out_dict, jobs_per_user_dict):
    types = [
        type_fullstack,
        type_frontend,
        type_backend,
        type_devops,
        type_ops,
        type_mobile,
        type_desktop,
        type_embedded,
        type_data_science,
        type_data_engineer,
        type_game,
        type_management,
        type_qa,
        type_education,
        type_design,
        type_analyst,
        type_marketer,
        type_ignore,
    ]

    with open(outpath, "w") as csvfile:
        w = csv.writer(csvfile)
        w.writerow(["year", "avg_jobs_per_user"] + types)
        for year in out_dict:
            row = [year, jobs_per_user_dict[year]]
            for t in types:
                row.append(out_dict[year][t] if t in out_dict[year] else 0)
            w.writerow(row)


def get_mapped_job(job):
    job = job.lower().strip()
    if job == "":
        return type_ignore
    if job == "devops specialist":
        return type_devops
    if job == "designer":
        return type_design
    if job == "c-suite executive":
        return type_management
    if job == "analyst or consultant":
        return type_analyst
    if job == "back-end developer":
        return type_backend
    if job == "windows phone":
        return type_mobile
    if job == "i don't work in tech":
        return type_ignore
    if job == "growth hacker":
        return type_marketer
    if job == "desktop developer":
        return type_desktop
    if job == "analyst":
        return type_analyst
    if job == "executive (vp of eng., cto, cio, etc.)":
        return type_management
    if job == "mobiledevelopertype":
        return type_mobile
    if job == "engineer, data":
        return type_data_engineer
    if job == "graphics programmer":
        return type_game
    if job == "systems administrator":
        return type_ops
    if job == "developer, game or graphics":
        return type_game
    if job == "desktop software developer":
        return type_desktop
    if job == "nondevelopertype":
        return type_ignore
    if job == "elected official":
        return type_ignore
    if job == "engineering manager":
        return type_management
    if job == "web developer":
        return type_fullstack
    if job == "machine learning specialist":
        return type_data_science
    if job == "data or business analyst":
        return type_analyst
    if job == "devtype":
        return type_fullstack
    if job == "response":
        return type_ignore
    if job == "developer, qa or test":
        return type_qa
    if job == "machine learning developer":
        return type_data_science
    if job == "developer, front-end":
        return type_frontend
    if job == "database administrator":
        return type_ops
    if job == "android":
        return type_mobile
    if job == "webdevelopertype":
        return type_fullstack
    if job == "blackberry":
        return type_mobile
    if job == "system administrator":
        return type_ops
    if job == "mobile developer - android":
        return type_mobile
    if job == "developertype":
        return type_fullstack
    if job == "ios":
        return type_mobile
    if job == "developer with a statistics or mathematics background":
        return type_ignore
    if job == "qa or test developer":
        return type_qa
    if job == "educator or academic researcher":
        return type_education
    if job == "engineer, site reliability":
        return type_devops
    if job == "marketing or sales professional":
        return type_marketer
    if job == "student":
        return type_ignore
    if job == "back-end web developer":
        return type_backend
    if job == "educator":
        return type_education
    if job == "front-end developer":
        return type_frontend
    if job == "developer, desktop or enterprise applications":
        return type_desktop
    if job == "senior executive/vp":
        return type_management
    if job == "occupation":
        return type_ignore
    if job == "scientist":
        return type_ignore
    if job == "developer, full-stack":
        return type_fullstack
    if job == "graphic designer":
        return type_design
    if job == "developer, embedded applications or devices":
        return type_embedded
    if job == "embedded application developer":
        return type_embedded
    if job == "quality assurance":
        return type_qa
    if job == "graphics programming":
        return type_game
    if job == "senior executive (c-suite, vp, etc.)":
        return type_management
    if job == "it staff / system administrator":
        return type_ops
    if job == "business intelligence or data warehousing expert":
        return type_data_engineer
    if job == "full stack web developer":
        return type_fullstack
    if job == "developer, mobile":
        return type_mobile
    if job == "front-end web developer":
        return type_frontend
    if job == "desktop applications developer":
        return type_desktop
    if job == "other (please specify):":
        return type_ignore
    if job == "mobile developer":
        return type_mobile
    if job == "devops":
        return type_devops
    if job == "enterprise level services developer":
        return type_ignore
    if job == "data scientist":
        return type_data_science
    if job == "executive (vp of eng, cto, cio, etc.)":
        return type_management
    if job == "mobile developer - ios":
        return type_mobile
    if job == "game or graphics developer":
        return type_game
    if job == "which of the following best describes your occupation?":
        return type_ignore
    if job == "other":
        return type_ignore
    if job == "desktop or enterprise applications developer":
        return type_desktop
    if job == "c-suite executive (ceo, cto, etc.)":
        return type_management
    if job == "embedded applications/devices developer":
        return type_embedded
    if job == "product manager":
        return type_ignore
    if job == "mobile application developer":
        return type_mobile
    if job == "mobile developer - windows phone":
        return type_mobile
    if job == "data scientist or machine learning specialist":
        return type_data_science
    if job == "educator or academic":
        return type_education
    if job == "embedded applications or devices developer":
        return type_embedded
    if job == "quality assurance engineer":
        return type_qa
    if job == "enterprise level services":
        return type_ignore
    if job == "full-stack developer":
        return type_fullstack
    if job == "na":
        return type_ignore
    if job == "academic researcher":
        return type_education
    if job == "manager of developers or team leader":
        return type_management
    if job == "marketing or sales manager":
        return type_marketer
    if job == "developer, back-end":
        return type_backend
    if job == "full-stack web developer":
        return type_fullstack
    if job == "designer or illustrator":
        return type_design
    if job == "programmer":
        return type_ignore
    if job == "developer":
        return type_ignore
    if job == "manager":
        return type_management
    if job == "engineer":
        return type_ignore
    if job == "sr. developer":
        return type_ignore
    if job == "full stack overflow developer":
        return type_fullstack
    if job == "ninja":
        return type_ignore
    if job == "mobile dev (android, ios, wp & multi-platform)":
        return type_mobile
    if job == "expert":
        return type_ignore
    if job == "rockstar":
        return type_ignore
    if job == "hacker":
        return type_ignore
    if job == "guru":
        return type_ignore
    if job == "self_identification":
        return type_ignore
    if job == "occupation_group":
        return type_ignore
    if job == "cloud infrastructure engineer":
        return type_devops
    if job == "project manager":
        return type_management
    if job == "security professional":
        return type_ops
    if job == "blockchain":
        return type_backend
    if (
        job
        == "mathematics developers (data scientists, machine learning devs & devs with stats & math backgrounds)"
    ):
        return type_data_science
    raise Exception(f"job not mapped: {job}")


main()

Также опубликовано здесь


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE