ソフトウェア エンジニアリングの求人市場で見られる傾向に非常に興味があります。何が起こっているのかについてまとまりのある正確な物語を伝えるのが非常に難しい場合があります。なぜなら、それは非常に速く起こるためであり、問題に関するデータを収集している人はほとんどいないからです.
たとえば、次のような質問に対する答えが知りたいです。
これらの質問のいくつかに答えられるようにするために、過去 9 年間の Stack Overflow 調査から開発者の雇用に関するすべての回答を集めました。開発者の仕事の見通しに興味があるなら、うまくいけば、これは役立つデータです.
表内のすべての数値は、特定の職種を特定した調査回答者の割合を表しています。
SO からの質問は年月を経て変化してきたため、これについては大雑把に考える必要があります。
私は答えを正規化しました。たとえば、「開発者、バックエンド」と「バックエンド Web 開発者」をまとめて「バックエンド」としています。
スタック オーバーフローにより、2015 年以降、人々は 0-多数の役職を選択できるようになりました。それ以前は、1 つに制限されていたようです。
開発者が選択できる仕事の選択肢が増えた年もありました。
「エンタープライズ サービス デベロッパー」や「選出された役人」など、話題から外れた多くの職種を捨ててきました。
これは単なる 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 でした。
「よりフルスタック、より専門性を低く」という傾向は、10 年間のデータ全体を通じて継続しています。 2017/2018 年に調査が大幅に変更されたことに注意することが重要です。そのため、数字に大きな変化が見られます。
過去 10 年間の傾向として、フロントエンドの作業のみ、またはバックエンドの作業のみを行う開発者の割合が減少していると結論付けるのは妥当と思われます。フルスタックエンジニアを兼務する人が増えています。
ここ数年、中小企業が増えている可能性もあります。通常、小規模な企業にはより多くのゼネラリストが必要ですが、今は推測に過ぎません。
フロントエンド エンジニアとバックエンド エンジニアの比率はかなり安定しており、バックエンド エンジニアの数はフロントエンド エンジニアの 2 倍弱です。
これには本当に驚きました。フロントエンド エンジニアとバックエンド エンジニアの比率は年々近くなると予想していました。
年 | バックエンド | 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年、いったい何があったの?正直なところ、データは壊れているようです。 Web サイトによると、 Web 開発者の 24% がバックエンドであると述べ、回答者の 75% が Web 開発者であると主張しているため、私は手動でデータを掘り下げました。
現時点では、私の側では合計されていないため、これらの数字にはいくつかの修飾子があったに違いないように見えます.解釈の分析から 2017 年を除外します。
DevOps は、従来の ops の地位を獲得しているようです。 2013 年には、誰も「DevOps」担当者であると自認していませんでしたが、2020 年と 2021 年までに、数字は非常に類似しているように見えます。
2016 年には、DevOps の数値が 1 年間の「ops」の数値を実際に上回りました。私の推測では、2016 年は、多くの企業が単に「運用」チームを「DevOps」チームとして単に見栄えを良くするためにリブランディングし始めた頃だったと思います。
私の意見では、 DevOps はほとんど間違った方法で行われているため、これらの数値を気にしすぎることはありません。ほとんどの企業で、「ops」の肩書と「DevOps」の肩書きがまったく異なるとは思えません。
「DevOps」は、ここ数年で最も下降傾向にあるように見えます。実際、2022 年には大きく上昇しました。ただし、「DevOps」と「ops」を合わせて見ると、このカテゴリはまだ少し下降傾向にあります。
興味深いことに、「ops」は最初から下降傾向にありましたが、「back-end」は 2016 年まで上昇傾向にあり、その後下降傾向にありました。
最初は、Web 開発で見られたのと同じ傾向を単に見ているだけだと思いました。ジェネラリストが増え、スペシャリストが減りました。
しかし、私が懐疑的になったのは、すべての職種を調べたところ、ほぼすべての職種が下降傾向にあることに気づいたからです...パーセンテージを見ると、明らかにそうではありません.これはゼロサムゲームです.
さらに掘り下げるために、スクリプトに新しいセクションを追加することにしました。各調査回答者が主張している仕事の平均数を計算し、次のデータを得ました。
年 | バックエンド | 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 年にかけて、開発者は 1 つの回答のみを送信するように制限されていたようで、これが非常に低い数字の説明に役立ちます。しかし、2019 年から 2021 年にかけて、ユーザーあたりの平均求人数は減少しました。
年月が経つにつれて、スタック オーバーフローは実際により専門的なカテゴリを追加したことも指摘しておく価値があります。
したがって、実際には、開発者がより専門化しているという良い証拠があります。少なくとも、開発者が専門化できる可能性のある方法が他にもあるということです。
とはいえ、このデータを見た後でも、バックエンド開発者がますます多くの "DevOps" 作業を、特に小規模な企業で行うようになるという十分な根拠があると思います。
年 | type_data_science | データエンジニア | バックエンド |
---|---|---|---|
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 年のことです。それまでは、バックエンド エンジニアとデータ サイエンティストがその役割を飲み込んでいたと思います。その新しい専門分野は確かに興味深いものです。
機械学習は過去 10 年間で確実に成長しましたが、2017 年にはちょっとした「ハイプ バブル」があったように見えますか?
私が最も興味深いと思ったデータに関する個人的な解釈について話しましたが、自分で調べられるように集計したすべてのデータを次に示します。
年 | avg_jobs_per_user | フルスタック | フロントエンド | バックエンド | DevOps | オペレーション | モバイル | デスクトップ | 埋め込み | データサイエンス | データエンジニア | ゲーム | 管理 | QA | 教育 | デザイン | アナリスト | マーケティング担当者 | 無視 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
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 | 18.30 |
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 | 18.30 |
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 |
Stack Overflow の生の CSV データへのリンクを次に示します。
これは、数字を処理するために使用した完全な 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()
こちらにも掲載