品牌型网站建设哪家,公司网站创建,镇江企业网站制作,合肥网达软件有限公司软件设计的第一性原理#xff0c;是结构化抽象。术生于道#xff0c;技术生于原理。引语所谓的第一性原理#xff0c;就是无论使用什么方法论#xff0c;都无法绕过的那最最基础的部分。无论是 DDD 设计#xff0c;还是面向模式的架构设计#xff0c;或 微服务架构#… 软件设计的第一性原理是结构化抽象。术生于道技术生于原理。引语所谓的第一性原理就是无论使用什么方法论都无法绕过的那最最基础的部分。无论是 DDD 设计还是面向模式的架构设计或 微服务架构均建基于结构化抽象。何为结构化抽象 先回答 “何为抽象” 与 “何为结构化” 两个问题。何为抽象 “编程漫谈三抽象” 一文阐述了什么是抽象及在编程与计算中的意义 “代码抽象与分层” 则列举了从代码中提炼出来的六类抽象涵盖了编程开发中常见的实体及处理。何为结构化 结构是事物的组成元素及关联和作用。 “编程漫谈十一编程概要” 一文阐述了编程中的各种数据结构及控制结构“软件的组合结构从指令到软件” 则阐述了组合元素的方法与结构。结构化分为数据结构化和控制结构化。数据结构化指海量数据的组织和存储及需要满足的约束比如一致性、完整性等控制结构化是指操作的组织和执行以及需要满足的约束。软件本质上是一种可动态而弹性变化的逻辑装置。结构化即是将逻辑进行抽象、提炼、分离、聚合构建成更加缜密、动态、弹性的结构流。逻辑是思维意识的一种形式。软件设计与开发是与自己的思维意识进行抗争与和解。理念设计与开发软件设计与开发工作渗透着结构化抽象的思想。譬如软件建模。是对大量原始数据进行结构化组织使之更加有序、有意义、可交互。数据存取。在建立对数据的组织抽象之后就要进行数据的存取操作。数据是规则的还是不规则的 数据量有多少及增长速度如何 是否要进行缓存 选取合适的数据存储组件。数据存储组件是对海量数据存储和访问的结构化抽象。流程构造。在确定数据存取方案后需要构建完整的流程。流程可以使用时序图来表示。流程包含前置、操作与契约。前置是进行操作需要满足的条件操作则是获取数据或请求某种执行契约是在完成操作之后必须满足的一系列断言。完整流程通常是“前置-操作-契约”的子流程的有序组合。编程实现。需要评估潜在变化的部分将通用的部分与易变化的部分相分离。设计模式设计模式是对象职责及交互的结构化抽象是体现结构化抽象思想的基本单元。可参阅“软件设计要素初探基础设计模式概览” 。架构模式是基于设计模式的更高层次的结构化抽象。可参阅“软件设计要素初探架构模式” 。设计模式和架构模式主要应对软件的业务可扩展性难题。技术机制在软件设计中技术是绕不开的一道槛。技术的作用在于在指定的场景下所执行的操作效果必须满足某种约束。技术机制是将多个相关联的结构化抽象进行聚合后的成品。异步比如先快速响应客户端再进行请求处理。其结构化抽象是操作相对于主进程的执行耗时与实际执行耗时无关。幂等比如处理资金问题必须考虑幂等问题即同一个请求执行多次的效果必须与执行一次的效果等同。幂等的结构化抽象是操作的主效果与操作次数无关。事务比如多个关联数据的插入、更新和删除必须保证原子性。要么全部执行要么一个都不执行。需要使用事务来保证。事务的特性是ACID结构化抽象是关联数据集合在操作前后必须满足某种一致性约束。确定“关联数据集的一致性约束”是关键其实现是还原点、快照与回滚日志。并发大量请求或数据集的处理使用串行的方式效率难以满足性能或吞吐量要求需使用并发的方式充分利用多核CPU资源。结构化抽象是多个相互独立的执行单元。这些执行单元拥有独立的CPU和缓存所使用的内存可以为共享内存型和独立内存型。同步在并发场景下要保证多个执行单元比如线程、进程等能够看到共享内存的最新更新值。同步的本质是确保指定顺序执行避免不确定的执行顺序带来不确定性的结果。其结构化抽象是临界区。临界区是约束执行顺序的一种结构。框架应用的组件、配置与启动可以做成通用的框架和脚手架反复使用快速启动和部署一项工程减少不必要的重复工作量。框架的结构化抽象是将工程中的配置、部署与启动、运行结构、通用任务进行提炼并形成固定的模式应用只需要关注可变的业务部分。限流突发的峰值流量为了避免瞬间占满和击垮服务器的资源和服务能力需要进行限流。其结构化抽象是在指定时间间隔内的通过许可数必须满足指定规格。缓存对于热点数据为了避免反复从源存储获取增大对存储的访问压力可以使用缓存来存储热点数据增大命中率提升性能减少对存储的不必要的访问压力。缓存的结构化抽象是使用少而精的空间优先于大而全的空间的搜索。“少而精”是指聚焦应用的经常被访问的热点数据。缓存的衡量指标是命中率和过期时间操作是缓存与源存储的读写同步。降级当非核心的依赖不可用时可以及时切断依赖舍小取大保证整体服务正常运行不受局部影响。降级的结构化抽象是是主备策略的设计与切换机制。重试当处理数据发生错误时可以进行重试来进行补偿和恢复。重试的结构化抽象是至少且通常只需保证一次操作成功。切面比如耗时统计。耗时统计与操作的执行内容无关仅关注操作的耗时。切面的结构化抽象是操作的非功能属性与功能本身的解耦。代理比如请求的负载均衡。不是直接执行目标操作而是创建一个代理由这个代理转发请求和执行目标操作。代理的结构化抽象是隐藏目标操作。版本号版本号通常用于实现非阻塞式并发即乐观锁。其结构化抽象是一个严格保证特征数值单调递增的机制。实践示例分析要对问题进行结构化抽象需要先提取问题的结构特征。可以分别从数据结构化和操作结构化两个角度来思考。分页比如分页功能是大多数信息系统管理的必备功能之一。怎么实现一个通用的分页功能呢 从数据结构化来思考其结构要素为偏移量、页大小、起始和结束位置。分页本身和获取何种对象无关。从操作结构化来思考其结构要素为1. select columns from table where condition limit offset, size ; 2. count distinct(id) from table where condition limit offset, size .columns , table, condition 都是可以根据具体业务来动态生成的而整个 SQL 的骨架是固定的。table 不一定指 DB , select , count 也不一定是 DB 的 sql 它只是表示在指定搜索条件下进行对象选择与统计的操作语义。columns , table, cond 的动态生成可以使用泛型和回调函数来传入和处理。限购限购是指定时间内指定 key 的实体允许通过的许可数量。与限流是同一类结构化抽象。许可数量是一个全局性约束。假设去掉“指定时间”的约束只限制许可数量 其结构化抽象是dec if total - count(key) 0. 并发的场景下total - count(key) 0 的值需要进行全局同步。如果加上“指定时间”的约束还需要考虑高并发场景下 dec if total - count(key) 0 的操作耗时。如果指定时间内不允许超过限购数量强约束则必须对 dec if total - count(key) 0 进行加锁吞吐量取决于操作耗时而不是指定的限购数如果指定时间内可允许暂时地超过限购数量弱约束则可参考限流算法。数据同步数据同步的结构化抽象是将源存储 S1, S2, ..., Sn 的数据复制到目标存储 D 。数据同步分为两种不同的场景有实时同步和离线同步。实时同步对数据延迟性容忍非常低离线同步则要求更快的吞吐量。实时同步通常采用流式同步通过接收消息流来处理。操作的结构化是Receiver (msg) - Format(msg) - Save for each msg . msg 是源存储中的一条数据或一个单位数据集。离线同步通常采用批量处理实现方式是批量获取数据并批量格式化后存储。操作的结构化是Divide(S) into N part(S) ; Select part(S) Then Format part(S) and Save for each part(S) 。可以根据业务唯一 ID 实现一个通用的 Divide 算法。离线同步要注意 format 的超时和健壮性处理记录下异常以便重试同时不因单个数据处理失败而中断整体流程流式同步则要注意控制好并发情形下的准确性。由于对吞吐量要求比较高往往采用乐观锁的方式找到某种能够控制全局版本号单调递增的机制或者尽量避免“多表同步到单表”的场景【并发场景下会带来更多复杂性】。积累抽象在实际工作中可以反思和提炼设计中所用到的结构化抽象。如果现有的结构化抽象及组合难以解决问题是否需要新的结构化抽象 创建新的结构化抽象并使之与已有的进行组合和集成。规模化挑战如果程序媛猿面对的是几万的数据量那是可以夜夜笙歌的。然而现实情况是面对的是亿级以上规模的数据量且数据量仍然在指数级增长。为了人类社会的无理性发展程序媛猿们真是费尽了心思花白了头。为了应对亿级规模的数据量并发、分布式等方案层出不穷结合变化的业务场景又衍生出更多的挠人烧脑的复杂问题。如何应对呢规模化挑战的结构化抽象是在指定时间内每秒处理的请求/单位数据集的吞吐量处理一个请求或单位数据集的平均响应时间以及在流量剧烈变化时的弹性扩展能力。并发并发和并行机制取代了串行机制。单CPU和单机的性能基本抵达瓶颈只能从多核CPU和多机上想办法。将要处理的数据量分解为多个相互独立的子数据集并在不同的执行实体里相互独立地执行。比如线程池Fork/Join Map-Reduce 执行模型。并发和并行虽然解决了单机性能不足的问题却引发了更多的问题。同步有了并发执行之后由于有些资源是共享的而一些热点数据往往被多个执行实体同时读取和修改又产生了竞争问题。为了解决竞争引入了同步机制。大量对同一资源、数据的操作进行同步引起性能问题。缓存对于热点数据的读取和操作通过“空间换时间”的策略使用缓存来提升性能降低对源存储的访问压力。限流由于允许并发请求进入则必须应对瞬间的峰值流量可见世态。限流必须有度不能因噎废食。需要对系统承载的负荷及极限负荷进行测量根据测量值来确定一个可动态调整的限流值。极限负荷测量即是压测。降级由于业务特性的不同环境的不稳定波动以及采用方案的局限性依赖服务有可能出现部分失败对于调用极其频繁的服务来说依赖服务的少许失败可能导致上层的雪崩效应。因此在依赖服务出现问题时必须进行适当的降级熔断。测量为了避免大流量或大数据结构导致软件运行出现问题降低维护成本不能仅仅停留在定性分析上还要进行量化。需要对系统进行仔细的测量。服务接口的 RT 和 吞吐量 如何 存取操作耗时如何 消息处理耗时和吞吐量如何 内存占用如何 大数据对象占用内存多大 能够承载的极限流量有多大 能够承载的极限对象大小是多大 指定时间段的失败数和失败率有多大 集群若以单机视角去考虑问题就会殚精竭虑地在“并发、同步、缓存、限流、降级”等上做到极致就像在单核时代将CPU主频做到极致一样。然而即使做到极致为了峰值流量所构建的机器资源在平均流量场景下会造成很大的浪费并且很难预估峰值流量会在什么时候来到。如果有一个超级大的聚合的池化资源总可以提供足够强大而弹性的CPU计算能力、内存能力、磁盘空间那么以上规模化引起的问题也将迎刃而解。这个超级大的聚合的池化资源就来自于构成集群的分布式系统的资源虚拟化后的能力即云计算能力。可视化为了从数据集中发现整体性的规律和趋势通过将大量数据集进行可视化拥有一个简明的全局视角。AI以数据为基础以规则集为准绳训练机器通过基本的规则集与数据的计算而获得某种“学习”能力从而能够分析更多的数据集调整现实活动和方式获得人力所无法得到的见解和经济效益。经验与洞见招聘或找工作的人常常说要“工作经验多少年才行”然而在软件设计中却容易“有经验而无洞见”。经验是什么经验是工作中遇到的问题及解决方案。有些问题只有在规模达到足够大的时候才会出现而大多数问题只要根据原理就能推导出来。在软件世界里并没有一成不变的最佳经验。洞见是什么洞见来自于究根追源从最基本的公理进行推导得出定理和定律从而能够预知问题。逻辑本质上是一种数学结构而数学正是能够进行推导的严密思维体系。软件设计的洞见来自哪里 究根追源软件逻辑建始于两条公理1 1 2机器的字长有限内存有限执行指令需要 CPU 时钟周期几乎所有软件问题都是这两个基本要素的组合和叠加而产生的。软件设计崇尚“自顶向下”的方式然而要获得洞见却需要“自底向上”的思考和推导通过多个层次的结构化抽象来建立。万变不离其宗。注意到第二条公理描述了现实系统的局限性。局限性正是经验的用武之地。在初期可以 80% 依据经验20% 依据原理而在后期则应该 80% 依靠原理20% 依靠经验。那么不依靠经验应该怎么做呢 举一个 API 调用的例子。可以测量这个 API 的平均耗时耗时分布大体了解这个 API 的对外输出指标。API 超时是因为什么呢 可能是网络环境波动导致。很难通过设计和开发优化环境的波动。如果不是从 API 的实现层面来说很可能是因为并发的大流量导致了竞争加剧线程死锁或者大量线程阻塞。API 超时又会导致多个子系统间数据不一致。可见并发与大流量是系统必须要面对的“对手”。并发与大流量一定需要通过工作经验来获得吗非也。并发与大流量的场景是可以模拟的。可以通过原理推导结合实验来模拟各种现实场景测量数据 并制订应对方案。 这是细功夫也是洞见的产生之源。小结本文阐述了软件设计中的结构化抽象的理念及实践方法涉及设计与开发、设计模式、技术机制、示例分析、规模化挑战及设计中的经验与洞见。结构化即是将逻辑进行抽象、提炼、分离、聚合构建成更加缜密、动态、弹性的结构流。做软件设计要同时看到骷髅与美人。论理要看到骷髅论情要看到美人。理即是结构化抽象。原文链接https://www.cnblogs.com/lovesqcc/p/11220727.html.NET社区新闻深度好文欢迎访问公众号文章汇总 http://www.csharpkit.com