一次开发效率提升优化的实战经验分享

♂邓文
2025-06-17 06:56
阅读 359

开篇:为什么要做这次“折腾”?

开篇:为什么要做这次“折腾”?

在互联网公司工作多年,我发现了一个普遍现象:我们花了太多时间在低效的流程和重复性的工作上。尤其是在中大型项目中,代码库越来越大、依赖越来越多、构建和部署耗时越来越长,这些都成了限制团队协作和交付效率的主要瓶颈。

最近我在一个持续集成(CI)平台的重构项目中,亲历并主导了一次针对开发与构建流程的整体优化。整个过程其实更像是“一边修复漏洞一边跑”,但也正是这种高压下的打磨,让我对“效率提升”这件事有了更深刻的认识。

所以今天想和大家分享这段真实的经历:我们遇到的问题是什么?怎么分析问题、制定方案的?过程中踩了哪些坑?最后取得了什么样的效果?如果你正在为类似问题头疼,也许能从我们的实践中找到一些启发。


问题描述:构建慢得让人抓狂

问题描述:构建慢得让人抓狂

我们的项目是一个典型的中型前端服务,使用 React + Node.js 搭建,前后端分离架构,并且通过 CI/CD 工具链进行自动化部署。随着业务扩展,项目的模块化程度越来越高,构建脚本也越来越复杂,最终导致每次提交后触发的构建流程耗时严重拉长 —— 从最初的3分钟涨到8分钟甚至更久

更糟心的是,这个构建流程不是一气呵成的。它分为几个阶段:

  1. 安装依赖(npm install)
  2. 打包前端(webpack build)
  3. 构建Docker镜像
  4. 推送镜像到私有仓库
  5. 部署到测试环境

每一个阶段之间都有串行等待,而且由于频繁修改的部分主要是前端静态资源,但构建却每次都重新打包全部内容。这明显不合理,但当时没人深究过怎么优化


解决方案:拆分流程 + 缓存加速 + 并行处理

第一步:拆解流程,明确瓶颈点

为了找出问题根源,我先用 CI 平台的日志分析工具做了一个简单的执行时间统计图。结果发现:

  • npm install 占比高达 2 分钟
  • webpack 构建平均 4 分钟
  • 其他流程相对稳定

于是我把优化目标定为:

  • 缩短 npm install 时间
  • 减少 Webpack 不必要的构建
  • 利用缓存机制加速重复流程

第二步:技术选型与方案对比

1. 使用 yarn 替换 npm

Node.js 包管理器方面,我们原来一直使用 npm,但它在安装依赖的时候是顺序下载、顺序执行,面对几十个包的时候效率很低。

我们尝试换成 yarn,它的优势在于:

  • 更快的并行安装方式
  • 自带缓存策略(yarn cache)
  • lock 文件结构更清晰

实际迁移之后,npm install 的耗时从 120 秒下降到 60 秒左右。

2. Webpack 启用持久化缓存

Webpack 默认情况下是不会缓存中间编译结果的。我们引入了 webpack-persistent-cache 插件,结合文件系统缓存来减少无变更内容的重复编译。

配置如下:

const FsCachePlugin = require('webpack-fs-cache-plugin');

module.exports = {
  // ...
  plugins: [
    new FsCachePlugin({
      cacheDirectory: path.resolve(__dirname, '.cache'),
      useHashScrolling: true,
    })
  ]
}

开启之后,未修改的模块可以直接命中缓存,整体构建时间减少约 40%,也就是 2.5 分钟缩短到了 1.5 分钟。

3. 构建任务并行执行

我们原本的 CI 流程是完全串行的,前端和后端的构建是分开的两个 job,实际上它们之间没有强依赖关系。我们将其改为并行执行,并将 Docker 镜像构建步骤也拆出来,在不影响逻辑的前提下利用并发能力。

比如 Jenkins Pipeline 改写后的部分片段如下:

