我带的外包兄弟放弃大厂转正,薪资翻倍入职字节

大家好,我是老A

国庆节的时候,收到一位粉丝的私信求助。一来一回聊了半天,我发现了一个很多技术兄弟的通病------我们称之为「收藏夹式努力 ​」。水文看不上,只想让大佬推荐技术宝典,一旦拿到手,焦虑感削弱,宝典就在收藏夹里吃灰,下了班照样峡谷开黑。当你想督促他深入研究时,他又会用「他是大佬,我不是,我做不到 」来给自己设限,最终陷入「持续焦虑,持续躺平」的恶性循环。

这种惰性,是人之常情。但人和人之间的差距,就在于如何对抗它。这让我想起了我去年带过的一个外包兄弟,小汪。坦白说,他刚来的时候,也和这位粉丝一样,技术普通,满脸焦虑,总觉得自己不行

但他最终,靠自己的努力,挣脱了这个循环。他没有转正,却在一年后,薪资翻倍进了字节。

今天,我就把小汪的这段真实经历,以及我当时给他设计的那份「镀金计划」,毫无保留地分享出来。希望能为所有困在原地的兄弟,提供一条走得通的路。

第一幕:一个困在围城的年轻人

小汪是2023年6月份进组的,主要跟我做CRM的售卖系统,给我的第一印象是这小伙子阳光开朗,踏实肯干,不懒惰,很勤劳,基本每天都是第一个到公司(当然不是说第一个到公司就好,主要是从这点看出他很勤劳)。

小汪的技术基础还行,大概半个多月就熟悉了公司的技术基础设施和基础业务,之后就开始跟着我做项目。

他的成长速度真的很快,每天都会追着我问各种业务问题,应用问题还有代码问题,每次CR也都主动找我交流,能看的出来,他是真的很想进步,所以我也是倾尽所有的去教他带他。前半年,他工作的热情高涨,每天都像个小太阳一样,正能量满满,积极乐观的工作态度感染着周围的同学。

但是半年后,明显感觉到这个小太阳能量不足了,脸上的笑容也越来越少,察觉到这个变化,我赶紧跟他进行了一次one one交流,让我终于知道了原因所在。

