技术债

关于技术债务的文章,尽管实践中会堆积技术债,但这个概念并不在我们的工作中频繁出现。这篇文章就系统性讲讲技术债,让大家避免知其然,不知其所以然。 一、技术债是什么 技术负债(英语:Technical debt),又译技术债,也称为设计负债(design debt)、代码负债(code debt),是编程及软件工程中的借鉴了财务债务的系统隐喻。指开发人员为了加速软件开发,在应该采用最佳方案时进行了妥协,改用了短期内能加速软件开发的方案,从而在未来给自己带来的额外开发负担。这种技术上的选择,就像一笔债务一样,虽然眼前看起来可以得到好处,但必须在未来偿还。软件工程师必须付出额外的时间和精力持续修复之前的妥协所造成的问题及副作用,或是进行重构,把架构改善为最佳实现方式。 1992 年,沃德 · 坎宁安首次将技术的复杂比作为负债。第一次发布代码,就好比借了一笔钱。只要通过不断重写来偿还债务,小额负债便可以加速开发。但久未偿还债务会引发危险。复用马马虎虎的代码,类似于负债的利息。整个部门有可能因为松散的实现,不完全的面向对象的设计或其他诸如此类的负债而陷入窘境。 二、技术债表现 技术债与其他债务本身一样,是一种透支行为,通过牺牲未来来满足当下的一些需求。也跟其他债务一样,技术债务也有利息,而且随着时间利滚利,会成为埋在项目里的定时炸弹。如果产品长期的可持续的发展,那么技术债的重要性是毋庸置疑的。 技术债务的本质是产品的结构阻碍了进步,表现出来的症状有:无法轻易重构产品以满足市场需求;组件之间的依赖性过多,体系结构不良;缺陷太多,结构不良;难以理解,难以改变。 技术债务的后果有偿还技术债务造成时间浪费,员工满意度降低带来士气低落,因解决遗留代码问题而错过优质项目造成人才流失,产品质量降低造成客户满意度下降,技术债务限制创新能力、扼杀创造性等诸多问题。 技术债不单单是技术债,它就像一个垃圾堆,久而久之不处理,慢慢周围就会产生更多的垃圾,因此产生的 “破窗效应” 更加是会对未来的项目环境造成很大的影响,大家也会逐渐丧失维护环境的信心。所以在讨论技术债的时候不仅仅是讨论技术债本身,技术债对团队追求质量的信心、对大家维护环境整洁的积极性都会造成很大的影响。 MartinFowler 把技术债分为四个象限,如下图所示: 三、技术债产生的原因 ●业务压力:为了满足业务的快速要求,在必要的修改并没有完成时就匆匆发布,这些未完成的修改就形成了技术负债。 ●缺少过程和理解:业务人员不清楚不理解技术负债的概念,在决策时就不会考虑到其带来的影响。 ●模块之间解耦不够:功能没有模块化,软件柔性不够,不足适应业务变化的要求。 ●缺少配套的自动化测试:导致鼓励快速而风险很大的 “创可贴” 式的 BUG 修复。 ●缺少必要文档:需求和代码都没有必要的支撑性文档或注释。 ●缺少协作:组织中的知识共享和业务效率较低,或者初级开发者缺少必要的指导。 ●重构延迟:在开发的过程中,某些部分的代码会变得难以控制,这时候就需要进行重构,以适应将来的需求变化。重构越是推迟,这些已有的代码被使用的越多,形成的技术负债就越多,直到重构完成。 ●不遵循标准或最佳实践:忽略了已有的业界标准、框架、技术和最佳实践。 ●缺少相关技能:开发人员有时候技能缺失,并不知道如何编写优雅的代码。 四、如何 “还债”? 技术债可视化 尽可能公开技术债,一开始就与团队,利益相关方一起权衡利弊,并明确告知影响与解决方案。平等沟通,相互理解。让技术债在业务层面、技术层面可见。 可以在组织资产负债表的财产债中新增两列:短期技术债和长期技术债。还可以用用跟踪开发速率的方式体现技术债对于产品的影响。 不同的债要对症下药 技术债的状态可以分类为偶然技术债、已知技术债和目标技术债。 偿还技术债时应遵循如下原则: 1)确定已知技术债必须还。 2)发现偶然技术债,立即还。 3)每个冲刺确定一定数量的已知技术债作为目标技术债,在当前冲刺中偿还。 4)无需偿还的技术债是行将就木的产品、一次性原型和短命产品。 五、如何避免 “欠债” 与其后期吭哧吭哧还债填坑,不如从一开始就尽量避免欠下技术债务。 避免使用过时的技术 遗留应用程序、过时的技术以及不同的平台和流程可能会使组织陷入沉重的技术债务,迫使其推迟基本的现代化计划。DNS 和流量管理技术提供商 NS1 的联合创始人兼首席执行官 Kris Beevers 说:“技术债务将大量金钱和宝贵的时间浪费在系统和应用程序上,而这些系统和应用程序并不是为现代企业所需的规模和速度而打造的。” 旧资产和老方法也往往充斥着安全漏洞,难以集成和自动化,并且很可能不再更新。 Beevers 指出:“寻找人才来管理基于复杂或过时的代码构建的遗留应用程序也是一个日益严峻的难题。坚持采用过时技术不仅会消耗宝贵的预算,而且还会阻碍公司创新和保持竞争力的能力。” 参考敏捷实践 有越来越多的组织渐渐接受敏捷软件开发,这是将方法交给协作、自行组织的团队和跨职能团队的一系列方法和实践。如果这种方法得到严格应用,敏捷开发使组织可以避免技术债务,其方法是快速且以迭代的方式创建和发布新产品。Dodd 说:“这一过程将新产品和新功能尽快并逐步地交到用户手中。” 随着新版本的交付,各种改进和问题都得到了解决,这使技术债务的积累不太可能产生。 敏捷方法认识到项目在生命周期中从未真正完成过,并且也从来都不是完美的。“同时,敏捷方法专注于…… 针对能力和质量的简化了的开发”,Dodd 说。重要功能往往要频繁地开发,测试并投入生产。敏捷团队可能不会发布软件的 “全面(Big Bang)” 方法,而是每年发布几次重大升级。Dodd 指出:“这可以使产品保持相当平稳的发展,还可以帮助用户避免重大的中断事件。” ...

