码农戏码

新生代农民工的自我修养

0%

几乎在每个团队,都至少有一份代码规范,或者代码的check list。然也就仅仅是一份清单。

每次团队复盘时,都会有一条,我们要写好代码,然“好代码”是什么样子,什么标准,全取决于各人的水平。

每个程序员也都知道code review的重要性,然排期很紧张,难得做一次。宁可花时间追查问题,也不做防御性准备。

这些现象,是不是特别平常,虽然很想改变,但又是无力感呢。

程序员对代码的追求态度决定了职业生涯的高度,代码的质量决定了生活质量。

为什么会有上面提到的现象,大概有这两方面的原因:

1、每个人对“好代码”的观念不一样

2、对于“坏味道”缺乏明确的表象判断,也就很难提出明确的改进措施

Read more »

先看一段简单的代码:

1
2
3
4
5
6
7
8
package com.zhuxingsheng.adapter

@PostMapping("/login")
public LoginResponse login(LoginRequest loginRequest) {

return loginService.login(loginReqeust);

}

从代码中,可以明显看出这是一段处理登陆请求的方法。在大多数项目中,这种代码很常见。

它有什么坏味道呢?

分层穿透了,LoginRequest类本应该属于入口层,结果穿透到了service层。

细细追究,需要明确的问题:

1、LoginRequest到底属于哪一层,是resource层,还是service层?

2、没有达到DDD防腐层的意义,resource是隔离外部与核心业务的,但却变成了透传。

Read more »

“学而优则仕”的传统文化渗透在各行各业。

那么”码而优则仕”则是这种文化的延伸,自然而然的结果。

当然很多程序员对做管理不感兴趣,想很纯粹的研究技术,成为一名技术专家。人各有志,但客观讲,技术专家与技术管理相比较,成为技术专家比技术管理难度大得多,只有做到在一个区域,一个行业屈指可数的顶尖专家,才有更加广阔的前景。尤其在国内的环境大多数都是业务型公司,技术本身没有直接价值,没有太高的壁垒,有太多能取代你位置的人。

当然,技术管理也有难度,尤其对于程序员群体。但只要做到一个团队内的最佳,则拿到了敲门砖,随时准备幸运之神的降临。跨越技术纯粹性的舒适性,技术管理之路就开启了。

Read more »

使用缓存来加速应用程序的访问速度,是几乎所有高性能系统都会采用的方法。

但缓存真的那么好吗?架构师在构建高性能系统时,是不是必须增加缓存组件?缓存是不是多多益善?

《一代宗师》里本山大叔说过这样的一段话:

“一门里,有人当面子,就得有人当里子。面子不能沾一点儿灰尘。流了血,里子得收着,收不住,漏到了面子上,就是毁派灭门的大事。”

如果缓存是里面的角色,那么绝对是面子。

虽然缓存带来了性能的提升,但给系统带来的多少复杂性。缓存穿透,缓存击穿,缓存雪崩,缓存污染这些问题不绝于耳。这些问题不是操作系统兜着,就是程序员。所以缓存是24K纯金的面子。人人都好面子,还得有个能轻松应对的里子。

Read more »

微服务架构已经很流行了,并且有大量文章描述相对单体架构,微服务架构带来的众多优点。

怎么从单体架构更优雅地转化为微服务架构呢?

有一种被实践证明有效的方法论:The Twelve-Factor App

1、Codebase

一份基准代码,多份部署

尽管每个应用只对应一份基准代码,但可以同时存在多份部署。每份 部署 相当于运行了一个应用的实例。通常会有一个生产环境,一个或多个预发布环境。此外,每个开发人员都会在自己本地环境运行一个应用实例,这些都相当于一份部署

2、Dependencies

显式声明依赖关系

12-Factor规则下的应用程序不会隐式依赖系统级的类库。 它一定通过依赖清单 ,确切地声明所有依赖项

3、配置

在环境变量中存储配置