pipeline {
    agent any
    stages {
        stage('Install Dependencies') {
            steps {
                sh 'yarn install'
            }
        }

        parallel {
            stage('Build Frontend') {
                steps {
                    sh 'cd client && yarn build'
                }
            }
            stage('Build Backend') {
                steps {
                    sh 'cd server && yarn build'
                }
            }
        }

        stage('Build Image') {
            steps {
                sh 'docker build -t my-service .'
            }
        }


![CI/CD流水线-2](https://code-guide.oss.shanghai.autogptai.club/common/file/download?name=date2025061706/01bcbb80-28c4-494b-8edd-88fb3a486534.jpg)


        stage('Deploy') {
            steps {
                sh 'kubectl apply -f k8s/'
            }
        }
    }
}

这样一套下来,总流程耗时由原来的 8 分钟压缩到了 4分钟左右


踩坑经验:理论很美好,现实有点骨感

虽然看起来一切顺利,但实际推进过程中还是踩了不少坑:

坑1:缓存不生效,反而增加了构建时间

一开始,我们简单地把缓存目录设为 .cache,但每次运行 CI 的时候发现缓存根本没命中。后来查文档才发现,因为每个 CI Job 是在一个全新的容器中运行的,缓存目录并不是持久化的。

解决办法是在 Jenkins 上启用 workspace 共享,并设置一个专用的挂载目录用于存放缓存文件,比如:

options {
    disableConcurrentBuilds()
}

environment {
    CACHE_DIR = "${env.WORKSPACE}/.build_cache"
}

steps {
    sh 'mkdir -p $CACHE_DIR'
    sh 'cd client && yarn config set cache-folder $CACHE_DIR'
}

这才保证了缓存的有效复用。


坑2:并行任务共享变量冲突

我们在一个分支中尝试并行执行多个任务,但是某些 job 会读取相同的临时配置文件,导致互相覆盖。例如,其中一个 job 修改了 .env 文件,另一个还在使用旧数据。

最终解决方案是:

  • 将共享文件路径重定向到独立子目录
  • 用环境变量替代文件配置传递参数
  • 使用原子操作替换对同一文件的多次写入

坑3:Docker 构建层污染缓存

我们原本的 Dockerfile 编写习惯不太好,很多命令写在一起,一旦某一步修改,后续缓存都会失效。后来改成按层级分离安装、拷贝等步骤,并尽量保持基础镜像不变:

FROM node:18-alpine as builder

WORKDIR /app

COPY package*.json ./
RUN yarn install --production

COPY . .
RUN yarn build

FROM nginx:alpine

COPY --from=builder /app/dist /usr/share/nginx/html

这样一来,只要 package.json 没变,安装的依赖就不会重建,有效提升了镜像构建速度。


效果总结:从8分钟到4分钟,节省了一半时间

最终我们成功将 CI 流程从最初的 8 分钟缩短到了 4 分钟以内。看似只是一个数字的变化,但带来的影响非常深远:

  • 团队成员每天节省下来的等待时间加起来非常可观
  • 提交反馈更及时,迭代效率更高
  • 线上发布更快,减少了等待部署的人工干预

更为关键的是,我们建立了一套可复用的优化模式,可以平移到其他项目上去。


经验分享:不要低估每一次“小改动”

项目管理工具-1

作为一线开发者,我们往往容易陷入“功能优先”的误区,觉得优化是次要的。但事实上,构建和部署的效率直接影响整个团队的节奏和士气。哪怕是一个小时省10分钟,一年下来也能多出几百小时,足够完成一个小项目了。

我总结了几条建议:

  1. 尽早介入流程优化,越早做越轻松;
  2. 重视缓存机制的设计,无论是本地还是 CI;
  3. 拆分任务并合理并行,避免不必要的串行等待;
  4. 日志和监控是最好的帮手,出现问题第一时间定位;
  5. 别怕改已有流程,该重构时就大胆重构;
  6. 让工具链透明可控,团队成员都能理解当前状态。

写在最后:技术之外的人文关怀

其实这篇文章写到这里,还有一个我一直想说但没提的话题 —— 那就是

很多时候,我们做技术优化,不只是为了性能或者体验,更是为了让一起工作的伙伴们少等一会儿,少焦躁一点。技术人的成就感不仅来自于写出漂亮的代码,也来自于让别人更顺畅地完成他们的工作。

这次优化虽然只是一次小小的重构,但当我看到同事们不再对着屏幕发呆,而是在 CI 完成后快速进入下一轮开发的时候,我觉得,值了。

希望这篇真实的经验分享,能给你带来一点点灵感和信心。毕竟,每一种“慢”的背后,都有一个潜在的“快”等着你去发现和实践。


作者简介
一名从事 DevOps 和工具链研发多年的程序员,热衷于提高团队工程效率,偶尔写点文字记录技术成长之路。欢迎关注我的 GitHub 和博客,更多实用技巧持续输出中。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