架构知识整理与思考(其四)
书接上回
建议,没有看过上一章的可以看一下,上一章“架构知识整理与思考(其二)”
感觉这都成链表了。
三生万物 软件架构
终于,我们进入了具体的软件架构讨论中。
软件架构是什么?相关定义如下:软件架构是指软件系统的高层设计,包括其结构、组件及其交互方式。它为软件系统提供了一个蓝图,描述了系统的主要组成部分、它们之间的关系以及设计和演化的关键决策。软件架构决定了系统的可维护性、扩展性、性能和可靠性。他包含整个系统的组件,关系,连接件,约束和原则。
很官方是说法,但是我们可以从结果导向来描述:
软件架构的终极目的就是最大化程序员的生产力,同时最小化系统的总运营成本。
阶段
开发阶段:人员多的情况下,可能会按照业务模块划分为多个事业部。
部署阶段:注意边界,减少服务
运行阶段:不要妄图使用多增加服务器资源的形式,加快响应。
当然这个很重要,但作为架构师应该更加注意如何设计优雅,高效的系统(事实上很多软件的cpu,内存资源都没有得到充分应用)
维护阶段:
维护的成本 取决于两个点:探秘和风险
探秘是对原本系统的挖掘,主要来自我们对于现有软件系统的挖掘,目的是确定新增功能或被修复问题的最佳位置和最佳方式。而“风险(risk)”,则是指当我们进行上述修改时,总是有可能衍生出新的问题,这种可能性就是风险成本。
保持可选项
之前也说了,整个软甲架构设计不可能至上而下的进行设计,因为在项目前期,你永远都无法收集足够多的信息,你不知道业务需求的变化点,业务的扩展点。在这种基调下,我们产生了“保持可选项”这种做法。
“保持可选项”:说白了就是和核心业务无关的一些设计,可以往后推迟。比如:我们都需要数据库,但是用mysql,oracle 甚至 redis哪些中间件,这个可以推迟。
《架构整洁之道》作者在提到这样一段有趣的话:
“那么如果其他人已经替我们做出了决策呢?譬如说,我们的公司已经指定了某个数据库,或某种Web服务,或某个框架,这时应该怎么办?通常一个优秀的软件架构师会假装这些决策还没有确定,并尽可能长时间地让系统有推迟或修改这些决策的能力。”
重复问题再讨论
所有的程序员都讨厌重复的代码,毋庸置疑且理应如此。
但是今天我们再从另外一个角度来看待这些问题。
比如一个PO与VO,他们都是描述业务对象,必然有很多相似的字段,那么是不是他们应该抽象为一个基本序列化对象呢,其实不然。
PO与VO有着不同的应用场景,更有着不同的更新速率,PO面向业务操作,VO承载前端页面信息。所以尽管有着重复字段,他们不应该合并。
说白了:职责不同,关注点不同,生命周期不同,更新迭代速度不同,他们不应该同等看待。
但是相对来说,我们可以使用其他方法来进行避免大量的CV代码,比如BeanCopy(注意字段属性和名称呀)
边界
在整个架构体系中,我觉得边界是最为重要的元素之一,划分边界,制定职责是每个架构师的基本功。我觉得我们不应该想着制造一个巨无霸的系统,解决系统的100%的问题,而是应该制定好边界,分层,分域的解决业务问题,毕竟你要考虑交付,周期,市场。
我觉得一个企业面对的问题是复杂的,抽象化线下业务场景到线上系统,他必然是一系列系统的集合。比如一个企业可能有:游供应链系统,内部ERP系统,CRM会员系统,还有业务中台充当BUS总线,数据中台进行挖掘客户,微信商城小程序进行销售等等。他们共同构成了整个企业的业务形态。
当然以上说的是系统与系统之间的边界,一不小心又扯远了。
我们把目光先foucs到单个系统内。