通常,应用的配置在不同部署 (预发布、生产环境、开发环境等等)间会有很大差异。这其中包括:

  • 数据库,Memcached,以及其他 后端服务 的配置
  • 第三方服务的证书,如 Amazon S3、Twitter 等
  • 每份部署特有的配置,如域名等

有些应用在代码中使用常量保存配置,这与12-Factor所要求的代码和配置严格分离显然大相径庭。配置文件在各部署间存在大幅差异,代码却完全一致。

4、后端服务

把后端服务(backing services)当作附加资源

后端服务是指程序运行所需要的通过网络调用的各种服务,如数据库(MySQL,CouchDB),消息/队列系统(RabbitMQ,Beanstalkd),SMTP 邮件发送服务(Postfix),以及缓存系统(Memcached)。

每个不同的后端服务是一份 资源 。例如,一个 MySQL 数据库是一个资源,两个 MySQL 数据库(用来数据分区)就被当作是 2 个不同的资源。12-Factor 应用将这些数据库都视作 附加资源 ,这些资源和它们附属的部署保持松耦合。

5、构建,发布,运行

基准代码 转化为一份部署(非开发环境)需要以下三个阶段:

  • 构建阶段 是指将代码仓库转化为可执行包的过程。构建时会使用指定版本的代码,获取和打包 依赖项,编译成二进制文件和资源文件。
  • 发布阶段 会将构建的结果和当前部署所需 配置 相结合,并能够立刻在运行环境中投入使用。
  • 运行阶段 (或者说“运行时”)是指针对选定的发布版本,在执行环境中启动一系列应用程序 进程。

12-factor 应用严格区分构建,发布,运行这三个步骤。 举例来说,直接修改处于运行状态的代码是非常不可取的做法,因为这些修改很难再同步回构建步骤。

6、进程

以一个或多个无状态进程运行应用

运行环境中,应用程序通常是以一个和多个进程运行的。

12-Factor 应用的进程必须无状态且无共享。 任何需要持久化的数据都要存储在后端服务内,比如数据库。

7、端口绑定

通过端口绑定(Port binding)来提供服务

互联网应用有时会运行于服务器的容器之中。例如 PHP 经常作为 Apache HTTPD 的一个模块来运行,正如 Java 运行于 Tomcat 。

12-Factor 应用完全自我加载 而不依赖于任何网络服务器就可以创建一个面向网络的服务。互联网应用 通过端口绑定来提供服务 ,并监听发送至该端口的请求。

8、并发

通过进程模型进行扩展

任何计算机程序,一旦启动,就会生成一个或多个进程。互联网应用采用多种进程运行方式。例如,PHP 进程作为 Apache 的子进程存在,随请求按需启动。Java进程则采取了相反的方式,在程序启动之初 JVM 就提供了一个超级进程储备了大量的系统资源(CPU和内存),并通过多线程实现内部的并发管理。上述2个例子中,进程是开发人员可以操作的最小单位。

9、易处理

快速启动和优雅终止可最大化健壮性

应用程序的进程应该是一次性的,以便它们可以快速启动、停止和重新部署,而不会丢失数据。这有助于快速弹性扩展、代码和配置更改的快速部署以及生产部署的稳健性。

10、开发环境与线上环境等价

尽可能的保持开发,预发布,线上环境相同

从以往经验来看,开发环境(即开发人员的本地 部署)和线上环境(外部用户访问的真实部署)之间存在着很多差异。这些差异表现在以下三个方面:

  • 时间差异: 开发人员正在编写的代码可能需要几天,几周,甚至几个月才会上线。
  • 人员差异: 开发人员编写代码,运维人员部署代码。
  • 工具差异: 开发人员或许使用 Nginx,SQLite,OS X,而线上环境使用 Apache,MySQL 以及 Linux。

