Tôi thực sự quan tâm đến các xu hướng mà chúng tôi thấy trong thị trường việc làm kỹ sư phần mềm. Đôi khi thật khó để kể một câu chuyện chính xác và chặt chẽ về những gì đang xảy ra bởi vì nó diễn ra quá nhanh và rất ít người đang thu thập dữ liệu về vấn đề này.
Ví dụ: đây là một số câu hỏi mà tôi muốn biết câu trả lời:
Tôi đã tổng hợp tất cả các câu trả lời về việc làm của nhà phát triển trong 9 năm qua của cuộc khảo sát Stack Overflow để bắt đầu có thể trả lời một số câu hỏi này. Nếu bạn tò mò về triển vọng việc làm cho các nhà phát triển , hy vọng, đây là dữ liệu hữu ích.
Tất cả các con số trong bảng đại diện cho phần trăm người tham gia khảo sát đã tự nhận mình là một loại công việc nhất định.
Các câu hỏi mà SO đặt ra đã thay đổi trong nhiều năm, vì vậy chúng ta nên hiểu điều đó bằng một hạt muối khổng lồ.
Tôi đã bình thường hóa các câu trả lời. Ví dụ: "nhà phát triển, back-end" và "back-end web developer" mà tôi đã nhóm lại thành "phụ trợ".
Tràn ngăn xếp cho phép mọi người chọn 0-nhiều chức danh sau năm 2015, trước đó, có vẻ như họ bị giới hạn ở một.
Trong một số năm, các nhà phát triển có nhiều lựa chọn công việc hơn để lựa chọn.
Tôi đã vứt bỏ rất nhiều loại công việc lạc đề như "nhà phát triển dịch vụ doanh nghiệp" và "quan chức được bầu".
Đây chỉ là dữ liệu Stack Overflow, vì vậy nó bị sai lệch bởi quy mô cơ sở người dùng của họ mỗi năm.
Điều đó nói rằng, chúng ta hãy đi vào dữ liệu. Tôi sẽ bỏ tập lệnh mà tôi đã viết để tạo dữ liệu tổng hợp cũng như liên kết đến dữ liệu thô ở cuối bài viết này.
năm | đầy đủ ngăn xếp | mặt trước | phụ trợ |
---|---|---|---|
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 |
Năm 2020 | 42.08 | 28,38 | 42,24 |
2021 | 39.42 | 21,85 | 34,84 |
2022 | 39,17 | 21,72 | 36,99 |
Năm 2013, tỷ lệ nhà phát triển "front-end" so với nhà phát triển "full-stack" là 15/85, trong khi tỷ lệ nhà phát triển "back-end" so với nhà phát triển "full-stack" là 24/76.
Xu hướng "nhiều ngăn xếp hơn, ít chuyên môn hóa hơn" tiếp tục trong toàn bộ dữ liệu mười năm. Điều quan trọng cần lưu ý là vào năm 2017/2018, cuộc khảo sát đã thay đổi đáng kể, đó là lý do tại sao chúng tôi thấy sự thay đổi lớn về các con số.
Có vẻ hợp lý khi kết luận rằng xu hướng trong thập kỷ qua là tỷ lệ các nhà phát triển chỉ làm công việc front-end hoặc chỉ làm back-end ngày càng giảm. Ngày càng có nhiều người tăng gấp đôi với tư cách là kỹ sư full-stack.
Hãy nhớ rằng điều này cũng có thể là đã có nhiều công ty vừa và nhỏ hơn trong những năm qua. Các công ty nhỏ hơn thường yêu cầu nhiều nhà tổng quát hơn, nhưng bây giờ tôi chỉ đoán.
Tỷ lệ kỹ sư front-end / back-end vẫn khá nhất quán, với số lượng kỹ sư back-end ít hơn hai lần so với kỹ sư front-end.
Điều này thực sự làm tôi ngạc nhiên, tôi đã mong đợi tỷ lệ giữa các kỹ sư đầu cuối và các kỹ sư phụ trách sẽ gần hơn trong suốt nhiều năm.
năm | phụ trợ | DevOps | ops |
---|---|---|---|
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 |
Năm 2020 | 42,24 | 10,51 | 13.11 |
2021 | 34,84 | 9,75 | 10,82 |
2022 | 36,99 | 13,2 | 11,8 |
Trong kịch bản của mình, tôi đã cố gắng chia nhiều vai trò "hoạt động truyền thống" thành danh mục "hoạt động" và nội dung "DevOps" thành vai trò "DevOps". Ví dụ: "SRE" tôi đã coi là "DevOps", trong khi "quản trị viên hệ thống" là "ops".
Chuyện quái gì đã xảy ra vào năm 2017? Dữ liệu trung thực có vẻ như bị hỏng. Tôi đã tìm hiểu dữ liệu theo cách thủ công vì theo trang web , họ khẳng định 24% nhà phát triển web cho biết họ đã trở lại và 75% người được hỏi khẳng định là nhà phát triển web.
Vào lúc này, đối với tôi như thể họ phải có một số vòng loại với những con số đó bởi vì nó không cộng dồn vào cuối của tôi. Tôi sẽ loại trừ năm 2017 khỏi phân tích của mình trong phần diễn giải.
DevOps dường như đang chiếm được chỗ dựa trên các hoạt động truyền thống. Vào năm 2013, không ai tự nhận mình là người "DevOps", nhưng vào năm 2020 và 2021, các con số trông rất giống nhau.
Cần phải chỉ ra rằng vào năm 2016, con số DevOps thực sự lu mờ con số "ops" trong một năm. Dự đoán tốt nhất của tôi là năm 2016 là khoảng thời gian nhiều công ty bắt đầu đơn giản đổi thương hiệu cho các đội "hoạt động" của họ thành các đội "DevOps" để trông thật bắt mắt.
Thật khó để quan tâm quá nhiều đến những con số này vì DevOps chủ yếu được thực hiện sai theo quan điểm của tôi. Tôi không tin rằng chức danh "hoạt động" và chức danh "DevOps" đều khác nhau ở hầu hết các công ty.
"DevOps" dường như có xu hướng giảm ít nhất trong những năm gần đây, trên thực tế, nó đã có một bước nhảy vọt tốt đẹp vào năm 2022. Tuy nhiên, nếu bạn xem xét "DevOps" và "ops" cùng nhau, thì danh mục này vẫn có xu hướng giảm một chút.
Điều thú vị là "ops" đã có xu hướng giảm ngay từ đầu, trong khi "back-end" có xu hướng tăng cho đến năm 2016 khi xu hướng đảo ngược và nó đã giảm kể từ đó.
Lúc đầu, tôi cho rằng chúng ta chỉ đơn giản là nhìn thấy cùng một xu hướng mà chúng ta đã thấy trong phát triển web: nhiều nhà tổng quát hơn, ít chuyên gia hơn.
Tuy nhiên, tôi ngày càng nghi ngờ vì khi tôi xem xét tất cả các hạng mục công việc, tôi nhận thấy gần như tất cả chúng đều có xu hướng giảm ... điều này rõ ràng không thể xảy ra khi chúng ta đang xem xét tỷ lệ phần trăm - đó là một trò chơi có tổng bằng không.
Tôi quyết định thêm một phần mới vào kịch bản của mình để đào sâu hơn. Tôi đã tính toán xem trung bình mỗi người tham gia khảo sát yêu cầu bao nhiêu công việc và nhận được dữ liệu này:
năm | phụ trợ | DevOps | ops | 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 |
Năm 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 |
Có vẻ như từ năm 2013-2015, các nhà phát triển đã bị hạn chế chỉ gửi một câu trả lời duy nhất, điều này giúp giải thích cho những con số siêu thấp. Tuy nhiên, từ năm 2019 đến năm 2021, số lượng công việc trung bình trên mỗi người dùng đã giảm xuống , điều này trái ngược với lý thuyết "những người theo chủ nghĩa tổng quát hơn".
Cũng cần phải chỉ ra rằng khi nhiều năm trôi qua, Stack Overflow thực sự đã thêm nhiều danh mục chuyên biệt hơn, mà sau đó tôi đã tự do nhóm thành các nhóm rộng hơn này.
Vì vậy, thực sự có bằng chứng tốt cho thấy các nhà phát triển đang chuyên môn hóa nhiều hơn, hoặc ít nhất là có nhiều cách khả thi hơn để một người có thể chuyên môn hóa.
Điều đó nói rằng, ngay cả sau khi xem xét dữ liệu này, tôi nghĩ rằng vẫn có một trường hợp tốt được đưa ra là các nhà phát triển back-end sẽ ngày càng làm nhiều công việc "DevOps" hơn , đặc biệt là tại các công ty nhỏ hơn.
năm | type_data_science | data_engineer | phụ trợ |
---|---|---|---|
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 |
Năm 2020 | 6.19 | 5,8 | 42,24 |
2021 | 5.12 | 5 | 34,84 |
2022 | 4,67 | 4,91 | 36,99 |
Thật thú vị với tôi rằng kỹ thuật dữ liệu chỉ thực sự bắt đầu xuất hiện trong dữ liệu khảo sát vào năm 2019. Cho đến lúc đó, tôi đoán các kỹ sư và nhà khoa học dữ liệu back-end đã nuốt chửng vai trò đó. Chuyên ngành mới đó chắc chắn rất thú vị.
Máy học đã hoàn toàn phát triển trong thập kỷ qua, nhưng có vẻ như đã có một chút "bong bóng cường điệu" vào năm 2017?
Tôi đã nói về các diễn giải cá nhân của mình liên quan đến dữ liệu mà tôi thấy thú vị nhất, nhưng đây là tất cả dữ liệu tôi đã tổng hợp để bạn có thể tự kiểm tra:
năm | avg_jobs_per_user | đầy đủ ngăn xếp | mặt trước | phụ trợ | DevOps | ops | di động | máy tính để bàn | nhúng vào | khoa học dữ liệu | data_engineer | trò chơi | ban quản lý | QA | giáo dục | thiết kế | nhà phân tích | nhà tiếp thị | phớt lờ |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
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 |
Năm 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 |
Đây là liên kết đến dữ liệu CSV thô trên Stack Overflow.
Đây là tập lệnh Python đầy đủ mà tôi đã sử dụng để xử lý các con số. Xin lỗi vì mã cẩu thả, tôi đã không dành nhiều thời gian cho mã.
Phần thú vị nhất của script có lẽ là hàm get_mapped_job
ở gần cuối, đó là nơi tôi tổng hợp tất cả các loại công việc được báo cáo bởi người dùng tràn ngăn xếp thành một số ít mà tôi đưa vào biểu đồ.
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()
Cũng được xuất bản tại đây