这条红线就是一个系统内模块的边界,很明显红线上方是业务逻辑,红线下方是数据库访问逻辑。同样很明显,使用了DIP依赖倒置的方式实现了模块之间的解耦。
这个架构边界线体现了“面向接口编程”的思想和“分层设计”的原则,强调高层业务逻辑与底层实现的解耦。箭头表明了依赖关系和数据流动方向。
整个架构流线图体现了以下两点:
业务规则只依赖抽象接口。
数据库访问逻辑通过实现接口为业务规则提供支持。
不完全边界
事物的发展必然有两方面,一方面我们强调理论基础,需要厘清模块边界;一方面又必须要注意需求的变化性,业务的不明确性,资源的限制问题等,又没有必要制定过于明确的边界。(道理等同于保持可选项那一章节)。
不完全边界是整个技术架构中的常态,反映了实际业务需求与技术实现之间的权衡。(架构师就是在不断的权衡中做出选择)
核心目标不是追求绝对的边界清晰,而是根据实际情况做出合理选择,保持架构的弹性和可维护性:
不完全边界是一种妥协,它牺牲了一部分边界的独立性,换取性能、效率或开发成本的优化。
合理性和控制力是关键:边界模糊或不完全的部分需要可控,且不应导致整体系统失去灵活性或可扩展性。
不完全边界的特点: 部分职责重叠、依赖存在、边界模糊、效率权衡(处于资源和性能的考虑,打破某些边界的独立性,选择更为紧密的集成方式)
理论基础:YAGNI原则
YAGNI 强调只实现当前明确需要的功能,而不为可能用到的功能预留过多复杂的架构。
如何体现 YAGNI 原则:
• 减少过度拆分:在初期,系统可以通过模块化组织,但避免过早地为每个模块独立编译和部署。
• 灵活应对变化:通过合理的接口设计,延迟决定完全解耦的边界,等需求成熟后再完善。
• 避免浪费资源:以最小的开发和维护成本满足当前业务需求,降低不必要的投资。
如何设计良性的不良边界
独立编译与部署后合并组件
这种方式是实现不完全边界的一个实际操作:将系统逻辑分解成多个模块(或微服务)进行开发,但最终以单一部署单元的形式发布。
这样做的好处是业务逻辑是清晰的,物理边界被弱化了,这样编译部署是快速的,且后期要转微服务也比较快。
采用策略模式实现单向边界
策略模式是一种经典的设计模式,可以帮助实现不完全边界的“方向性隔离“。
在边界不完全的情况下,策略模式通过定义行为接口,将逻辑的变化点隔离到实现类中。
核心模块只依赖接口,不关心具体实现,从而保持边界的稳定性。
门户模式
门户模式是一种为模块化架构引入边界的方式,但它强调模块的集中访问和管理。
核心思想:
提供一个统一的门户组件来协调不同模块或子系统之间的交互,减少模块间的直接依赖。门户组件通常通过接口或消息机制与模块交互。(有点像SOA下的BUS总线或者kafka消息流机制触达)
总结一下架构师在边界制定中的职责
架构师的一个重要任务是根据业务和技术需求,动态决定边界的设置和完全性程度。这包括以下几个方面:
1.预判未来可能的变化
识别扩展点:通过分析业务需求,判断哪些模块可能需要更灵活的边界。
2.延迟决策
控制架构复杂性:在项目初期尽量避免过度设计,推迟对边界完全性的决策。
通过接口保护边界:即使是目前的边界不完全,也要通过接口或适配器模式确保模块的逻辑不直接暴露。
3.平衡短期与长期利益
短期目标:快速交付、降低初始成本。
长期目标:保持架构的弹性,支持未来需求的变化。
架构师的职责:
- 识别哪些地方需要边界。
- 判断边界是否需要完全隔离。
- 在架构演进中,动态调整边界的实现方式。
通过这种方式,架构能够在复杂性和灵活性之间找到平衡,实现更合理的模块化设计。
浅谈隔离(部署单元)
边界的核心价值是什么?是资源的隔离,是为了更好地控制和优化资源的使用,同时实现系统的高可用性、可维护性和可扩展性
隔离的具体体现是什么?是线程,进程,或者说是一个个服务。
线程(内存与任务的隔离)
特性:
• 线程共享进程的内存空间。
• 隔离的粒度较小,更关注任务级别的独立性。
隔离方式:
• 线程之间通过栈内存隔离(每个线程有自己的栈空间)。
• 使用锁、信号量等机制防止共享资源的竞争问题。
适用场景:
• 并行计算:如 Web 服务器的多线程模型。
• I/O 密集型任务:通过多线程提高资源利用率。
进程级隔离:内存和资源隔离
特性:
• 进程有独立的内存空间,相互之间无法直接访问内存。
• 每个进程的资源(如文件描述符、网络端口)是独立的。
隔离方式:
• 操作系统内核提供进程间的隔离。
• 进程间通过 IPC(管道、消息队列、共享内存等)或网络通信。
适用场景:
• 需要更高可靠性和容错性,如分布式系统中的服务进程。
• 运行资源密集型任务的独立模块,如数据库进程。
服务级隔离:部署和扩展隔离
特性:
• 服务是一个独立的进程,但更强调“业务功能”的独立性。
• 服务可以部署在不同的机器上,甚至可以通过容器技术在相同机器上运行多个服务实例。
隔离方式:
• 网络协议(如 HTTP/gRPC)是服务间通信的主要形式,边界更为明确。
• 数据库、配置、缓存等资源通常是服务私有的,避免跨服务共享。
适用场景:
• 微服务架构:服务根据业务功能独立,易于扩展和部署。
• 多团队协作:每个团队负责自己的服务,解耦业务逻辑。
总结
边界划分的最终目的,是为了更好地控制和优化资源的使用,同时实现系统的高可用性、可维护性和可扩展性:
资源独立:
• 每个边界内的单元能够独立占用和管理资源(如内存、CPU、网络端口等),减少干扰。
• 进程和服务的边界隔离可以有效限制单点故障的影响。
容错性增强:
• 线程边界较弱,线程崩溃可能影响整个进程。
• 进程和服务边界较强,一个进程或服务崩溃不会直接影响其他进程或服务。
并行与扩展:
• 边界划分可以帮助系统更好地实现并行化(线程级并行、进程级并行)。
• 服务级边界允许通过水平扩展(增加服务实例)来提升系统吞吐量。
职责清晰:
• 在服务级隔离中,边界通过功能拆分变得更加明确(如按业务功能划分服务)。
• 边界明确后,团队或模块间的职责也更清晰,减少依赖冲突。
层次与策略
《架构整洁之道》中有这样一句话,我觉得概括了整个软件系统的:“本质上,所有的软件系统都是一组策略语句的集合。是的,可以说计算机程序不过就是一组仔细描述如何将输入转化为输出的策略语句的集合。”
层次
层次是架构中的逻辑分区,用来将系统的功能职责划分为不同的模块,每一层都有明确的职责和边界,并依赖于其他层次提供的功能。
特点:
抽象与隔离:
• 上层依赖下层提供的接口,不直接关注下层的具体实现。
职责分离:
• 每一层只关注特定的逻辑职责。】
顺序性:
• 通常遵循自顶向下调用(例如,UI 层调用业务层,业务层调用数据层)。
典型的分层架构:
• 表示层(Presentation Layer):负责与用户交互。
• 业务逻辑层(Business Logic Layer):封装核心业务逻辑。
• 数据访问层(Data Access Layer):管理数据库操作。
策略
策略是一种实现目标的方法或技术,通常是针对某个问题领域的解决方案,可以在不同的层次中实现。
特点:
灵活性:
• 不依赖具体的上下文,可以独立应用于不同场景。
针对性:
• 专注于解决某一类问题,例如缓存策略、负载均衡策略、事务管理策略。
实现多样性:
• 同一策略可以有多种实现(例如,缓存策略可以用 Redis,也可以用内存)。
典型的策略:
• 算法策略:选择不同的排序算法、加密算法等。
• 架构策略:微服务拆分策略、数据分区策略。
• 业务策略:订单分发策略、推荐系统中的推荐算法策略。
关系
层次与策略的关系可以总结为:层次提供组织框架,策略提供实现手段。
• 层次:解决的是系统的结构化问题,为架构提供一个清晰的逻辑框架。
• 策略:解决的是具体的实现问题,为层次的内部提供多样化的解决方案。
• 关系:层次提供稳定的骨架,策略注入灵活的血肉,使系统既保持统一性又具备适应性。
简单来说,层次是“骨架”,策略是“肌肉”,两者共同组成了健壮的系统架构。
整洁架构