12-Factor 应用想要做到 持续部署 就必须缩小本地与线上差异。 再回头看上面所描述的三个差异:

  • 缩小时间差异:开发人员可以几小时,甚至几分钟就部署代码。
  • 缩小人员差异:开发人员不只要编写代码,更应该密切参与部署过程以及代码在线上的表现。
  • 缩小工具差异:尽量保证开发环境以及线上环境的一致性。

11、日志

把日志当作事件流

将日志流式传输到选定的位置,而不是将它们转储到日志文件中。日志可以定向到任何地方。例如,它们可以被定向到 NoSQL 中的数据库、另一个服务、存储库中的文件、日志索引和分析系统或数据仓库系统。

12、管理进程

后台管理任务当作一次性进程运行

将管理任务与应用程序的其余部分分开,以防止一次性任务导致正在运行的应用程序出现问题。容器使这很容易,因为可以启动容器只是为了运行任务然后将其关闭。

最近看完了一本大佬很早就推荐的书:《演进式架构》

现在看已经算是一本很老的书了,里面的很多概念对架构师来讲已经算是耳熟能详了。

如果你没有一些常识性思考,那还是可以看看的,如果没有时间,我通过这篇读书笔记梳理了书中的核心知识点,结合最近的一些新书观点,方便你快速获取这些知识。

Read more »

《程序员软技能》中,提到过一种思维,要把自己当成一家企业,而就职公司是我们的客户。

既然如此,我想需要考虑的最重要的事情应该是我给客户提供了什么产品,产品是什么价格?

对于程序员来讲,提供的最根本产品自然是代码,我们现在需要考虑的事就是代码的价格,平均到基本单位,就是每一行代码值多少钱?

当下市场,先考虑一下代码语言种类:

使用java语言写的一行代码

使用go语言写的一行代码

使用python语言写一行代码

亦或写一行sql

甚至调试一个AI模型参数

这些代码它们的价格肯定是不一样的。想到的第一个因素估计是写的人不一样。都写相同的语言代码,什么在决定价格?自然是写代码程序员的水平了。如同时期研究生相对本科生自然值钱些。

即使都是出于同一人之手。那么是什么决定了价格?是因为牛逼吗?

PHP是最好的语言?从高维度讲sql man与AI调试师没什么不同,那决定价格的最根本因素是什么?

在市场上,决定价格的最重要因素是需求

现在写一行VB语言会比java语言值钱吗?不是VB语言不好,终究是因为市场需求。当更先进更高阶的技术出现,更能满足市场需求时,价格自然上涨。这也是为什么苦逼程序员必须随着技术更迭不停地学习。甚至要预判技术趋势,提前投入精力学习。才能保障自己写的代码价值不被贬值。

除了市场需求因素,程序员水平,还有什么因素呢?我们还需要考虑哪些问题?

把需求换种说法,就是写的代码是否有用?

从关注程序员自身来讲,可以考虑再深入点:

1、我写的代码对别人有没有用呢?

写个hello world,或者写了个微信,似乎都有用

2、我写的代码对别人有用的话,有多大用处呢?如何做到最有用?

hello world作用可以作教程,对小白编程基础培训,微信可以通讯、支付、摇一摇,似乎用处都不小。因此它们的作用不能从程序员侧考虑,而得从客户侧考虑。

3、我写的代码对别人有用的话,对多少人有用?如何做到对更多人有用?

hello world面对的人群是刚要入门编程人员,而微信是全民应用;要想对更多人有用,全民编程似乎不太可能

4、我写的代码对别人有用的话,在多长时间段对别人有用呢?如何做到让这个时段更长些

除了上面的问题,还需要从客户侧考虑,不能只是埋头写一行行的代码,还得考虑客户的需求,这样又需要考虑一些问题:

1、他们真正的需求是什么?最需要的是什么?

需要程序员?需要35岁以下的程序员?

2、我是那个能满足他们需求的人吗?

在优化人员时,优化名单上会出现你的名字吗?

3、如果我能,我有没有可能成为必需?

4、如果我不能,我怎样才能?

5、有必要一定由我去满足他们的需求吗?