2023年10月29日 · 1 分钟

关于设计模式

【策略模式】(Strategy Pattern) 其中的Context是一个所谓的“上下文”,不一定非得是个类,也可以只是一个函数/方法。最关键的是,我们其实根本不需要ConcreteStrategyX类,也不需要它们的对象。我们要的只是一个execute函数而已,我们甚至连execute这个函数名都不需要,只要能执行它就行。 看看函数式编程是怎么玩的(这里以大家都熟悉的JavaScript为例): function context(func) { // 做些什么... var result = func() // 有需要的话可以传参 // 再做些什么... } context(function() { // 做些什么... return 123 // 是否需要返回值看需求 }) 一个匿名函数参数func搞定。 Java能搞出这种类图来,全都是因为Java没有一等公民的函数,所以函数必须依附于类(静态方法)或者对象(非静态方法)。而玩静态方法又没法玩多态,而且类不能当成参数传递给其他函数/方法,所以只能用对象携带方法。而对象的方法必须有个名称,为了统一,就叫execute。由于需要多态,所以我们必须提一个接口出来,在接口里声明execute的方法签名。所有这一切说白了都是为了讨好Java编译器,否则它会给你颜色(red)看。 当然,自从Java有了函数式接口和lambda后一定程度上也能玩函数式编程了。 【观察者模式】(Observer Pattern) 这个在JS里大家已经熟悉到不能再熟悉了: someButton.onclick = function(event) { // 处理点击事件 } 又是一个匿名函数搞定!上图里的Subject#attach在这里就是直接赋值。Subject#detach就是赋空值。Subject#notify就是调用一下匿名函数而已。而Observer#update就是匿名函数本身。 【访问者模式】(Visitor Pattern) 能整成这样我也是服了。说白了不就是访问者需要判断一下元素类型嘛。直接套用策略模式,在匿名函数里if-else一下不就行了?(当然还有其他方式,比如引入一个工厂。有模式匹配的函数式编程语言如Haskell、Erlang、Elixir等玩起来更简单)。 【装饰器模式】(Decorator Pattern) 这才是函数式编程的魅力所在! function core1(arg1, arg2) { // 做些啥 return 123 } function core2(arg) { // 做些啥 return 456 } function decorate(core) { // 做些准备工作 return function() { // 做些啥,甚至可以改变参数 var ret = core(...arguments) // 做些啥,甚至可以改变返回值 return ret } } var decorated1 = decorate(core1) var decorated2 = decorate(core2) 酷吧?又是匿名函数搞定!只不过这次的匿名函数是返回值。 ...

2023年10月1日 · 2 分钟

阿里编程规约

命名风格 【强制】抽象类命名使用 Abstract 或 Base 开头; 异常类命名使用 Exception 结尾; 测试类 命名以它要测试的类的名称开始,以 Test 结尾。 【强制】POJO 类中布尔类型变量都不要加 is 前缀,否则部分框架解析会引起序列化错误。 【强制】包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。包名统一使 用单数形式,但是类名如果有复数含义,类名可以使用复数形式。 正例: 应用工具类包名为 com.alibaba.ai.util、类名为 MessageUtils 【推荐】在常量与变量的命名时,表示类型的名词放在词尾,以提升辨识度。 正例: startTime / workQueue / nameList / TERMINATED_THREAD_COUNT 17.【参考】枚举类名带上 Enum 后缀,枚举成员名称需要全大写,单词间用下划线隔开。 B) 领域模型命名规约 数据对象: xxxDO,xxx 即为数据表名。 数据传输对象: xxxDTO,xxx 为业务领域相关的名称。 展示对象: xxxVO,xxx 一般为网页名称。 POJO 是 DO/DTO/BO/VO 的统称,禁止命名成 xxxPOJO。 常量定义 【推荐】不要使用一个常量类维护所有常量,要按常量功能进行归类,分开维护。 【推荐】如果变量值仅在一个固定范围内变化用 enum 类型来定义。 SPRING(1), SUMMER(2), AUTUMN(3), WINTER(4); 代码格式 【强制】采用 4 个空格缩进,禁止使用 tab 字符。 IDEA 设置 tab 为 4 个空格时,请勿勾选 Use tab character ...

