
黄色代码这个词十个新手里有八个是在刚装好编辑器、兴冲冲写完人生第一段程序之后撞见的代码能跑控制台也正常输出结果但编辑器里那几个变量名底下偏偏挂着一条黄色波浪线右键一看还弹出一堆看不懂的提示文案。有人以为是电脑中病毒了有人以为是代码写脏了还有人干脆把整个文件的代码块选中看是不是背景色设置出了问题。实际上所谓黄色代码绝大多数情况下指的是编辑器或语言服务在你代码下方标注的黄色警告标记warning它是静态检查体系里的一个层级跟红色报错error完全不是一回事。它想表达的意思是这段代码语法上合法、大概率也能跑起来但里头存在某种潜在风险或者不符合项目约定的写法。这篇文章面向的就是刚上手编程、被满屏黄线搞得心里发毛的新手也适合那些写了几年代码、却一直把警告当背景噪音的老手——因为黄色代码这件事从来不是点一下灯泡自动修好这么简单背后牵扯的是类型检查、规则配置、团队协作和工程治理一整条链路。我会从编辑器为什么画黄线讲起把最常见的十几类警告逐条拆开给出可以直接抄作业的配置和治理节奏最后把我自己踩过的坑摊开说。1. 先把黄色这件事说清楚它到底是谁画上去的很多人下意识觉得黄线是编辑器自带的代码洁癖其实画线的不是一个角色而至少是三个不同来源的检查器在同一个文件上工作。搞清楚是谁在提示你比急着改代码重要得多因为不同来源的警告处理逻辑和优先级天差地别。1.1 三类施压者语言服务、代码检查工具、编辑器的风格检查第一类是语言服务也就是负责语法解析和类型推导的那一层。它挂在编辑器背后文件一保存就把内容丢进内存里做词法和语法分析构建语法树再根据类型声明推导每个表达式的类型。它报出来的黄色通常是类型不匹配可能为空的引用函数缺少返回值这类语义级问题风险等级最高。第二类是独立的代码检查工具业内叫 linter。它不关心你的程序能不能编译通过它关心的是代码写得是否符合一组预设规则比如变量有没有用到、有没有硬编码的魔法数字、函数圈复杂度是不是超了阈值、导入顺序对不对。这类工具的判定标准完全来自配置文件跟你的代码能不能跑没有半点关系。第三类是编辑器自己的风格层包括格式化提示、拼写检查、缩进对齐、行宽超限、以及某些版本里针对注释内容的词典匹配。这一类警告纯属审美范畴一条不改也不影响任何功能但它恰恰是黄线里数量最多的那批也是造成警告疲劳的元凶。注意判断一条黄线归谁管最省事的办法是把鼠标悬停在提示上看弹出文案里有没有带上规则编号或者工具名。带编号的去配置文件里搜这个编号一定能找到开关不带的八成是语言服务的内置诊断得从类型声明和编译配置入手。1.2 黄和红的本质区别一个不阻断一个会阻断红线的语义很明确语法不合法、类型不可能成立、必填参数缺失。这类问题出现时程序要么根本编译不过去要么一旦运行必然在某个点上崩掉所以编辑器用最刺眼的颜色标出来编译器和打包工具也会直接拒绝产出。黄线的语义是能过但不太对。打个类比红线像是仪表盘上亮起的故障灯车当场就不走了黄线像是胎压监测提示车照样能开甚至能开很久但你心里得清楚现在不适合跑高速。这个能过的特性是黄色最危险的地方它给了你无视它的理由而这些被无视的问题会在某次重构、某次依赖升级、某次线上并发量翻倍的时候集中爆出来版本只是外加一次莫名其妙的报错。我在带新人的时候习惯说一句话红线是编译器逼你改的黄线是未来的你自己求你现在改的。前者不修不行后者不修也能活但活得不安稳。1.3 新手最容易踩的三个误会第一个误会是黄线等于我写错了。实际上大量的黄色提示是风格偏好比如某团队规定字符串必须用单引号你用了双引号就是一条警告这跟对错毫无关系。有例外有约定但错这个字太重了。第二个误会是黄线可以永远不管。这个更致命。当屏幕上出现三百条警告时任何人的大脑都会自动把它们归类为背景噪音这时候真正藏在高风险警告就一起被淹没了。工程上有个专门的说法叫警告疲劳它不是个人素质问题而是任何不加治理的代码库必然出现的系统性现象。第三个误会是编辑器在针对我。规则不是你写出来的是项目根目录下那几个配置文件定出来的你可能只是接手了一份别人配的规则或者不小心打开了一个位于项目根目录之外的文件导致规则加载失效或者反过来说加载了一份更严格的父级配置。你被针对的错觉本质上是配置继承链路没搞明白。2. 黄色标记背后的检查逻辑拆解想彻底摆脱被动挨打的局面得知道检查器是怎么看懂你的代码的。这一节稍微讲点原理但我会尽量用能直接对上号的方式讲不堆术语。理解这套机制之后你会发现很多为什么这条不提示那条提示的疑惑答案其实很朴素。2.1 从字符串到语法树检查器眼里的代码长什么样你写的是一个文本文件检查器眼里的却是一棵树。流程大致四步先把字符流切成词法单元标识符、关键字、运算符、字面量这叫词法分析再按语法规则把词法单元组装成抽象语法树一个函数就是一个节点函数体里每一条语句是它的子节点然后遍历这棵树建立符号表记录每个名字在哪个作用域声明、被引用了多少次最后做类型推导给每个表达式算出一个类型。变量声明了但从未使用这种警告判定逻辑简单到有点可爱符号表里这个名字的引用计数是 0。检查器不在乎你这个变量叫什么、当初为什么留下它只数引用次数。可能为空的对象被直接访问属性这种警告判定逻辑稍复杂一点推导出来这个表达式的类型是一个联合类型里面包含了空值成员而你在访问属性之前没有做任何收窄比如判空分支、可选链、非空断言。检查器做的事就是模拟所有可能的路径只要有一条路径会导致空指针它就亮黄灯。2.2 规则到底从哪来默认集、项目配置、目录继承检查工具的规则来源是分层的。最底层是工具自带的推荐规则集一般叫 recommended 之类的名字装完就有一批默认开启的规则。往上一层是项目根目录的配置文件可以逐条开启、关闭、调整等级警告还是错误、修改参数。再往上一层是上级目录的配置在单仓库多项目的结构里父目录的配置会被子目录继承这一层最容易出问题。真实的坑是这样你在一个子目录里调试发现某条警告怎么都不出现改配置也没反应折腾半小时才发现真正生效的是三层目录之外的那份配置文件而你改的那份根本没被读取。还有一种反向情况你打开的是项目根目录之外的单个文件检查工具根本没把它当成项目的一部分配置文件压根没加载于是所有警告集体消失你以为代码突然变干净了。提示排查配置问题的第一动作永远是确认当前文件到底归属于哪份配置。主流工具都提供打印最终生效配置的命令直接输出解析后的完整规则表比靠猜快得多。2.3 为什么同一个文件在两台机器上黄线数量不一样这个问题在协作场景里出现频率极高而且往往引发不必要的争执。成因大致五种我按出现概率排一下成因具体表现排查方向检查工具版本不一致工具大版本升级后默认规则集变了老版本没提示的规则新版本默认开锁定依赖版本写进锁定文件编辑器插件版本不一致插件内置的解析器版本不同对同一语法支持程度不同团队统一插件与版本清单运行时或解释器版本不一致语言服务按不同版本的语法标准解析新语法在旧版本里被判为错误在配置里明确声明目标版本文件未纳入项目范围文件在项目根目录之外配置未加载检查项目文件里的包含与排除规则缺少类型声明文件第三方库没有类型声明类型推导退化成任意类型相关警告集体失效安装对应的类型声明包或自己写声明第三条特别值得展开。你在配置文件里声明目标版本这件事不是为了跑得更快而是为了让检查器和你的运行环境对齐。声明了较低的版本检查器就不会推荐那些在旧环境里不存在的语法声明了较高的版本检查器会主动提示你哪些老写法已经可以换成新写法。这是个双向约束写清楚比不写清楚强太多。3. 高频黄色类型逐条拆解与处理办法接下来是干货主体。我把新手最常撞见、以及老手最容易误判的警告按类别分好组每一类都说明它为什么会被报出来、真实风险有多大、该怎么处理。先说结论黄色警告绝对不能一视同仁地对待必须分级否则你会在无风险的那批上耗光耐心。3.1 未使用的东西变量、导入、参数、私有方法这是出现频率断层第一的警告类型。成因基本都是写一半改主意了本来想用某个变量接返回值后来直接内联了复制一段代码过来配套的导入原封不动搬过来了函数签名定好之后某个参数在实现里压根没用到。风险等级低。它不会导致程序出错纯粹是死代码。但它的危害在于累积——一个文件里堆了八个没用到的导入读代码的人就得多花时间分辨哪些是真依赖。而且未使用的导入在某些打包配置下不一定会被摇树优化掉白白增大产物体积。处理手法上有个细节值得说函数参数这类未使用的警告通常可以配置成只检查最后一个之后的参数。这很好理解很多回调函数的签名是框架定死的你只关心第三个参数前两个不能删这种警告关掉是合理的属于工具本身提供的精确豁免机制。至于私有方法未使用这类警告我的建议是必须处理。因为私有方法没人调用往往意味着重构做了一半漏掉了或者调用点被误删了。这在测试覆盖不充分的项目里就是一颗定时炸弹。3.2 类型与可空性真正会咬人的那一批这一类警告的风险等级是最高的也是我建议你看到就立刻停手处理的。典型形态包括把可能是空值的对象当非空用、函数声明的返回类型和实际返回的分支对不上、参数传入的类型和声明的类型不兼容、把任意类型的值直接赋给具体类型的变量。为什么说它咬人因为这类问题在开发环境里往往不报错。你本地的数据是完整的接口返回的字段一个不少所以代码跑得通黄线一直被无视等到线上某个边界数据缺失或者某次接口变更把字段名改了程序就在那里崩了而且崩的位置离真正的错误源头可能隔了三层调用。处理这类警告有一个原则值得反复强调不要用强制的类型断言去消灭警告。很多人一看到类型不匹配第一反应是加一个断言把类型强行改成目标类型警告确实消失了但问题只是被你从编译期推迟到了运行期而且编辑器从此再也帮不了你了。正确的做法是把类型定义补准确或者在进入业务逻辑之前加一层数据校验把不可信的外部数据清洗成可信的内部结构。// 不推荐用断言把警告按下去风险被隐藏 const user fetchUser() as User; console.log(user.profile.name); // 推荐先校验再使用把不确定性挡在门外 function isUser(value) { return ( value ! null typeof value object typeof value.id string value.profile ! null typeof value.profile object ); } const raw fetchUser(); if (!isUser(raw)) { throw new Error(user payload shape mismatch); } console.log(raw.profile.name);这段代码里两种写法的行数差了三倍但只有第二种能让编辑器闭嘴——因为类型收窄是真实发生的不是强制的。这也是判断警告是被解决还是被掩盖的核心标准警告消失之后检查器对这个变量的认知是否更准确了。3.3 过时接口与弃用提示依赖升级之后一批原本干干净净的代码突然集体黄了绝大多数是这一类。检查器告诉你你调用的这个函数、这个参数、这个类在库里已经被标记为弃用未来某个版本会移除。风险等级中但时间敏感。它现在还能跑升级到下个大版本就彻底跑不了。所以处理节奏是排期而不是立即但必须进待办清单而且要写清楚目标版本。有一个现实问题得说清楚弃用提示不总是有替代方案。有时候新接口的能力还不如旧的或者替代方案在你的使用场景里根本走不通。这种情况下合理的做法是在调用点加一条带原因的豁免注释注明为什么暂时不能升级到新接口跟踪到什么时候把技术债显性化。最糟糕的做法是全局关掉弃用检查那你以后所有升级都等于闭着眼睛过马路。3.4 命名、复杂度与代码异味这一类是规则驱动的没有任何硬性标准全靠团队约定。典型的有函数名不符合命名风格、单个函数圈复杂度超过阈值、嵌套层级超过三层、文件行数超限、字符串里出现魔法数字、布尔参数过多。风险等级低到中。它们反映的是可维护性不是正确性。但对于新手来说这类警告恰恰是最有价值的反馈因为它相当于一个资深工程师在旁边提醒你这个函数已经绕得没人看得懂了。处理建议分情况命名类的直接改成本极低收益极高复杂度过高的不要硬拆先想清楚这个函数实际上在做几件事按职责拆而不是按行数拆魔法数字和布尔参数这类抽成具名常量或者改用配置对象一次改动能让后面所有调用点都变清晰。我个人的经验是圈复杂度阈值这种东西一旦团队里有人开始为了过检查而机械地把一个函数拆成三个只有十行的私有函数结果调用链反而更难追踪那说明阈值定得不合理或者拆分的粒度错了。工具给的是信号不是圣旨。3.5 异步与潜在运行时陷阱这一批是新手最容易忽略、后果又最严重的。典型形态异步调用的结果没有被等待、异步函数内部抛出的异常没有人接、回调里用了循环变量导致闭包捕获错值、定时器没有清理。风险等级高。而且这类问题的表现形式特别阴险——程序不崩只是行为不对。数据没保存成功但界面显示成功、请求发出去了但错误被静默吞掉、组件卸载之后定时器还在跑导致内存泄漏。处理这一类靠看到黄线再改是被动的。更有效的做法是在配置里把这类规则从警告提升为错误让它在提交之前就拦住你。痛一次之后就会形成肌肉记忆如果一直停留在警告级别你会一直绕过去直到某天被线上的数据结构打脸。警告类别典型文案大意真实风险建议处理节奏未使用声明声明了但从未读取无功能风险影响可读性随手清理类型不匹配类型不可赋值 / 参数类型不符高运行期崩溃立即修可空性对象可能为空高空指针立即修弃用接口该接口已标记弃用中升级阻断排期并记录异步未处理返回的 Promise 未被处理高错误静默丢失立即修或提级为错误复杂度超限圈复杂度超过阈值中维护成本重构时顺手处理命名风格不符合约定的命名格式无随手改或按团队规范拼写检查词典未收录该词无关闭或维护词库4. 解决路径从逐个点灯到批量治理新手最常见的应对方式是一个一个点灯泡自动修复改完这个改那个一天下来改了八十条第三条改错了引入新问题第五条改完又冒出两条新的。这种方式在文件级别能撑一阵子在项目级别必然失败。真正有效的做法是建立一套分级策略和闸门机制。4.1 分级先判断这条警告值不值得花时间我给自己定的判断方法是三个问题问完基本就有答案了。第一问这条警告如果被带上线最坏会发生什么答案是程序崩溃、数据错乱、安全边界失效的归为必修优先级最高当天处理。答案是什么都没有发生的归为可清理攒一批一起做。第二问如果我三个月后再回来看这段代码会不会因为这个警告而多花时间会那说明它影响的是可维护性值得排期。第三问要关掉它我需要给出一个能说服别人的理由吗如果需要而我说不出来那就不该关。按这个框架过一遍通常 20% 的警告承担了 80% 的风险剩下的都是噪音。把 20% 清干净你的代码质量就已经超过绝大多数仓库了。4.2 配置实操三个技术栈的落地写法配置这件事光说原则没用直接给能跑的写法。下面三份配置是我在不同项目里反复用过的底子可以按需删减。注意配置文件的字段名会随工具版本变化大版本升级时务必对着官方迁移说明核对一遍这一步偷懒的代价是配置静默失效你以为规则开了其实没开。先说前端项目里最常见的静态检查配置重点是三处未使用变量的精确豁免、把危险的规则提到错误级别、以及避免和格式化工具抢活。{ root: true, env: { browser: true, es2022: true }, parserOptions: { ecmaVersion: latest, sourceType: module }, extends: [eslint:recommended], rules: { no-unused-vars: [warn, { args: after-used, ignoreRestSiblings: true, caughtErrors: none }], no-undef: error, no-constant-condition: [error, { checkLoops: false }], eqeqeq: [warn, smart], no-console: [warn, { allow: [warn, error] }] }, overrides: [ { files: [**/*.test.js, **/__mocks__/**], rules: { no-console: off } } ] }解释几个关键选择把「未定义变量」设为 error 而不是 warn因为它几乎总是拼写错误导致的运行时崩溃没有商量的余地把「相等比较」设为 warn 加 smart 模式是因为和空值比较时用宽松相等是社区通行的写法硬性要求全等反而制造噪音对测试目录单独关闭控制台警告因为测试里打日志是正常行为一刀切会让测试文件永远带着黄线。再看 TypeScript 项目的编译配置这里的原则是一次把严格模式全开不要一件一件试。逐项开启的路径会让你在中间状态停留很久而且不同严格选项之间有耦合单独开某一项可能出现更难理解的报错。{ compilerOptions: { target: ES2022, module: ESNext, moduleResolution: Bundler, strict: true, noUnusedLocals: true, noUnusedParameters: true, noImplicitReturns: true, noFallthroughCasesInSwitch: true, exactOptionalPropertyTypes: true, forceConsistentCasingInFileNames: true }, include: [src/**/*], exclude: [node_modules, dist] }有个细节必须提醒noUnusedLocals这一类选项在编译阶段是错误红但很多编辑器把它呈现为警告黄所以你在编辑器里看到黄线、跑构建却直接失败别觉得是工具抽风这是两套呈现层级的差异。另外include字段决定了哪些文件归这个项目管你在 include 范围外新建的文件配置对它不生效这就是前面说的文件一挪警告全消失的根源。然后是 Python 项目。这一块过去是工具混战的典型场景配置文件分散在多个文件里规则互相覆盖。现在主流做法是集中到一份项目配置文件里用一套工具覆盖风格检查和常见错误检测。[tool.ruff] line-length 100 target-version py311 exclude [.venv, build, dist] [tool.ruff.lint] select [E, F, W, I, B, UP, SIM] ignore [ E501, B008 ] [tool.ruff.lint.per-file-ignores] tests/**/*.py [S101, E402] __init__.py [F401]这里踩过的坑值得单列配置段的层级在不同大版本之间改过早期写在顶层的 lint 相关字段后来迁到了子表里。你如果照着一篇两年前的教程配很可能发现规则根本没生效而且不报错就是静默无效。第二个坑是F401导入未使用在包的初始化文件里必须豁免因为那个文件的导入本来就是为了对外暴露接口它没有被使用的概念。4.3 把闸门装好提交前拦一道流水线上拦一道配置写得再漂亮只要没人执行就等于没写。我的做法是两道闸门。第一道是提交前的本地检查只检查本次改动涉及的文件速度要快超过五秒人就会开始想办法绕过。#!/usr/bin/env bash set -euo pipefail staged$(git diff --cached --name-only --diff-filterACMR | grep -E \.(js|jsx|ts|tsx|py)$ || true) if [ -z $staged ]; then exit 0 fi echo linting staged files... echo $staged | xargs npx eslint --max-warnings 0 echo $staged | grep -E \.py$ | xargs -r ruff check注意--max-warnings 0这个参数它是整条命令的灵魂。不加它检查工具在有警告的情况下依然返回成功钩子形同虚设。加上它任何一条新引入的警告都会让提交失败。配合只检查改动文件这个限制体验上是可接受的。第二道是流水线上的全量检查放在合并请求阶段不给放行按钮留余地。# 以常见的流水线 YAML 结构为例各平台字段名略有差异 stages: - verify lint: stage: verify script: - npm ci - npm run lint:ci allow_failure: false rules: - if: $CI_PIPELINE_SOURCE merge_request_eventallow_failure: false这一行同样关键。我见过太多仓库把静态检查那一关设成允许失败理由通常是存量警告太多先放行。结果就是这一关永久性地变成了绿色装饰从设置那天起再也没有人看过它的输出。要么让它挡住合并要么干脆别设这一关——一个永远通过的检查项比没有检查项更糟糕因为它给人虚假的安全感。4.4 存量代码怎么办围栏策略而不是大扫除接手一个满屏黄线的老项目最容易犯的错是发誓花一个周末全部清干净。这条路走不通原因有两个一是几百条警告里混着不同等级的问题你没法在一个周末内对每条都做出正确判断二是大规模改动的回归风险极高为了清警告引入线上故障得不偿失。我用的方法是围栏先把新代码的闸门关死再慢慢清存量。具体三步。第一步把高风险规则提为错误只对这些规则做全量清零。范围收窄之后工作量通常在一两天内风险也可控。第二步在配置里对存量目录做临时豁免把豁免范围写清楚、写上到期时间、写进待办。第三步每改动一个模块就把这个模块从豁免名单里移出去顺带把它清干净。这样清理成本被摊到日常迭代里不需要专门立项也不会集中爆发风险。这套方法的心理效果也很重要。新人入职看到满屏黄线会直接放弃看到自己负责的目录是干净的、只有少数几个历史目录带豁免就会愿意保持下去。可见的秩序感是维持秩序的前提这话听起来虚实际执行下来差别很大。5. 常见问题与排查实录这一节记录的是我和身边同行反复遇到的疑难情况。共同特点是现象很怪原因很朴素不知道方法的话能耗掉半天。5.1 代码改了黄色还在或者黄色突然全没了第一种情况先分清是检查结果没更新还是这条警告真的还在。判断方法很简单改一个明显的语法错误看红线有没有即时出现。如果红线也没反应那就是语言服务卡住了重启语言服务即可不用怀疑代码。如果红线正常而黄线不动那多半是这条警告来自编译期缓存清掉缓存目录重新构建。第二种情况黄色突然全部消失这比黄线不消失更值得警惕。最常见的原因是文件被移到了项目配置的包含范围之外检查器不再把它当成项目的一部分自然也就没有规则可应用。其次是不小心把整个文件加了豁免注释或者选错了语言模式比如把一个脚本文件按纯文本打开。还有一种是依赖没装好类型声明缺失导致检查器降级运行很多依赖类型推导的规则集体失效。遇到突然变干净第一反应应该是排查而不是高兴。注意判断警告是否真的被消除最可靠的动作是在命令行跑一次全量检查而不是信任编辑器界面。编辑器的显示层有自己的缓存和节流机制命令行输出才是唯一的真相。5.2 多个检查器打架同一条规则重复提示或互相冲突这种局面在前端项目里尤其常见格式化工具要求这一行必须换行静态检查工具说这一行不该换行你改过去它改过来来回拉锯。根本原因是两个工具的职责边界没有划清。我的处理原则是格式问题全部交给格式化工具静态检查工具里所有跟格式相关的规则一律关闭。缩进、引号、分号、行宽、括号位置这些都属于格式格式化工具做得又快又准静态检查工具插手只会制造冲突。静态检查工具专注在语义和逻辑层面未使用的代码、可疑的条件判断、危险的类型转换。Python 生态里类似的冲突是多个检查工具同时开启同一条问题被三个工具各报一次。解决办法很简单只保留一套主检查工具其余关掉或降级为只在流水线上跑。编辑器里同时挂着三套检查器的结果除了让你更想无视它们之外没有别的效果。5.3 真的是误报怎么办豁免要带理由和期限必须承认有误报而且有些规则确实不适用于你的场景。这时候合理的做法是精确豁免而不是关掉整条规则。精确豁免有三个要素范围最小只豁免那一行或那一个文件不要整个目录、写明理由为什么这里可以例外、留下可追溯的标记如果是临时豁免写上什么时候该回来处理。// eslint-disable-next-line no-console -- 启动阶段需要打印就绪日志日志系统尚未初始化 console.log(service ready);# noqa: B008 -- 该函数作为框架钩子被调用参数在调用时求值是设计要求 def configure(app, optionsload_defaults()): ...//nolint:errcheck // 关闭错误由连接池统一记录此处重复上报会刷屏 _ pool.Close()这三段注释的共同点是看到的人一眼就知道为什么能例外以及是不是可以照抄。反过来如果你在文件顶部写一行全局关闭三个月后没人知道当初为什么关也没人敢打开这条规则就永久性地死掉了。5.4 排查速查表把上面这些经验整理成一张表出问题时按行对照能省掉大量瞎猜的时间。现象最可能的原因第一动作改完代码黄线不消失语言服务卡住或编译缓存重启语言服务清缓存重建黄线突然全部消失文件不在项目包含范围内检查配置里的包含与排除设置提示文案里没有规则编号来自语言服务内置诊断不是 linter查类型声明与编译配置同一条规则被重复提示多个检查器同时开启只留一套主检查工具配置改了不生效实际生效的是上级目录的配置打印最终生效配置核对只在某台机器上出警告依赖或运行时版本不一致锁定依赖版本统一环境升级依赖后警告暴增弃用标记集中触发按弃用清单排期别全局关闭提交钩子没拦住警告缺少最大警告数为零的参数加上该参数并验证返回码我在实际使用中的体会是黄色代码这件事最难的从来不是怎么改而是决定改哪些。工具会不加区分地把所有偏差都标成同一个颜色但它们的风险差了两个数量级。你真正需要培养的能力是看到一条警告之后在两秒钟内判断出它属于哪一档然后该立刻动手的立刻动手该记录的记录该关掉的连同理由一起关掉。这个判断力比记住任何一条规则都值钱而且它只会在你亲手处理过几百条警告之后才长出来。所以别怕黄线多怕的是你把它们全当成背景色那才是真正的麻烦开始的地方。