这么多的问题,总结成一句话,行动指南:挑最需要的事情做,自然就成了最被需要的人。


常听些大佬讲,要有商业sense,而一切商业模式的根本,怎么赚钱,赚什么钱,赚多少钱。

在现如今充满物质喧嚣的大环境中,总包、副业刚需、内卷这些词时时充斥我们时,更应该考虑下商业底层逻辑。

我想作为程序员,“我的一行代码值多少钱?”,这个问题是最基本的商业sense。

这些年中台、微服务都是技术浪潮中的弄潮儿。两者的命运似乎是所有技术新词的缩影:先谈,再建,后拆,最后平静。

如中台,开始时聊什么都得带上中台,战略层喜欢谈,执行层也喜欢谈,再后面跟随一线大厂纷纷搭建自己的中台,然后就是反思,拆除中台,最后平静看待中台。

中台可以说已经经历完整的生命周期,而微服务周期也差不多,但对于“拆掉”,两者的声势与目标却不太相同。

《中台是什么》中提出,“效能下限”与“创新上限”就像翘翘板,产生了哑铃效应,而中台则是追求效能的极致,同时却也降低了创新上限

建中台是为了效能,拆中台是为了创新。

以阿里为代表的大厂对拆中台真是高举高打,但看看微服务,可没哪个大厂高喊要拆掉微服务,可见他们俩还是有本质差别的。

更神奇的是,不管是拆微服务还是拆掉微服务,本质需求却是一致的:提升效能

为什么都是提升效能,从两种行为分别阐述一下

为什么拆分微服务

首先一起回顾一下,为什么要拆分微服务?对于这个问题不得不再向前回退,回到单体架构时代

在微服务架构出现之前,单体架构是永恒,天经地义的。以致于“单体架构”一词都没人提出。

项目起初,单体架构无疑是最佳选择,不仅易于开发、易于测试、易于部署,且由于系统中各个功能、模块、方法的调用都是进程通信,性能是最高的。

甚至在项目从小型发展为中型时,也没有那么不堪。虽然是单体架构,但内部结构并非“铁板一块”,在业务量级可承载范围内,也有一定程度的扩展性。

从两个视角观察扩展性

在纵向角度,绝没有一个项目完全是个“大泥球”形态,至少都会以分层架构风格对代码进行纵向层次划分。

在横向角度,单体架构也支持以功能、技术等维度划分,拆分成各个模块,以便代码重用和管理,甚至提取出各种形体组件,如jar

那拆微服务解决了哪些效能问题?

第一程序效能

在于应用程序的某个方面给基础设施带来了过重负担,这反过来又很可能会导致糟糕的用户体验。

如,图像处理需要大量CPU,如果CPU负载变得非常高,这将会导致应用其他处理资源的饿死现象。影响系统延迟,甚至影响系统可用性。

也就是说应用程序中局部缺陷会造成全局问题。局部间没有隔离能力,一旦出现内存泄漏、线程爆炸、阻塞、死循环等问题,将影响整个程序。不仅导致单个功能不可用,甚至整个程序的效能都降至为零。

从程序维护性来说,所有代码都在同一进程,无法做到单独停止、更新、升级某一部分代码。只能制定专门停机更新计划,整体做灰度发布,A/B测试。

第二团队效能

与应用的关系不大,但关系到如何组织团队。在应用程序的特定部分,投入工作的人越多,开发和部署就会越慢,而且越容易出错。

如,抢占持续部署同一服务,出现排队现象,意味着本可以交付产品的工程师只能坐等轮到他们进行部署。出事“紧急事件”时,多个团队代码都需要回滚。

综上所述,简单总结一下,单体架构并不是一无是处,项目起始阶段依然是最佳选择;

当对应用程序性能要求超过单机能力,以及软件的开发人员规模明显超过了“2 Pizza Team”时,
不管是程序效能还是团队效能都已经达到瓶颈,此时可以通过微服务架构来解决这些问题。