2023年8月20日 · 8 分钟

OneData数据仓库架构

**1.**什么是 onedata 面对爆炸式增长的数据,如何建设高效的数据模型和体系,对这些数据进行有序和有结构地分类组织和存储,避免重复建设和数据不一致性,保证数据的规范性,一直是大数据系统建设不断追求的方向。OneData 即是阿里巴巴内部进行数据整合及管理的方法体系和工具。阿里巴巴的大数据工程师在这一体系下,构建统一、规范、可共享的全域数据体系,避免数据的冗余和重复建设,规避数据烟囱和不一致性,充分发挥阿里巴巴在大数据海量、多样性方面的独特优势。借助这一统一化数据整合及管理的方法体系,我们构建了阿里巴巴的数据公共层,并可以帮助相似的大数据项目快速落地实现。 **2.**指导思想 阿里巴巴集团数据公共层设计理念遵循维度建模思想,可参考 StarSchema-The Complete Reference 和 The Data Warehouse Toolkit-The Definitive Guide to Dimensional Modeling。数据模型的维度设计主要以维度建模理论为基础,基于维度数据模型总线架构,构建一致性的维度和事实。其核心的实施指导方针如下: 首先,要进行充分的业务调研和需求分析。 其次,进行数据总体架构设计,主要是根据数据域对数据进行划分;按照维度建模理论,构建总线矩阵,抽象出业务过程和维度。 再次,对报表需求进行抽象整理出相关指标体系,使用 One Data 工具完成指标规范定义和模型设计。 最后,是代码研发和运维。其实施流程主要分为:数据调研、架构设计、规范定义和模型设计。 **3.**业务调研 业务调研:需要确认要规划进数仓的业务领域,以及各业务领域包含的功能模块,以阿里的业务为例,可规划如下矩阵 需求调研:了解需求方关系哪些指标?需要哪些维度、度量?数据是否沉淀到汇总层等。 可以想象一下,在没有考虑分析师、业务运营人员的数据需求的情况下,根据业务调研建设的数据仓库无疑等于闭门造车。了解了业务系统的业务后并不代表就可以进行实施了,此刻要做的就是收集数据使用者的需求,可以去找分析师、业务运营人员了解他们有什么数据诉求,此时更多的就是报表需求。 需求调研的途径有两种:一是根据与分析师、业务运营人员的沟通(邮件、IM)获知需求;二是对报表系统中现有的报表进行研究分析。通过需求调研分析后,就清楚数据要做成什么样的。很多时候,都是由具体的数据需求驱动数据仓库团队去了解业务系统的业务数据,这两者并没有严格的先后顺序。 举例:分析师需要了解大淘宝(淘宝、天猫、天猫国际)一级类目的成交金额。当获知这个需求后,我们要分析根据什么(维度)汇总,以及汇总什么(度量),这里类目是维度,金额是度量;明细数据和汇总数据应该怎样设计?这是一个公用的报表吗?是需要沉淀到汇总表里面,还是在报表工具中进行汇总? **4.**架构设计 4.1 数据域的划分 数据域是指面向业务分析,将业务过程或者维度进行抽象的集合,一般数据域和应用系统(功能模块)有联系,可以考虑将同一个功能模块系统的业务过程划分到一个数据域。业务过程可以概括为一个个不可拆分的行为事件,如下单、支付、退款。为保障整个体系的生命力,数据域需要抽象提炼,并且长期维护和更新,但不轻易变动。在划分数据域时,既能涵盖当前所有的业务需求,又能在新业务进入时无影响地被包含进已有的数据域中或者扩展新的数据域。如表所示是功能模块/业务线的业务动作(部分示例): 根据业务过程进行归纳,可以抽象出如下数据域: 4.2 构建总线矩阵 在进行充分的业务调研和需求调研后,就要构建总线矩阵了,需要做两件事情: 1.明确每个数据域下有哪些业务过程。 2.业务过程与哪些维度相关,并通过总线矩阵定义每个数据域下的业务过程和维度。 如下表是供应链管理业务过程示例: 4.3 规范定义 规范定义主要定义指标体系,包括原子指标、修饰词、时间周期和派生指标。 4.4 模型设计 模型设计主要包括维度及属性的规范定义,维表、明细事实表和汇总事实表的模型设计。 4.5 架构总结 One Data 的实施过程是一个高度迭代和动态的过程,一般采用螺旋式实施方法。在总体架构设计完成之后,开始根据数据域进行迭代式模型设计和评审。在架构设计、规范定义和模型设计等模型实施过程中,都会引入评审机制,以确保模型实施过程的正确性。 **5.**指标体系搭建 5.1 指标体系核心结构 ...