小汪表示他觉得自己就是个二等公民,作为外包,他感受到了诸多不便,再努力都没用。

  • 不便一:各种权限申请搞疯掉

    小到一篇文档、一个钉钉名片、一个项目环境吧器,大到一个代码库、应用、开关、配置他通通都要经过4层以上的审批,给他的工作带来了极大的不便,过程中也倍受冷眼,比如跟某些大厂骄子申请权限,已读不回,钉了也不回的例子太多,其中的心酸只有他自己能懂。

  • 不便二:外包身份让他无法接触到核心

    虽然我带着他做项目,能教的都在教他,业务也都给他讲的明明白白,但是从不会让他接触到项目最核心的技术部分,也不会把核心开发部分交给他做(这个我要喊一句冤枉,不是不交给小汪做,是不能,我们有严格的要求核心研发必须正式员工来做,毕竟背锅也是我们自己来,所以自己做也比较放心,但是每次的CR我都会叫上小汪,让他知道这个需求的核心部分是如何实现的)。

  • 不便三:所有的需求都不会让他独立完成,都需要我出技术方案,他去执行

    小汪觉得这样很不利于他的成长,就像离不开鸡妈妈的小鸡(这里批评一下,这个比喻太不恰当了,我不是鸡妈妈😂)。后面这里我改为了他出方案,我来把关评审。

  • 不便四:所有的核心技术分享都接触不到

    小汪说他想成长,但是每次部门的核心技术分享都不会邀请他,他也不知道有哪些技术分享,这让他更加难受,想成长却没有门(这个我后面反思了,因为我们的技术分享基本都在晚上8点以后,外包同学基本6点多就下班了,所以之前我一直没好意思留下小汪,毕竟让人加班等到8点不太优雅,那次one one谈话后我每次分享都会提前告诉他

最后小汪终于道出了压在心底的话:他拼命工作、拼命学习,就是为了撕掉"二等公民"的标签,成为一个真正的"自己人"。但他抬头四顾,满眼都是绝望:"A哥,我来了一年多了,一个转正的都没见过。这条路,真的走得通吗?"

第二幕:"B面"点化------"你的目标,从一开始就错了"

听了他的话,我沉默了足足有半分钟。我不是在想怎么安慰他,我是在想,这盆冷水,到底该怎么泼下去,才不至于浇灭他眼里最后的光。

他说的这些,我何尝不知呢?别说他只来了一年多,我在公司6年了,也没见到一个外包转正的。外包转正,这本身就是一个悖论,可能性十不足一。

所以我直接告诉他了外包转正的三个"残酷真相"

  1. "HC(Headcount)隔离墙":首先外包在哪个公司都算是一种技术资源,哪里需要去哪里。其招聘成本和正式员工不在一个等级,一个部门每年的正式员工HC是很珍贵的,基本一年1-2个,所以老板和HR都想把这个名额给到一个尽可能优秀的人。那么老板如何判断一个候选人是否优秀?第一就要看学历和工作经历,基本95%的外包同学都倒在这一关了。而一个外包HC就宽松多了,老板向部门申请预算也会容易的多,所以体现在面试上也容易很多。这就是为什么外包在老板这关就很难转正的原因。
  2. "招聘标准双轨制" :坦诚地说,社招一个P6的门槛,和外包转正一个P6的门槛,是完全不同的。我们社招的时候招一个P6的标准:985/211、有大厂经历、能独立完成中型项目、对自己做过的项目完全掌握这就行了。但是如果是外包转正一个P6:那你得有极其耀眼的项目经历或者做出过什么大贡献,比如挽回了1000万资损这种。但是这两个条件对于外包同学来说,难于上青天。。。这本身就是不公平的,却是赤裸裸的现实。
  3. "价值归属的原罪":外包同学是不会自己负责一块独立的业务的,所以他在项目里做的所有业绩,在汇报时天然会归功于他的直属正式员工Leader。

最后,我看着他的眼睛,一字一句地跟他说:"小汪,记住,从今天起,别再把转正当成你唯一的目标了。那是一条官方留给你,但几乎锁死的路。你的真正出路,是把在这里的每一天,都当成一场偷师学艺。你的目标,不是留下,而是镀金后,去一片更广阔的天空!"

第三幕:镀金!从CRUD Boy到"准架构师"的技术蜕变

1. 镀金第一步:"偷"文档,找到"战场"

老A点化 :我告诉小汪,你要学会"偷师",去lark上把我们CRM系统 所有的故障复盘文档 ,全都找出来读一遍。再去看架构组的周会纪要 ,看看那些P8、P9们,到底在为什么问题而头疼 。同时多交好一些正式员工,作为资源人脉,一旦有HC可以做内推。

发现"战场": 小汪花了一周的下班时间,真的找到了一个有价值的痛点------一个半年前的P3故障 复盘文档。这个故障始于CRM系统一个用于"同步客户签约状态 "的核心接口,由于需要依次调用 "会员中心"、"订购中心"、"风控中心"、"合同中心"四个下游服务,这几个系统都是有20年以上的历史的老系统,整个链路过长,在大促高并发下,TP99延迟飙升到5秒以上,导致整个签约流程的体验很差,经常出现签约异常情况。这个问题,因为"历史悠久、无人敢动",至今只是做了限流(令牌桶),也提出了渐进式优化的方案,但是苦于业务排期压力,一直没有排上日程。

老A点评 :"镀金 "的第一心法,找到那个所有人都知道痛,但没人敢治的"病灶 "。这,就是你的战场

2. 镀金第二步:"偷"代码,找到"武器"

小汪找到了"战场",但却不知道该怎么解决。他能想到的,还是优化SQL、加缓存这些常规操作。

老A点化 :我直接把公司内另一个核心交易网关 的代码读权限,给他临时申请了一天。然后告诉他:"别看那些修修补补的代码。去看看我们最新一代的交易应用代码,看看他们是如何编排和调度多个下游微服务的。偷师他们的设计思想。"

"偷"到"圣经" :小汪在这份新代码里,第一次看到了一个完全不同的世界------基于CompletableFutureThreadPoolExecutor构建的、优雅的异步化、非阻塞的编排方案。他这才明白,高手们早就不用同步调用链这种办法了。

3. 镀金第三步:从"看懂"到"精通"的灵魂拷问

小汪看了一天的交易代码,然后兴奋地跑来找我,说他准备用CompletableFuture.allOf()来并行化那三个RPC调用。但他还没说完,我就提出了三个"B面"灵魂拷问,直接把他问住了:

第一问:你打算用什么线程池来跑这些异步任务?

小汪脱口而出:"就用CompletableFuture默认的就行吧?"

我告诉他,这就是新手和老兵的第一个分水岭 。默认的ForkJoinPool.commonPool(),就像一个顶级餐厅里那几个最牛的、做菜最快的大厨,它是为计算密集型任务设计的。

而你的RPC调用,是IO密集型任务,就像是去等一份永远不知道何时能送达的外卖。如果你让大厨去等外卖,整个厨房很快就会瘫痪。

正确的做法,是为这些IO任务,单独建立一个"服务员"线程池,让他们去等,别占用我们宝贵的大厨资源

java 复制代码
// 老A的B面架构第一课:为IO密集型任务自定义线程池
private final ThreadPoolExecutor syncExecutor = new ThreadPoolExecutor(
    20, // 核心线程数,根据QPS和下游延迟估算
    200, // 最大线程数,应对突发流量
    60L, TimeUnit.SECONDS, // 空闲线程存活时间
    new LinkedBlockingQueue<>(1000) // 队列大小,防止OOM
);

第二问:三个RPC调用,真的可以完全并行吗?

我让他把旧代码贴出来,又问了他第二个问题:"你仔细看,这三个RPC调用,真的可以完全并行吗?" 小汪看着旧代码里那句orderClient.getLastOrder(info.getOrderId()),沉默了。

他这才发现,获取"订单信息",依赖于先获取"会员信息"的结果

我告诉他,allOf是万马奔腾,适用于没有依赖关系 的并行任务。而这种需要"第一棒跑完,第二棒才能接力"的场景,你需要的是thenCompose<。这,是第二个分水岭

java 复制代码
// 老A的B面架构第二课:用thenCompose处理依赖性的异步任务
CompletableFuture<UserInfo> futureInfo = CompletableFuture.supplyAsync(...);
CompletableFuture<OrderInfo> futureOrder = futureInfo.thenCompose(info -> 
    CompletableFuture.supplyAsync(() -> orderClient.getLastOrder(info.getOrderId()), syncExecutor)
);

第三问:你准备用 thenAccept还是 thenAcceptAsync来更新数据库?

最后,我问了他第三个问题:"当所有结果都计算完,你准备用thenAccept还是thenAcceptAsync来更新数据库?" 小汪一脸茫然。

我给他讲了一个真实的"B面"血泪史:曾经一个团队,因为在回调里使用了同步的thenAccept,而回调方法里又有一个微小的锁竞争,导致在高并发下,整个异步线程池被"反向"阻塞,引发了P2故障。

这,是第三个分水岭 ------ 永远要假设你的回调逻辑也可能阻塞,用thenAcceptAsync把它也扔进线程池里去执行,做到"绝对隔离"。

4. 终极镀金:用"A面"武器,重构"B面"屎山

在我问出这三个问题,并把自定义线程池ThenCompose这两个武器的核心代码画给他看之后,小汪说他要回去思考下。

我知道,他已经悟了,聪明的小汪~

又过了大概一周后,小汪发来了一个重构方案评审会邀,在会上他向我展示了他利用下班和周末的时间,写出的下面这份堪称"教科书级"的重构方案。

他不仅完美地应用了我们讨论的所有技术点,甚至还举一反三,在方案里加入了极其专业的超时控制(orTimeout)基于指数退避的重试机制、以及完善的异常处理

他不再是简单地模仿,而是真正理解了系统痛点背后的"B面"权衡。

我很惊讶于小汪的执行力,可以这么快就给出这样比较完整的方案。我对整体的重构方案进行了严格的技术把关和评估,最终评审通过,决定采用小A的这套方案 ,并通知小A配合测试同学给出压测方案和报告。 团队双周技术分享会上,小汪主讲了这个重构方案,并给出了详尽的压测报告(P99延迟从5秒降到150ms,接口吞吐量提升300%),整个过程技惊四座。那一刻,再也没有人把他当外包了。

java 复制代码
@Service
public class UserSyncServiceV2 {
    // 老A的B面架构第一课:为IO密集型任务自定义"服务员"线程池
    private final ThreadPoolExecutor syncExecutor = new ThreadPoolExecutor(
            20, 
            200, 
            60L,
            TimeUnit.SECONDS, 
            new LinkedBlockingQueue<>(1000)
    );
    
    // ... 注入各个Client ...
    
    public CompletableFuture<Boolean> syncStatusAsync(Long customerId) {
        // 1. 并行获取无依赖的用户信息和风控结果
        CompletableFuture<UserInfo> futureInfo = CompletableFuture.supplyAsync(
                () -> userClient.getUserInfo(customerId), 
                syncExecutor
        );
        
        CompletableFuture<RiskResult> futureRisk = CompletableFuture.supplyAsync(
                () -> riskClient.checkRisk(customerId), 
                syncExecutor
        );
        
        // 2. 老A的B面架构第二课:用thenCompose处理依赖性的异步任务(订单依赖用户信息)
        CompletableFuture<OrderInfo> futureOrder = futureInfo.thenCompose(info -> {
            if (info == null || info.getOrderId() == null) {
                // 如果前序结果为空,优雅地返回一个空的Future
                return CompletableFuture.completedFuture(null);
            }
            return CompletableFuture.supplyAsync(
                    () -> orderClient.getLastOrder(info.getOrderId()), 
                    syncExecutor
            );
        });
        
        // 3. 老A的B面架构第三课,组合所有结果,并用thenApplyAsync进行最终的数据库操作
        return CompletableFuture.allOf(futureOrder, futureRisk)
                .thenApplyAsync(v -> {
                    // ...从各个Future中join()结果,并进行组合...
                    // ...验证数据完整性...
                    
                    // 更新数据库
                    updateDatabase(syncResult);
                    
                    log.info("用户状态同步成功, customerId: {}", customerId);
                    return true;
                }, syncExecutor)
                .exceptionally(e -> {
                    log.error("异步同步失败, customerId: {}", customerId, e);
                    return false;
                });
    }
    
    // ... updateDatabase()等私有方法 ...
}

老A说:从毕业作品到"生产级"的最后三公里

兄弟们,小汪的这份代码,已经是一个极其优秀的技术验证原型。但要把它真正投入生产,我们还需要打磨三个"B面"细节:

线程池的哨兵: 必须为这个线程池配置合理的拒绝策略,并接入相关监控平台(如Sunfire)进行监控,防止在高并发下被打爆。

异步安全保障: exceptionally里的简单日志还不够。生产级代码需要集成Resilience4j这样的熔断器和重试框架,防止下游服务的抖动引发雪崩。

数据的安全锁: 异步化后,如何保证数据一致性?我们需要引入Saga或TCC等分布式事务方案,来确保整个流程的原子性。

这最后三公里,才能区分出你是高级工程师 还是架构师

第四幕:一年之后------"他放弃了转正的想法,选择了字节"

就这样,小汪按照我的镀金计划不断的"偷师取经,稳步成长",我能明显感觉到他在技术、视野和自信心上发生了脱胎换骨的变化。今年年初,我们的一个正式HC恰好空出,老板也确实在考虑他。但与此同时,通过之前积攒来的人脉,他也拿到了一个字节的面试机会。结果也在我的意料之中,他顺利通过了面试,薪资直接翻倍。他最终礼貌地"放弃"了在内部等待那个不确定的转正机会,飞到了另一片天空。

感言

我至今都记得小汪拿到Offer后请我吃饭时说的话:"A哥,谢谢你,没有你就没有我的今天。谢谢你让我找到成长的最优路径,谢谢你掏心窝子对我说的那些话,谢谢你对我的倾囊相授,谢谢你让我明白成长的意义所在,谢谢你让我知道我可以,我能行!"

老A说:其实一个人的价值,不应该由别人给你打上的身份标签来定义。我们可能无法选择起点,但可以通过正确的战略和努力,选择自己的终点。

老A时间

感谢各位兄弟的阅读。

我是老A,一个只想跟你说点B面真话的师兄。如果这篇文章让你有了一点点启发,那就是对我最大的肯定。

为了感谢大家的支持,我把这两年在一线大厂面试和带团队中,沉淀下来的所有上不了台面的私房笔记,整理成了一份《程序员B面生存手册》。

里面没有市面上千篇一律的八股文,只有一些极其管用的"潜规则"和"避坑指南",希望能帮你少走一些弯路。

关注我的同名公众号【大厂码农老A 】,在后台回复"B面",就能免费获取。

回复"简历 "获取《简历优化手册

回复"arthas "获取史上最全的《大厂arthas实战手册

回复"指导 "获取《大厂外包镀金手册

最后,如果觉得内容还行,也希望能点个赞、点个在看,让更多需要它的兄弟看到。

我们一起,在技术的路上结伴"陪跑"。

相关推荐
摇滚侠3 小时前
Spring Boot3零基础教程,生命周期监听,自定义监听器,笔记59
java·开发语言·spring boot·笔记
凯子坚持 c3 小时前
Llama-2-7b在昇腾NPU上的六大核心场景性能基准报告
java·开发语言·llama
武子康3 小时前
大数据-136 - ClickHouse 集群 表引擎详解 选型实战:TinyLog/Log/StripeLog/Memory/Merge
大数据·分布式·后端
Somehow0073 小时前
从Binlog到消息队列:构建可靠的本地数据同步管道(macOS本地部署Canal & RocketMQ并打通全流程)
后端·架构
T___T3 小时前
JavaScript 变量声明详解:var、let、const 的核心差异
javascript·面试
ai安歌3 小时前
【Rust编程:从新手到大师】Rust概述
开发语言·后端·rust
百锦再3 小时前
国产数据库替代MongoDB的技术实践:金仓数据库赋能浙江省人民医院信息化建设新展望
java·开发语言·数据库·mongodb·架构·eclipse·maven
T___T3 小时前
Git 入门实战笔记:从 0 到 1 掌握代码版本管理流程
git·面试
武子康3 小时前
Java-160 MongoDB副本集部署实战 单机三实例/多机同法 10 分钟起集群 + 选举/读写/回滚全流程
java·数据库·sql·mongodb·性能优化·系统架构·nosql