微服务怎么解决效能问题?

对于程序效能,在单体架构时代,想要整体系统的可靠性,我们只能努力让每一个模块,每一行代码都可靠,以达到整体系统的最终可靠性。

然而常常事与愿违,战术层面再优秀,也难以弥补战略层面的缺陷。在构建大规模系统时,人们的观念也从“尽量不出错”向正视“出错是必然”转变,在此前提下,历史悠久的单体架构终被挑战。

微服务把独立的单体架构内部依赖组件,由“编译时期”推迟到了“运行时期”,对时间维度的解耦,带来了运行时动态扩展、服务间技术异构、服务独立交付等好处。

也就解决了上面所述的局部间没有隔离能力造成的全局性故障,导致整体程序效能降至为零的情况。也实现了局部维护的能力,提升系统整体可维护性,保障系统整体可靠性与可用性。

对于团队效能,系统不再是一块整体,团队更加独立地工作,独立地部署,从而发布更多产品。

尤其在康威定律的指导下,划分组织边界以及服务职责范围,让组织之间更高效默契的沟通以及相互配合提升整体效益。

为什么拆掉微服务

微服务的确带来了很大的收益,不管在系统扩展性,还是在组织扩展性,都促使商业最大限度的规模化。

然业务不是永远增长的,随着业务增长乏力,收益萎缩,需要探索新商业机会,原先高成长的业务团队规模也慢慢收缩,之前的服务系统也慢慢沦为遗留系统。

从原先增长期的每个系统0.5人,到维护期每个人10个系统,服务与团队与康威定律极度不匹配。

简而言之,在高增长期康威定律带来的所有收益,随着时间的推移,业务收缩,都变成了“遗留”团队的负债。

所以需要拆掉微服务,改变服务边界以匹配团队边界,平稳回归康威定律。当然也不是彻底拆掉所有微服务回归单体架构。重点是重新调整职责范围,拆分成符合团队的服务边界。

此时再回头看微服务概念时,当初纠结的“微”到底是多大的问题,已经完全不重要。微服务只是相对单体架构(Monolithic)的称呼,“微”不代表任何实际的内容。

我们需要更多的关注“合适大小”,服务经过了恰当地设计,以满足其需求:它负责“合适数量”的功能。而且,至于什么是“合适”并不是一个静态的概念,它取决于团队,即团队的技能集、组织的状态、投资回报率(return-on-investment,ROI)的计算、持有成本以及该服务运行的时间点。

简单总结一下,拆掉微服务,相对程序效能,更多的关注点在团队效能,服务边界匹配团队边界。其次,在整合团队,回归康威定律的过程中,业务流量也是在减少的,程序效能问题也再像扩张时期那么显著。

总结

一切技术都得服务于业务,而业务形态决定了技术形态。

没有完美的业务,也必然没有完美的技术,只有两者相匹配时,才能相得益彰。

不管是建,还是拆。都是适时的选择。架构只有顺应环境才能生存,最大化业务价值。

参考

拆掉微服务

之前总结了一篇文章《单服务器高性能》,主要整理了两方面的知识:

一是socket以及IO常识

二是单机高性能模式

你会发现IO知识一般不会单独出现,常会与socket,linux底层相关知识结合出现,所以在学习IO时,总会有很多的背景知识,不然会很吃力。或者不明就理。

这是为什么呢?

与socket关联,应用角度看,是因为发生IO时,数据来源与目的地除了磁盘就是网络了,而网络必谈socket;其次从OS角度看,linux思想就是一切皆是文件,socket也是文件的一种。

与linux关联,上面写了linux一切皆是文件,IO操作对象都是文件;其次IO操作得涉及内核,IO的一切优化都需要得到OS的支持。

所以你会发现,谈到I/O multiplexing、mmap、Zero-copy这些提升IO性能的技术时,都需要OS层面出手,否则很难有大的提升。