一个良好的架构,应该具有以下特性:
独立于架构,可被测试、独立于UI、独立于数据库、独立于外部系统。
独立于架构(以下描述在我DeepSeek上的深度联想,真香啊,我写在此篇时恰好是1.28日除夕晚)
概念解构:何为"独立于架构"?
1.空间维度解耦:
// 错误示范:业务逻辑与框架耦合
class OrderController {async createOrder(@Res() response: ExpressResponse) {const data = await this.service.create(req.body);response.status(201).json(data); // 深度绑定HTTP框架}
}// 整洁架构实现
interface OrderPresenter {present(order: Order): void;
}class HttpOrderPresenter implements OrderPresenter {constructor(private response: Response) {}present(order: Order) {this.response.status(201).json(adaptToDTO(order));}
}
关键点:业务代码不感知任何传输协议(HTTP/GRPC/CLI)
2.时间维度隔离:
// 传统分层架构的渗透性腐蚀
@Entity
public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id; // JPA注解污染领域模型
}// 整洁架构的防护策略
class UserEntity {private UserId id; // 领域自有的ID概念
}class UserJpaEntity {@Idprivate Long persistenceId; // ORM模型
}
本质:领域模型的生命周期应超越任何持久化框架的存续周期
实践悖论:架构既是手段也是约束
1.架构选择的量子态现象:
| 业务阶段 | 适用架构模式 | 解耦策略 |
|---|---|---|
| 探索期 | 单体+模块化 | 接口隔离 |
| 成长期 | 微服务+事件驱动 | 上下文映射 |
| 成熟期 | 领域驱动设计 | 限界上下文 |
| 转型期 | 函数式架构 | 不可变数据结构 |
2.典型反模式警示:
# 框架主导的架构(Django式渗透)
class Order(models.Model): # ORM模型直接作为领域对象user = models.ForeignKey(User)total = models.DecimalField()def save(self, *args, **kwargs):# 业务逻辑混入持久化操作if self.total < 0:raise ValueErrorsuper().save(*args, kwargs)# 整洁架构改造方案
class Order:def __init__(self, user_id, items):self.user_id = user_idself.items = items@propertydef total(self):return sum(item.price * item.quantity for item in self.items)class OrderRepository:def save(self, order: Order): orm_order = OrderORM.convert(order)orm_order.save()
救赎之道:业务规则的执行不依赖任何持久化机制
动态平衡法则
-
架构适应度函数:
function architectureFitness(context) {const { changeFrequency, teamSize, bizComplexity } = context;// 解耦度计算公式const decouplingFactor = Math.log2(changeFrequency * bizComplexity);// 架构复杂度阈值const maxLayers = teamSize / 3; // 康威定律量化return decouplingFactor <= maxLayers ? '适度架构' : '过度设计'; } -
决策平衡矩阵:
| 变更维度 | 过早抽象成本 | 延迟决策成本 | 平衡点判断标准 |
|---|---|---|---|
| 支付渠道扩展 | 高 | 低 | 实现基础接口即可 |
| 多租户改造 | 低 | 高 | 需要预留身份隔离抽象层 |
| 国际化支持 | 中 | 中 | 使用策略模式动态加载资源 |
案例推演:电商系统演进史
每个架构演进节点都在证明:真正的架构是业务诉求在特定时空条件下的最优映射。当我们在代码中写下interface OrderService时,本质上是在构建抵御技术变迁的第一道防线,但同时也需警惕抽象层变成新的"架构牢笼"。
架构师的元认知
1.破界思维训练法:
def challenge_assumptions(arch):for layer in arch.layers:if layer.is_core:print(f"尝试将{layer.name}替换为不同技术栈")print(f"改造成本评估:{layer.calculate_rewrite_cost()}")class Architecture:def __init__(self):self.layers = [Layer("Web", False),Layer("Domain", True), # 真正的核心Layer("Infra", False)]
2.架构健康度检查表:
[ ] 业务规则是否能在不启动Web容器的情况下测试
[ ] 能否在1天内替换数据库类型
[ ] 领域模型是否包含任何框架注解
[ ] 新业务需求是否主要修改领域层
[ ] 基础设施层是否可插拔
最终极的"独立于架构",是培养出在代码中看见业务本质,在需求中洞见架构趋势的双重视野。就像优秀的建筑大师既能驾驭钢筋混凝土,又能让空间服务于人的真实需求一样,真正的架构师要让技术架构在业务土壤中自然生长,而非强行扭曲业务来适应架构范式。
总结
架构设计的理想目标
• 技术无关性:
• 不依赖于特定技术栈或框架,随时可以替换实现。
• 业务驱动:
• 以业务逻辑为核心,技术细节服务于业务需求。
• 易于扩展:
• 增加新功能时不需要修改现有代码,只需添加新的模块。
• 敏捷性:
• 支持快速迭代开发和变更响应。
• 可维护性:
• 代码清晰、可测试,易于排查问题和维护。
• 高性能:
• 架构在满足上述目标的同时,应考虑系统的性能优化。
总结:架构设计的本质
一个好的架构就是在不断变化中保持稳定的能力:
• 它能在需求变更时快速适配。
• 它能隔离变化,将影响最小化。
• 它能在复杂的技术栈下,始终以清晰的边界和职责为中心。
通过明确的边界和独立性设计,你的系统能够灵活面对变化,同时在演进中始终保持核心逻辑的稳定性和一致性。
横跨型变更(Cross-Cutting Concern)
定义:
指需要同时修改多个系统层级(展示层/应用层/领域层/基础设施层)或跨越多个限界上下文的变更。这类变更往往涉及系统核心业务规则的调整,或全局性技术栈升级。
典型场景:
- 多租户改造:需要在UI、权限校验、数据存储等各层增加租户隔离逻辑
- 国际化支持:涉及前端语言包、后端多时区处理、数据库字符集调整
- 安全审计增强:从接口鉴权到数据落盘的全链路审计跟踪
- 核心领域模型重构:如电商系统将"订单"拆分为"交易单"和"物流单"
破坏力评估公式:
变更成本 = 影响模块数 × 技术债务系数 × 团队认知差异度
横跨型变更的四大挑战
架构腐蚀加速
每次横跨变更都会在架构中留下"补丁",逐渐形成耦合网络
测试复杂度激增
需要同时验证:
- 领域逻辑正确性
- 上下游服务兼容性
- 数据一致性
- 性能基线
团队协作瓶颈
技术债利滚利效应
未妥善处理的横跨变更会指数级增加后续修改成本
六维处理策略
1.防腐层设计(Anti-Corruption Layer)
// 旧订单服务适配器
public class LegacyOrderAdapter {public ModernOrder convert(LegacyOrder legacyOrder) {return ModernOrder.builder().id(legacyOrder.getOrderNo()).amount(legacyOrder.getTotal().subtract(legacyOrder.getTax())).build();}
}// 新领域模型
public class ModernOrder {private OrderId id;private Money amount;
}
作用:隔离新旧系统,控制变更影响范围
2.事件溯源(Event Sourcing)
class OrderService:def __init__(self, event_store):self.event_store = event_storedef create_order(self, command):event = OrderCreatedEvent(command.order_id, command.items,datetime.now())self.event_store.publish('order_stream', event)# 查询端通过投影构建视图
class OrderProjection:def __init__(self):self.orders = {}def apply_event(self, event):if isinstance(event, OrderCreatedEvent):self.orders[event.order_id] = {'items': event.items,'status': 'created'}
优势:核心业务变更只需追加新事件类型,不影响已有逻辑
3.上下文映射(Context Mapping)
## 支付上下文与订单上下文的协作
- 关系类型:客户-供应商
- 通信协议:RESTful API + 回调通知
- 防腐策略:* 订单侧定义PaymentGateway抽象接口* 支付侧提供OpenAPI规范文档
- 同步机制:每季度进行契约测试对齐
4.特性开关(Feature Toggle)
// 功能标记配置
const featureFlags = {NEW_TAX_CALCULATION: true,LEGACY_CHECKOUT: false
};// 业务逻辑分支
function calculateTax(order) {if (featureFlags.NEW_TAX_CALCULATION) {return applyRegionalTaxRules(order);} else {return legacyTaxCalculation(order);}
}
价值:实现灰度发布,降低全链路变更风险
5.CQRS模式
// 命令端
public class OrderCommandService {public async Task Handle(CreateOrderCommand cmd) {var order = new Order(cmd.Items);await _repository.Save(order);await _eventBus.Publish(new OrderCreatedEvent(order.Id));}
}// 查询端
public class OrderQueryService {public OrderDto GetOrder(Guid id) {return _readModelCache.Get(id);}
}
收益:分离读写模型,独立演进查询逻辑
6.契约测试(Pact Testing)
# consumer订单服务的契约定义
interactions:- description: 创建订单后支付request:method: POSTpath: /paymentsbody:orderId: "123"amount: 100.00response:status: 201headers:Content-Type: application/json
作用:保障跨服务变更的兼容性
谦卑对象
谦卑对象模式最初的设计目的是帮助单元测试的编写者区分容易测试的行为与难以测试的行为,并将它们隔离。其设计思路非常简单,就是将这两类行为拆分成两组模块或类。其中一组模块被称为谦卑(Humble)组,包含了系统中所有难以测试的行为,而这些行为已经被简化到不能再简化了。另一组模块则包含了所有不属于谦卑对象的行为
实现细节
刚刚其实也说了,架构的一些细节:
这里额外在提一下:
数据库只是实现细节,web是实现细节,应用程序框架也是实现细节。
写在最后的一些话
我不太能保证后面还有没有一个总结和实战了,对了我有个思维导图,GitMind的,我先开一下,地址是:
链接: https://gitmind.cn/app/docs/mkrarxey
密码: 6787
然后,看这本书始于一会回家探亲,然后巨空,找不到好看的小说书。于是开始了看起了这个,后面越看越嗨。
再后来,我担任了我们公司的华东区域技术经理兼架构师(口头上的,ppt任命的),然后主导一个复杂项目的落地。也是因为第一次担任技术负责人,总想着尽善尽美,结果最小MVP未评估好,两次严重Delay。
整个过程中,令我感触最大的不是技术栈,选型啥的,而是项目管理。资源紧缺,反加班情绪高涨,客户无故增加需求,虚空撤我职,种种狗屁倒灶,却又真实存在的事情。
于是更加想找点方法论,比如:
1.项目什么阶段,应该做什么样的设计?(通过组件张力图,表示REP,CCP,CRP在不同的阶段有不同的表示)
2.技术债务问题,如何处理?(重构+前期的预设+Sonnar代码扫描)
3.短期利益与长期目标如何平衡?(根据项目资源,交期,进行平衡。迭代演进过程)
4.需求与业务的变化性与框架模块边界的定义应该如何?(迭代演进)
5.如何在有限资源下,保证主流程贯通(测试用例驱动,V模型)
6.架构的一些权衡点的考虑(YAGNI原则,有些指标天生互斥,一如安全性和性能,在架构上属于权衡点,只能选其一)
后面的这些是AI的补充:
7.团队认知差异导致重复造轮子(每日站会同步进展+模块owner机制)
8.文档资产随时间失效(代码即文档+架构决策记录ADR)
9.自动化基建滞后(首个迭代即搭建CI/CD流水线)
10.技术选型短视(建立技术雷达评估矩阵)
11.第三方依赖失控(建立供应商AB方案+版本门禁)
12.上线风险评估缺失(预埋暗开关+灰度发布策略)
13.过度设计反噬(建立架构适应度函数验证,这个可以有,我最近在看的《分布式系统架构-架构策略与难题求解》,恰巧看到这一个章节)
14.性能问题滞后暴露(在MVP阶段建立性能基线与监控)
15.跨团队协作低效(统一契约测试+接口模拟服务)
16.技术债可视化不足(SonarQube技术债看板量化)
17.生产环境止血能力弱(构建混沌工程演练机制)
最后的最后,如果我后面有时间,我会根据我实际的经验+《分布式系统架构-架构策略与难题求解》这本书内的一些实操,写一篇“架构知识整理(其五)”作为补充(PS:我之前还想着给一张当时在架构考试的时候,那个的架构设计风格的和耦合关系图,但是后面想想,实在有点太偏理论)。
而现在,我想去在我的电脑上玩玩k8s,我刚刚下载了Ubuntu的轻量虚拟机工具。当然还有空的话,我也要更新一下自己的简历去了。
相关文章:
架构知识整理与思考(其四)
书接上回 建议,没有看过上一章的可以看一下,上一章“架构知识整理与思考(其二)” 感觉这都成链表了。 三生万物 软件架构 终于,我们进入了具体的软件架构讨论中。 软件架构是什么?相关定义如下…...
组合数:从基础理论到高效算法实现
文章目录 一、组合数学基础二、经典算法实现三、取模运算与高效算法四、算法选择策略五、典型应用场景六、进阶技巧七、常用模板总结: 一、组合数学基础 1.1 组合数定义 在离散数学中,组合数 C ( n , k ) C(n,k) C(n,k)(记为 ( n k ) \dbi…...
【C++】B2124 判断字符串是否为回文
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 💯前言💯题目描述输入格式:输出格式:样例: 💯方法一:我的第一种做法思路代码实现解析 💯方法二:我…...
DeepSpeed Zero 解读
目录 主要参考: 分布式训练基础 – 数据并行,模型并行,流水线并行 DeepSpeed Zero 的各个 stage 介绍 针对Zero 的各个stage,这里有三个点需要额外再说一下: 各个stage,要实现将某一部分参数分配到不同GPU,…...
Windows 安装Linux子系统
文章目录 一、启用虚拟化二、安装子系统1. 查看所有官方支持的 WSL 发行版2. 安装 Ubuntu3. 安装非官方发行版(如 CentOS)三、启动和更新子系统1. 启动Ubuntu终端2. 更新系统四、管理已安装的发行版在 Windows 的 WSL(Windows Subsystem for Linux)中,除了 Ubuntu,你还可…...
基于Spring Security 6的OAuth2 系列之八 - 授权服务器--Spring Authrization Server的基本原理
之所以想写这一系列,是因为之前工作过程中使用Spring Security OAuth2搭建了网关和授权服务器,但当时基于spring-boot 2.3.x,其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0,结果一看Spring Security也升级…...
【LeetCode 刷题】回溯算法(5)-棋盘问题
此博客为《代码随想录》二叉树章节的学习笔记,主要内容为回溯算法棋盘问题相关的题目解析。 文章目录 51. N皇后37. 解数独332.重新安排行程 51. N皇后 题目链接 class Solution:def solveNQueens(self, n: int) -> List[List[str]]:board [[. for _ in rang…...
PaddleOCR 截图自动文字识别
春节假期在家无聊,撸了三个小工具:PC截图编辑/PC录屏(用于meeting录屏)/PC截屏文字识别。因为感觉这三个小工具是工作中常常需要用到的,github上也有很多开源的,不过总有点或多或少的小问题,不利于自己的使用。脚本的编…...
算法题(48):反转链表
审题: 需要我们将链表反转并返回头结点地址 思路: 一般在面试中,涉及链表的题会主要考察链表的指向改变,所以一般不会允许我们改变节点val值。 这里是单向链表,如果要把指向反过来则需要同时知道前中后三个节点&#x…...
梯度、梯度下降、最小二乘法
在求解机器学习算法的模型参数,即无约束优化问题时,梯度下降是最常采用的方法之一,另一种常用的方法是最小二乘法。 1. 梯度和梯度下降 在微积分里面,对多元函数的参数求∂偏导数,把求得的各个参数的偏导数以向量的形式…...
独立开发者小程序开发变现思路
随着移动互联网的发展,小程序已成为许多独立开发者展示才能和实现收入的重要平台。作为一种轻量级的应用形态,小程序具有开发成本低、用户体验好、传播效率高等优势,为独立开发者提供了多种变现方式。然而,要想实现真正的盈利&…...
软件测试 - 概念篇
目录 1. 需求 1.1 用户需求 1.2 软件需求 2. 开发模型 2.1 软件的生命周期 2.2 常见开发模型 2.2.1 瀑布模型 2.2.2 螺旋模型 1. 需求 对于软件开发而言, 需求分为以下两种: 用户需求软件需求 1.1 用户需求 用户需求, 就是用户提出的需求, 没有经过合理的评估, 通常…...
使用SpringBoot发送邮件|解决了部署时连接超时的bug|网易163|2025
使用SpringBoot发送邮件 文章目录 使用SpringBoot发送邮件1. 获取网易邮箱服务的授权码2. 初始化项目maven部分web部分 3. 发送邮件填写配置EmailSendService [已解决]部署时连接超时附:Docker脚本Dockerfile创建镜像启动容器 1. 获取网易邮箱服务的授权码 温馨提示…...
基于springboot+vue的航空散货调度系统
开发语言:Java框架:springbootJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:…...
自学习记录-编程语言的特点(持续记录)
我学习的顺序是C -> python -> C -> Java。在讲到某项语言的特点是,可能会时不时穿插其他语言的特点。 Java 1 注解Annotation Python中也有类似的Decorators。以下为AI学习了解到的: Java的Annotation是一种元数据(metadata)&a…...
[MRCTF2020]Ez_bypass1(md5绕过)
[MRCTF2020]Ez_bypass1(md5绕过) 这道题就是要绕过md5强类型比较,但是本身又不相等: md5无法处理数组,如果传入的是数组进行md5加密,会直接放回NULL,两个NuLL相比较会等于true; 所以?id[]1&gg…...
MATLAB实现多种群遗传算法
多种群遗传算法(MPGA, Multi-Population Genetic Algorithm)是一种改进的遗传算法,它通过将种群分成多个子种群并在不同的子种群之间进行交叉和交换,旨在提高全局搜索能力并避免早期收敛。下面是多种群遗传算法的主要步骤和流程&a…...
强化学习笔记(5)——PPO
PPO视频课程来源 首先理解采样期望的转换 变量x在p(x)分布下,函数f(x)的期望 等于f(x)乘以对应出现概率p(x)的累加 经过转换后变成 x在q(x)分布下,f(x)*p(x)/q(x) 的期望。 起因是:求最大化回报的期望,所以对ceta求梯度 具体举例…...
【MATLAB例程】TOA和AOA混合的高精度定位程序,适用于三维、N锚点的情况
代码实现了一个基于到达角(AOA)和到达时间(TOA)混合定位的例程。该算法能够根据不同基站接收到的信号信息,自适应地计算目标的位置,适用于多个基站的场景 文章目录 主要功能代码结构运行结果程序代码 主要功…...
使用Pygame制作“青蛙过河”游戏
本篇博客将演示如何使用 Python Pygame 从零开始编写一款 Frogger 风格的小游戏。Frogger 是一款早期街机经典,玩家需要帮助青蛙穿越车水马龙的马路到达对岸。本示例提供了一个精简原型,包含角色移动、汽车生成与移动、碰撞检测、胜利条件等关键点。希望…...
深度解读 Docker Swarm
一、引言 随着业务规模的不断扩大和应用复杂度的增加,容器集群管理的需求应运而生。如何有效地管理和调度大量的容器,确保应用的高可用性、弹性伸缩和资源的合理分配,成为了亟待解决的问题。Docker Swarm 作为 Docker 官方推出的容器集群管理工具,正是在这样的背景下崭露头…...
8、面向对象:类、封装、构造方法
一、类 1、定义 类:对现实世界中事物的抽象。Student 对象:现实世界中具体的个体。张三、李四 这些具体的学生 面向对象的特征:抽象、封装、继承、多态 OOP: Object Oriented Programming(面向对象编程) 类和对象…...
AI时代IT行业职业方向规划大纲
一、引言 AI时代的颠覆性影响 ChatGPT、Midjourney等生成式AI对传统工作模式的冲击 案例:AI编程助手(GitHub Copilot)改变开发者工作流程 核心问题:IT从业者如何避免被AI替代,并找到新机遇? 二、AI时代…...
STM32 旋转编码器
旋转编码器简介 旋转编码器:用来测量位置、速度或旋转方向的装置,当其旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的方波信号,读取方波信号的频率和相位信息即可得知旋转轴的速度和方向 类型:机械触点式/霍尔传…...
大模型领域的Scaling Law的含义及作用
Scaling Law就像是一个“长大公式”,用来预测当一个东西(比如模型)变大(比如增加参数、数据量)时,它的性能(比如准确率)会怎么变化。 它能帮助我们提前知道,增加多少资源…...
从 C 到 C++:理解结构体中字符串的存储与操作
对于刚入门 C/C 的程序员来说,字符串的存储和操作可能是个容易混淆的知识点。在 C 中,std::string 提供了非常友好的接口,我们可以轻松地在结构体中使用字符串类型,无需关注底层细节。然而,在 C 语言中,字符…...
git基础使用--4---git分支和使用
文章目录 git基础使用--4---git分支和使用1. 按顺序看2. 什么是分支3. 分支的基本操作4. 分支的基本操作4.1 查看分支4.2 创建分支4.3 切换分支4.4 合并冲突 git基础使用–4—git分支和使用 1. 按顺序看 -git基础使用–1–版本控制的基本概念 -git基础使用–2–gti的基本概念…...
【算法】回溯算法专题③ ——排列型回溯 python
目录 前置小试牛刀回归经典举一反三总结 前置 【算法】回溯算法专题① ——子集型回溯 python 【算法】回溯算法专题② ——组合型回溯 剪枝 python 小试牛刀 全排列 https://leetcode.cn/problems/permutations/description/ 给定一个不含重复数字的数组 nums ,返…...
Vue2.x简介
Vue2.x简介 Vue2.x的版本介绍Vue2.x的两大组件库 Vue2.x的版本介绍 Vue2.x是vue.js的第二个主要版本,最初版发布于2016 年,最终版发布于2023年12月24日(版本号:2.7.16,版本名:Swan Song(绝唱&a…...
FFmpeg:多媒体处理的瑞士军刀
FFmpeg:多媒体处理的瑞士军刀 前言 FFmpeg 是一个功能强大且跨平台的开源多媒体框架,广泛应用于音视频处理领域。 它由多个库和工具组成,能够处理各种音视频格式,涵盖编码、解码、转码、流处理等多种操作。 无论是专业视频编辑…...
