avatar
文章
73
标签
209
分类
30
首页
简历
技术文章
时间图
分类
标签
关于
高晓庄 札记
首页
简历
技术文章
时间图
分类
标签
关于

高晓庄 札记

Docker 从入门到生产实践
发表于2026-02-05|Cloud NativeDocker
Docker 从入门到生产实践 Docker 的价值不在于”会跑一个容器”,而在于把”环境一致性”从口头承诺变成工程事实。本文聚焦真正影响生产环境的几个关键点。 镜像分层:缓存用对了,构建快 10 倍Dockerfile 的每一行指令都会生成一层。构建缓存能否命中,取决于指令和上下文是否变化。 一个反面例子: 1234# 差:每次代码变动都让 COPY 之后的层全部失效FROM openjdk:17COPY . /appRUN mvn package 依赖下载是构建中最慢的环节,却每次都要重跑。正确做法是先拷贝依赖清单,再拷贝源码: 123456FROM openjdk:17WORKDIR /appCOPY pom.xml .RUN mvn dependency:go-offlineCOPY src ./srcRUN mvn package -DskipTests 依赖层只有在 pom.xml 变化时才重建,日常改动源码时构建秒级完成。 镜像瘦身:从 800MB 到 120MB大镜像的问题不只是占磁盘,更影响部署速度——每台机器都要拉一遍。 瘦身三板斧: 多阶段构建:构建...
依赖注入:为什么你的代码不该自己 new 对象
发表于2026-02-02|基础
上一篇讲 SOLID 时,最后一条”依赖倒置原则(DIP)”是最难的。而依赖注入(DI)就是 DIP 的落地实现。 如果你用过 Spring,那你天天都在用 DI,只是可能没想过它背后的道理。 没有 DI 的世界先看一段”正常”的代码: 1234public class OrderService { private OrderRepository repository = new MySQLOrderRepository(); private EmailSender emailSender = new SmtpEmailSender();} 这段代码有什么问题? 强耦合:OrderService 直接依赖了具体实现 MySQLOrderRepository。要换数据库,就得改 OrderService。 难测试:想测试 OrderService,没法单独测,因为它内部硬绑定了真实的数据库和邮件服务。 重复创建:每个用到 OrderRepository 的类都自己 new 一个,浪费资源且状态难统一。 依赖注入的解法DI 的思路是:对象不再自己...
单元测试与 TDD:先写测试再写代码,真的值得吗
发表于2026-01-26|基础
写代码十年,我发现一个规律:越资深的工程师,越重视测试。 而新手最常见的误区是:觉得写测试是”额外负担”,是”拖慢进度”的事。 其实恰恰相反——测试是帮你提效的,不是给你添堵的。 为什么要写单元测试1. 让你敢重构没有测试的代码,重构就是赌博。你改了 A 处,可能偷偷破坏了 B 处,而你自己完全不知道。 有了测试,重构完跑一遍测试,全绿就说明行为没变。测试是重构的安全网。 2. 让 bug 更早暴露bug 越晚发现,修复成本越高。单元测试能在开发阶段就抓住大部分逻辑错误,而不是等到线上出问题才返工。 3. 测试本身就是文档一份好的测试用例,比注释更能说明”这段代码到底该怎么用、边界条件是什么”。 测试金字塔一个常见的分层模型: 1234567 /\ / \ E2E 测试(少,慢,贵) /----\ / \ 集成测试(中) /--------\ / \ 单元测试(多,快,便宜)/------------\ 原则:底层多写,顶层少写。 单元测试快、便宜、稳定,应该是主力。E2E 测试慢、贵、脆弱,只...
函数式编程范式:纯函数、不可变数据与高阶函数
发表于2026-01-24|基础
如果你长期写面向对象的代码,第一次接触函数式编程(FP)可能会觉得”别扭”。 但理解之后你会发现,它不是要取代面向对象,而是给了你另一种处理复杂问题的思维方式。 函数式编程的核心思想函数式编程有三个核心概念,理解了它们就抓住了 FP 的精髓。 1. 纯函数(Pure Function)纯函数满足两个条件: 同样的输入,永远得到同样的输出(确定性) 不产生任何副作用(不修改外部状态) 12345678910// 纯函数:输入相同,输出必然相同int add(int a, int b) { return a + b;}// 非纯函数:依赖并修改了外部状态int counter = 0;int increment() { return ++counter;} 为什么纯函数好?因为: 容易测试:不需要 mock 一堆状态 容易推理:看输入输出就能理解,不用追踪外部状态 天生线程安全:没有共享可变状态,就没有并发问题 2. 不可变数据(Immutability)函数式编程倾向于使用不可变数据:对象一旦创建,就永不改变。要”修改”...
Spring Cloud 微服务架构演进
发表于2026-01-22|JavaSpring Cloud
Spring Cloud 微服务架构演进 从单体到微服务,是企业级系统架构演进的必经之路。本文梳理 Spring Cloud 微服务的核心组件与实战经验。 演进路径1234567单体应用 ↓垂直拆分(按业务) ↓SOA(服务化) ↓微服务(独立部署、独立伸缩) Spring Cloud 核心组件 组件 职责 Eureka / Nacos 服务注册与发现 Config / Nacos 配置中心 Gateway / Zuul API 网关 OpenFeign / RestTemplate 服务调用 Hystrix / Sentinel 熔断限流 Sleuth / SkyWalking 链路追踪 选型建议 新项目:Spring Cloud Alibaba(Nacos + Sentinel + Seata) 存量项目:Spring Cloud Netflix(Hystrix 已停止维护,注意迁移) 微服务 ≠ 银弹引入微服务带来的复杂度: 分布式事务 链路追踪 服务治理 部署...
SOLID 五大原则:面向对象设计的地基
发表于2026-01-21|基础
很多人学了二十多个设计模式,却还是写不好代码。原因往往在于:只学了”招式”(模式),没学”心法”(原则)。 SOLID 就是面向对象设计的”心法”,五个字母对应五条原则: S:单一职责原则 O:开闭原则 L:里氏替换原则 I:接口隔离原则 D:依赖倒置原则 理解它们,你才能真正理解那些设计模式为什么那么设计。 S:单一职责原则(SRP) 一个类只应该有一个引起它变化的原因。 说白了:一个类只干一件事。 反例:一个 UserService 既处理用户注册逻辑,又负责发短信、写日志、发邮件。这个类有四个变化原因,任何一处需求变更都要动它。 正例:拆成 UserService、SmsService、EmailService,各司其职。 好处:类的职责清晰,改一个功能不会波及无关逻辑,也更容易测试和复用。 判断标准:如果描述一个类要做的事,需要用”和”字连接(”它负责 A 和 B 和 C”),那大概率违反了单一职责。 O:开闭原则(OCP) 对扩展开放,对修改关闭。 这是五条里最重要的一条,也是所有设计模式的共同目标:加新功能时,尽量通过”新增代码”实现,而不是”修改已有代码”。...
时间复杂度与空间复杂度:Big-O 到底怎么算
发表于2026-01-19|基础
评价一个算法好不好,不能靠”感觉快慢”,得有一个统一的标尺——这就是复杂度分析。 而复杂度分析里最重要的工具,就是 Big-O(大 O 记号)。 为什么需要 Big-O假设你写了一个查找函数,怎么评价它快不快? 有人会说”在测试机器上跑了 10ms”。但换个机器、换个数据量,结果就变了。 Big-O 解决的就是这个问题:它描述的是”随着数据量增大,运行时间怎么增长”的趋势,而不是具体的运行时间。 比如: O(1):数据量翻倍,时间不变 O(n):数据量翻倍,时间也翻倍 O(n²):数据量翻倍,时间变 4 倍 Big-O 到底怎么算算 Big-O,核心就一句话: 忽略常数和低阶项,只保留增长最快的项。 举例: 13n² + 2n + 100 → O(n²) 为什么可以忽略?因为当 n 足够大时,n² 那一项会完全主导,2n 和 100 都微不足道。 所以: 3n → O(n) n² + n → O(n²) 2^n + n² → O(2^n) 常见复杂度量级(从小到大) 量级 名称 例子 O(1) 常数 数组按下标访问、哈希表查找 O(log n) 对...
堆与优先队列:Top K 问题的标准答案
发表于2026-01-17|基础
面试里有一类题出现频率极高: 从一个亿级数据里,找出最大的 10 个元素(Top K)。 如果你直接排序再取前 10,那是 O(n log n)。但如果用堆,可以做到 O(n log k)。 堆到底是什么,为什么这么强?今天讲透。 堆是什么堆是一种特殊的完全二叉树,它有一个关键性质: 大顶堆:每个节点的值都 ≥ 其子节点的值(根最大) 小顶堆:每个节点的值都 ≤ 其子节点的值(根最小) 注意,堆只保证”父大于子”,不保证左右子树之间的大小关系,也不像二叉搜索树那样全局有序。 堆还有一个巧妙的地方:它可以用数组来存储。 因为完全二叉树的结构是确定的,所以可以用下标表示父子关系: 下标 i 的左子节点:2i + 1 下标 i 的右子节点:2i + 2 下标 i 的父节点:(i - 1) / 2 用数组存储,省去了指针开销,这也是堆高效的原因之一。 堆的两种核心操作1. 插入元素(上浮)把新元素放到数组末尾,然后不断和父节点比较,如果比父节点大(大顶堆)就交换,直到满足堆的性质。 这个过程叫”上浮”,时间复杂度 O(log n)。 2. 删除堆顶(下沉)取出堆顶(最大&#x...
1…78910
avatar
高晓庄
Java / Go / Python
AI / RAG / Agent
Cloud Native / Kubernetes
文章
73
标签
209
分类
30
Follow Me
最新文章
腾讯 Hy4 首发速评:770B 跑分该怎么读2026-11-04
善待自己是一剂不保证有效的药方 — 听程乐松讲2026-09-10
听《十字路口》刘震云那一期,我突然不焦虑了——一个普通人的几个共鸣2026-09-08
关于"内卷"的经济学解释——读《人月神话》和薛兆丰之后2026-09-05
不确定性是人生唯一确定的事——我不再假装掌控一切2026-09-01
分类
  • AI31
    • Agent2
    • Architecture1
    • CV1
    • Dify1
    • LLM2
    • RAG1
  • Architecture3
标签
n8n Claude Code DFS Copilot 王阳明 HashMap 注意力机制 单元测试 多线程 QLoRA MetaGPT 工程化 开发范式 TDD 人生 开篇 Prompt 架构 Function Calling 工程 智能问数 Gemini 中年 MySQL Docker BabyAGI AI工作流 向量数据库 代码审查 Tool Use 函数式编程 Flannel 检索增强 网络排障 记忆 自动化 递归 云原生 单例模式 Self-RAG
归档
  • 2026-11 1
  • 2026-09 4
  • 2026-08 16
  • 2026-07 10
  • 2026-06 7
  • 2026-05 4
  • 2026-04 5
  • 2026-03 2
网站信息
文章数目 :
73
本站总字数 :
88.5k
本站访客数 :
本站总浏览量 :
最后更新时间 :
© 2025 - 2026 By 高晓庄