其中I/O multiplexing与Reactor经常被搞混,甚至被认为是同一种东西。

我再尝试总结一下I/O Multiplexing的前世今生以及与reactor的关联:

I/O multiplexing

multiplexing概念多用于通信领域,详细可看Multiplexing – Definition – Types of Multiplexing: FDM, WDM, TDM,截取两张图片表示multiplexing技术前后的对比:

在没有multiplexing时,每次通信,一个通道上只能传输一个信号,浪费了带宽

当有了multiplexing技术后,通过设备多路复用器multiplexer(MUX),一个通道可以传输多个信号,带宽最大化利用。在接受端,通过信号分离器demultiplexer(DEMUX),再把多个信号分离开。

通过上面的两张图可以看出,multiplexing技术里面有两个设备比较关键,一是MUX负责多路复用,另一个是DEMUX负责多路分发。

理解了multiplexing,再看看I/O

简要回顾一下:

从最原始的BIO,PPC模式进化到TPC,通过线程池有效控制线程扩张,但线程上下文切换也带来了性能损耗依然不能小觑。关键是IO处理没有丝毫改进。

从图中可以看出,之前block的依然block,之前system call的依然发生,对于成千上万的连接高并发,怎么达到高性能?

怎么办呢?

这一次还是kernal体现了大爱无私的胸怀,在提供了blocking read方法与non-blocking read方法后,又体贴地想出了两种方法

1、不要每次都来问了,一次性打包问吧。把所有的system call整合在一起,一次性打包给system kernal,结合上面的multiplexing技术,I/O multiplexing由此而来。

2、不要总跑来问我了,有情况我通知你吧。对,这就是著名的Hollywood Principle

根据这两个办法,打造出了最终的完美体epoll。当然在这个完美体前还有select、poll两个被丢弃的废品。至于这三者区别,可详看《单服务器高性能》


Reactor pattern

The reactor design pattern is an event handling pattern for handling service requests delivered concurrently by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to associated request handlers.

更详细的介绍可看Reactor An Object Behavioral Pattern for Demultiplexing and Dispatching Handles for Synchronous Events

看一下reactor pattern里面包含的部件:

1.event:
IO event like write, read, timeout and signal.

2.Event Source (ES):
file descriptor (fd) in linux and Socket or Handle in Windows. Program adds the event that it cares on the given event.

3.event_demultiplexer (ED):
select() and epoll() provided by the OS. The program firstly add the event source (fd) and the related events to the ED. When event comes, ED eill notify that the events on one or more EVs are ready where program can process the events in nonblock way. The same ED way like select(), poll() and epoll() are used in Libevent where they are encapsulated by eventop struct.

4.event_handler_interface and event_handler_imp (EH):
EH has a serial of interfaces and each interface refers to a different event.Reactor will invoke certain interface when some certain event fets ready. EH usually binds a valid ES.
In libevent, it is event struct.

5.reactor:
It is the event management. It uses ED internally to add and remove event. When event is ready, invoke the callback function on the event. It is actually event_base struct in libevent.

可以看到在reactor pattern中,有个reactor部件。而还有个部件event_demultiplexer是由多路复用技术支持。

所以在谈到reactor时,是reactor模式,还是reactor部件?也没必要咬文嚼字了,反正他们是一家。

不仅如此,还有一股编程思潮:响应式宣言里面也有reactor

头晕,反正他们都是一家族的。

总结

一堆名词堆一起,看是又不是,是不是剪不断,理还乱。

简单讲:

结合I/O与multiplexing,由此得来I/O multiplexing。

Reactor模式中包含了reactor部件及依赖了多路复用技术。而多路复用技术的底层epoll又吸取了reactor思想。

道生一,一生二。阴阳之道,存乎万物之间。

不管在做系统分析,还是系统设计时,我们大概率都会提到领域模型这个词,奇妙的是虽然大家都在谈论领域模型,但每个人心中都有一份对领域模型的认知。