2023年3月5日 · 2 分钟

Hive调优大全

调优具体细节 Hive建表设计层面 Hive 的建表设计层面调优,主要讲的怎么样合理的组织数据,方便后续的高效计算。比如建表的类型,文件存储格式,是否压缩等等。 利用分区表优化 关于 Hive 的表的类型有哪些? 1、分区表 2、分桶表 分区表 是在某一个或者几个维度上对数据进行分类存储,一个分区对应一个目录。如果筛选条件里有分区字段,那么 Hive 只需要遍历对应分区目录下的文件即可,不需要遍历全局数据,使得处理的数据量大大减少,从而提高查询效率。 也就是说:当一个 Hive 表的查询大多数情况下,会根据某一个字段进行筛选时,那么非常适合创建为分区表,该字段即为分区字段。 select1: select .... where country = "china" select2: select .... where country = "china" select3: select .... where country = "china" select4: select .... where country = "china" ..... 分门别类:这个city字段的每个值,就单独形成为一个分区。其实每个分区就对应带HDFS的一个目录 在创建表时通过启用 partitioned by 实现,用来 partition 的维度并不是实际数据的某一列,具体分区的标志是由插入内容时给定的。当要查询某一分区的内容时可以采用 where 语句,形似 where tablename.partition_column = a 来实现。 1、创建含分区的表: CREATE TABLE page_view(viewTime INT, userid BIGINT, page_url STRING, referrer_url STRING, ip STRING COMMENT 'IP Address of the User') PARTITIONED BY(date STRING, country STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY '1' STORED AS TEXTFILE; 2、载入内容,并指定分区标志: ...

2022年9月18日 · 14 分钟

Hive 数仓建表该选用 ORC 还是 Parquet,压缩选 LZO 还是 Snappy

在数仓中,建议大家除了接口表(从其他数据库导入或者是最后要导出到其他数据库的表),其余表的存储格式与压缩格式保持一致。 在数仓中,建议大家除了接口表(从其他数据库导入或者是最后要导出到其他数据库的表),其余表的存储格式与压缩格式保持一致。 我们先来说一下目前 Hive 表主流的存储格式与压缩方式 从 Hive 官网得知,Apache Hive 支持 Apache Hadoop 中使用的几种熟悉的文件格式,如 TextFile(文本格式),RCFile(行列式文件),SequenceFile(二进制序列化文件),AVRO,ORC(优化的行列式文件)和Parquet 格式,而这其中我们目前使用最多的是TextFile,SequenceFile,ORC和Parquet。 下面来详细了解下这 2 种行列式存储。 1、ORC 1.1 ORC 的存储结构 我们先从官网上拿到 ORC 的存储模型图 看起来略微有点复杂,那我们稍微简化一下,我画了一个简单的图来说明一下 但是由于索引的高成本,在**「目前的 Hive3.X 中,已经废除了索引」**,当然也早就引入了列式存储。 列式存储的存储方式,是按照一列一列存储的,如上图中的右图,这样的话如果查询一个字段的数据,就等于是索引查询,效率高。但是如果需要查全表,它因为需要分别取所有的列最后汇总,反而更占用资源。于是 ORC 行列式存储出现了。 在需要全表扫描时,可以按照行组读取 如果需要取列数据,在行组的基础上,读取指定的列,而不需要所有行组内所有行的数据和一行内所有字段的数据。 了解了 ORC 存储的基本逻辑后,我们再来看看它的存储模型图。 同时我也把详细的文字也附在下面,大家可以对照着看看: 条带 (stripe):ORC 文件存储数据的地方,每个 stripe 一般为 HDFS 的块大小。(包含以下 3 部分) index data:保存了所在条带的一些统计信息,以及数据在 stripe中的位置索引信息。 rows data:数据存储的地方,由多个行组构成,每10000行构成一个行组,数据以流( stream)的形式进行存储。 stripe footer:保存数据所在的文件目录 文件脚注 (file footer):包含了文件中 sipe 的列表, 每个 stripe 的行数, 以及每个列的数据类型。它还包含每个列的最小值、最大值、行计数、求和等聚合信息。 postscript:含有压缩参数和压缩大小相关的信息 所以其实发现,ORC 提供了 3 级索引,文件级、条带级、行组级,所以在查询的时候,利用这些索引可以规避大部分不满足查询条件的文件和数据块。 ...

2022年7月24日 · 3 分钟

CDH角色划分

1. 服务器配置 主节点: hostname: m1,m2,m3 vcore:48 内存:128G SSD:1T(不算系统盘) 工作节点: hostname: n1,n2,n3,n4 vcore : 48 内存:256G SSD:1T(不算系统盘) 2. 节点职责描述 m1: 控制核心;cdh核心,hadoop主节点 m2: 网关入口;主节点高可用,一些组件的web ui,用户入口 ,(前期做计算任务的driver端,后期优化driver打散到各节点) m3: 后台服务;组件元数据库,任务的history服务 ,(后期做元数据HA) n1~n4: 算存一体;提供存储,计算等服务 3.角色分配策略 一、hdfs NameNode一般在主节点上,初始化安装的时候没有高可用,所以有SecondaryNameNode的作为一个备份,NameNode它会将它拆分后进行分布式存储,其中的数据是分散在各个DataNode节点,且默认都会有3个副本,防止其中一台机器宕机使得数据缺失。balancer一般与namenode搭建在一起。 二、hive hive metastore server与hiveServer2一般搭载一起上,但也可以分开,因为hive服务需要启动hiveServer2,访问sparksql需要启动metastore而hive gateway,事实上并不是真正的角色,也没有状态,但它们充当了告诉客户端配置应该放置在哪里。 添加Hive服务时,默认情况下会创建Hive网关。 三、cloudera manager server 这个可以根据实际搭建,这个相当于是集群的监听器,在网页上出现的的图表也就是这个监听器类似的,这个可以搭建在主节点上,但若是主节点上分配的角色过多会影响其服务器的性能。 四、spark 这个角色可以分配这任意的机器上,按实际情况调整。spark-gateway全部部署在各个机器上,这个对于个人理解来说相当于spark、spark2机器之间的通信功能。 五、yarn jobhistory与resourcemanager进行通信,所以部署上一般在同一台机器上放在主节点上,而nodemanager分配在各个节点上 六、zookeeper 这个若是机器足够一般是奇数的,所以部署在m节点上比较合适。奇数台、高可用、与管理角色共置 七、hue 会对外提供一个web ui,以便于数据分析和数据开发做即席查询。这个服务随意部署,根据自己的机器部署情况来看。 4.角色划分详情表 控制核心 网关+入口 元数据+历史服务 存算一体 m1 m2 m3 n1 n2 n3 n4 cloudera management Alert Publisher ✅ Event Server ✅ Host Monitor ✅ Service Monitor ✅ hdfs NameNode ✅ ✅ JournalNode ✅ ✅ ✅ Failover Controller ✅ ✅ HttpFs ✅ DataNode ✅ ✅ ✅ ✅ yarn ResourceManager ✅ ✅ NodeManager ✅ ✅ ✅ ✅ JobHistory Server ✅ hive Hive MetaStore Server ✅ HiveServer2 ✅ HiveGateway ✅ ✅ ✅ ✅ ✅ ✅ ✅ spark Spark History Server ✅ Spark Gateway ✅ ✅ ✅ ✅ ✅ ✅ ✅ impala Impala StateStore ✅ Impala catalog Server ✅ Impala Daemon ✅ ✅ ✅ ✅ zookeeper zk-node ✅ ✅ ✅ hue Hue Server ✅ Hue Load Balancer ✅ 5. 未来升级项 work节点扩展硬盘,只需将新盘挂载到新目录/hadoop/data2或/hadoop/data3,更新hdfs配置就能完成存储扩展(支持热加入) ...

2022年5月15日 · 1 分钟