套用DDD,我们需要统一语言,首先需要对“领域模型”有一个统一认知。达成共识。

你可以暂时挂起大脑进程,想想:“领域模型是什么?怎么描述?”

世事万物都在变化中发展,就如同“手机”,十年前和现在,人们对它的认知也是不一样的。所以我们一起回顾一下最原始的“领域模型”是什么,你是否记起大明湖畔的领域模型。

“领域模型”最早流行于OOA中,简单回顾一下OOA/D

OOA/D

分析:强调的是对问题和需求的调查研究,而不是解决方案。例如,如果需要一个新的在线交易系统,那么,应该如何使用它?它应该具有哪些功能?

设计:强调的是满足需求的概念上的解决方案,而不是实现。例如,对数据库方案和软件对象的描述。设计思想通常排斥底层或“显而易见”的细节。最终设计可以实现,而实现则表达了真实和完整的设计。

++分析和设计可以概括为:做正确的事和正确地做事++

OOA:强调在问题领域内发现和描述对象(或概念)。例如,在航班信息系统里包含飞机、航班和飞行员等概念。

OOD:强调的是定义软件对象以及它们如何协作以实现需求。例如,软件对象Plane可以有tailNumber(飞机唯一标识)和getFightHistory方法(飞行过的航班)

领域模型

领域模型是OOA中最重要的和经典的模型。

定义

领域模型是对领域内的概念类或现实世界中对象的可视化表。也称为概念模型、领域对象模型和分析对象模型。

不是描述软件类、软件架构领域层或有职责软件对象的组图。

Why

为什么需要领域模型?去掉修饰语,为什么需要模型,这在DDD系列文章中已经解释:模型是对业务复杂度的简化和提炼。帮助我们更好地理解业务。

同理领域模型能够使我们理解关键概念和业务知识。

我们在设计和实现时,软件类名称也大多源于领域模型的名称,以使对象具有源于领域的信息和职责。

这样可以降低我们思维与OO建模之间的表示差异

How

如何创建领域模型?

  1. 寻找概念类
  2. 将其绘制为UML类图中的类
  3. 添加关联和属性

寻找概念类

根据领域模型定义,需要先找到概念类。

概念类是思想、事物或对象。可以从其符号、内涵和外延考虑。

符号:表示概念类的词语或图形

内涵:概念类的定义

外延:概念类所适用的一组示例

考虑购买交易事件的概念类。

可以使用符号Sale对其命名。

Sale的内涵陈述为“表示购买交易的事件,并且具有日期和时间”

Sale的外延是所有销售的例子,或者说是世界上所有销售实例的集合

描述类图

领域模型描述的信息可以采用纯文本方式表示。

但是在可视化语言中更容易理解这些术语,特别是它们之间的关系,因为我们的思维更擅长理解形象的元素和线条连接。

在应用UML时,领域模型被描述为一组没有定义操作的类图。

关联

关联是类之间的关系,表示有意义和值得关注的连接。

关联能够满足当前所开发场景的信息需求,并且有助于理解领域。

关联被表示为类之间的连线,并冠以首字母大写的关联名称。

关联末端可以包含多重性表达式,用于指明类的实例之间的数量关系。

关联本质上是双向的,方向箭头只是为了方便阅读,默认是从左往右。

总结

没有所谓唯一正确的领域模型。所有模型都是对我们试图要理解的领域的近似。

领域模型主要是特定群体中用于理解和沟通的工具。

有效的领域模型捕获了当前需求语境下本质抽象和理解 领域所需要的信息,并且可以帮助理解领域的概念、术语和关系。


到此,已经完成追忆大明湖畔的领域模型,也是OO风云初起时代领域模型的含义。

如果你想更多的回忆,可以去看看以往OO方便书籍,本文内容大多来自《UML和模式应用》。

现今,领域模型演义出更多新的含义,如Martin Fowler提出的充血模型,以及DDD中的领域模型。

在与别人交流时,我们得听声听音,是否在同一频道。