0%

软件设计

缘起

总结一些软件设计的技巧,方便阅读别人的源代码,以及方便自己设计软件

名词

闭包

TODO

PoC

PoC(Proof of Concept),即概念验证。通常是企业进行产品选型时或开展外部实施项目前,进行的

sku vs spu

SPU = Standard Product Unit (标准化产品单元):OPPO R17这是商品的SPU

SKU=stock keeping unit(库存量单位) :如流光蓝(三种颜色:流光蓝、霓光紫、霓光渐变色)+8G+128G(两种配置:8G+128G、6G+128G)。即OPPO R17有一个SPU、6种SKU。

设计模式

TODO

利用spring自动注入list的实现策略模式

参考文献

对代码构建的思考

第一阶段:先考虑代码复用(最简单理解以后少些代码)
第二阶段,考虑软件结构的可扩展性
第三阶段,考虑软件结构的可以移植性(跨平台兼容性等)

文档

文档在软件中,基本贯穿整个软件设计的过程。

在设计软件的初期,需要先对需要操作的数据结构进行一定的规划,比如数据库建表如何设计。

在软件设计中,按照前期的规划使用或修正之前的数据结构。

在设计完软件的维护中,需要文档辅助对整个软件的整体架构和数据结构的回顾等。

如何用语言定义uml:plantuml

plantuml官方文档我的PlantUML笔记

用代码生成uml

讲的很好的uml图例

json数据结构文档

json数据的格式,是最通用的数据结构,常用在。

如何将其数据结构进行工程性的描述定义呢?

参考文献

stack overflow:如何对json数据结构进行文档化

安全

sso单点登录设计

问题的伊始

今日登录github的时候要求全部使用pat登录,更深入的理解了sso

git clone时出现的问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Microsoft Windows [版本 10.0.19043.985]
(c) Microsoft Corporation。保留所有权利。

D:\ednow>git clone https://github.com/ednow/blog.git
Cloning into 'blog'...
remote: Support for password authentication was removed on August 13, 2021. Please use a personal access token instead.
remote: Please see https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/ for more information.
fatal: Authentication failed for 'https://github.com/ednow/blog.git/'

D:\ednow>git clone https://github.com/ednow/blog.git \
fatal: destination path '\' already exists and is not an empty directory.

D:\ednow>git clone https://github.com/ednow/blog.git

D:\ednow>git clone https://github.com/ednow/blog.git
Cloning into 'blog'...
remote: Enumerating objects: 4133, done.
remote: Counting objects: 100% (1406/1406), done.
remote: Compressing objects: 100% (919/919), done.
remote: Total 4133 (delta 917), reused 938 (delta 468), pack-reused 2727
Receiving objects: 100% (4133/4133), 4.38 MiB | 3.49 MiB/s, done.
Resolving deltas: 100% (2625/2625), done.

D:\ednow>

参考文献:github官方文档,具体操作的时候并不好操作,建议看下面的stackoverflow的讨论

stackoverflow的讨论

拓展阅读

单点登录的百度百科

saml数据格式

记一次性能优化实践,4c8g如何支撑5w的QPS

参考文献

PaaS 建设反思 (一) —— 一言难尽的胖容器

参考文献

系统要知道自己接收的参数是哪些

一定要做合法性校验、用enum维护,让别人知道有哪些参数,系统要有准入准出设计

超时处理

问题

如何写出维护性高、稳定性高、扩展性高的代码

  • 维护性高:后面维护的人如何能快速看懂
  • 稳定性高:不能出线上问题,不出严重的线上问题
  • 拓展性高:如果有新的需求插进来如何降低改动量、甚至不需要新的的代码

不合理的代码逻辑一览

1.上游不应该把两个参数通过某个分隔符拼接成一个参数,下游又通过这个魔法分隔符将参数分开,拆成两个参数,从中提取需要的参数

2.正确使用切面:如果使用切面handle exception会导致跟踪不到具体抛出exception的位置,就不要这样用

3.一定要有manager管理对应的mapper:(1)可以统一看到某个方法都被谁调用了 (2)可以加redis进行cache对应的查询

4.最少知道原则:不要暴露过多的参数给你的用户

5.一定要有合法性的校验

6.可枚举的变量一定要有一个枚举类来维护,减少代码中的魔法值

7.如果使用mysql数据库存了大量的json字符串又要后端解析,尽量使用nosql数据库直接映射类的属性
参考文献

8.接口返回的参数,如果在领域模型里面定义了,如果为空,不能设置为null,而应该设置为默认值,比如如果这个参数是list应该返回Collections.emptyList(),。但要如果业务方直接使用data里面的数据又出现问题

9.尽可能记录的时候带上commit id
比如postman测试的时候的时候request的name可以这样子命名【是否测试成功】【系统是不是应该返回合理的数据】系统/功能/参数/commitId【Y】【正】秒杀/付款/e564826

10.@Deprecate 需要加上 @deprecate注释表明原因

11.配置中心和数据库的职责?

12.可枚举变量作为外部参数的时候,应该暴露出去数字。如果以字符串形式传参的话可能会出现【全大写、全小写、驼峰、首字母大写】等奇怪的形式。

13.画架构图的时候最好,不要有太多弯来弯去的线、颜色。当你必须要使用的时候证明你所表达的内容缺乏条理性。而且用户也不想看。

14.函数、流程内部不应该变动入参的内容。

15.以下过程需要有try-catch:

  • 涉及到网络的:http请求、rpc请求
  • 涉及到文件的:打开文件

16.什么时候throw exception?
1.当不希望下面的流程继续走下去的时候,可以用这个方式让流程强行终止。但注意一定要对外提供一致的rsp格式。直接throw会是一堆调用栈暴露给对面。可以设计一个切面,统一处理exception(自定义exception基类,切面处理到这种基类exception,整理成统一的返回格式)。

17.避免在for循环内打印无效日志

18.cache使用copy on write的设计,不要用定时任务去更新。比如在内存中cache数据库中某张表的内容,这个时候应该设计成有请求过来先查内存,内存中查不到再查数据库。如果设计成定时加载的话,如果有实时性要求很高的场景就会影响用户的体验。

19.对于接口接收、发送一定要有标准的数据格式。长度限制、类型限制、枚举限制。如果长度过长的必须有截断处理,并且监控不合法的接口请求,及时发现下游发服务的异常。

这里的上下游定义

20.对于中台系统的设计一定要减少重复开发,技术人员对接的成本。比如已经验证过的业务模式,如果有新的业务方接入,应该有统一的接入流程(比如通过审批系统),由业务方的技术、运营自己形成闭环。

bad practice:由对方产运人员与己方技术人员沟通后,写死到配置中心、MySql中。

best practice:通过中台的审批系统提交配置信息,审批通过后自动写入到配置中心、Mysql中,解放己方技术人员的时间成本。使得经验、业务逻辑有自动化可重复属性。

21.标准化的流程不仅仅只是负责人的技术方向,还应该有产品规划,未来系统演进的落地支撑。不然换一个负责人,标准流程也许就跟着负责人的情绪走,何谈标准。

bad practice:这里,这里要建标准。这些标准的系统化(与整个系统的演进的步调统一,理解应用的成本比较小),对产运研的帮助有限,可重复性(延续性,随着时间的演进能继续被接受和运用)也没有保障。

22.为什么代码会有很多遗留代码,由于要考虑系统升级,新旧切换的时候要能兼容,后面又没有删除代码

23.短信之类的触达需要保证触达一次并且一定只触达一次:TODO

24.如何讲清楚生产问题,影响范围,从什么时候开始影响

25.下游如何兼容上游的变动,不然会出问题:TODO

26.讲话的艺术:需要将别人讲的问题进行一些解答,如果自己的想法有考虑到的话可以往自己的方案上引导,提高自己的方案的说服力。

27.一个枚举类里面应不应该有一些业务逻辑,让这个domin类很重?:TODO

28.需要考虑自己的方法将来被使用的影响,单独写一个独立的mapper隔离了表结构的改变,但是新增字段需要借助这个方法落库,其实每次又要到这个方法里面手动加入字段

29.需要保证测试环境的稳定,数据什么的都是可用的

30.要考虑到以后对接(测试,产品),以及不懂技术的人如何能够看懂。要返回可读的错误信息,以及错误信息要不要落流水表,使得可以查

31.涉及到回调的、请求外部资源的,要考虑最终一致性以及幂等

32.考虑存储、性能,降本增效

33.需要考虑到数据库的长度处理的异常。

34.当master也有问题的时候,有可能是依赖出问题了。mapper找不到是starter有问题

35.redis pipeline 自己计算slot应该只以uid的sharding为依据

36.org.apache.rocketmq.client.exception.MQClientException: The producer service state not OK, SHUTDOWN_ALREADYredis.clients.jedis.exceptions.JedisNoReachableClusterNodeException: No reachable node in cluster。原因在于一个component注入到容器时,一个配置文件没有值导致其他中间价实例化失败。

37.性能优化第一步,日志级别改为info/error,删掉无用的日志打印。识别中间依赖服务的性能影响

38.规则如何去写?:

39.使用Mcache的时候,注意必须得外部调用这个类的方法,动态代理才会生效。

40.需要知道每个功能点哪个业务方在用,可能需要些埋点

41.服务治理,优雅停机:参考文献

42.数据库查不到主从延迟

43.消费者缩容,rebalance的时候,ack还没有给到mq,会导致消息被重复消费,需要消费者端做好幂等。

44.大表归档取归档数据要limit,否则会捞出来很多,导致内存爆掉/超时

45.大表批量删除会导致超时

46.一段逻辑如果变量的命名是一个字母,而且处处都用到的话可以抽离出一个函数,给这一段逻辑赋予更多的含义,后续会好维护一点

47.可能为了性能、编程方便,一个领域模型,会被包装成map<唯一键,领域对象>。但这样子会导致看的人晕晕乎乎的,不是一个很好的编程习惯

48.Too many Cluster redirections:

49.参数有奇怪的空格,导致排查半天

50.Arthas线上watch

51.谨慎使用单个接口,尽量使用批量的接口。不要重复请求,如果同一进程已经请求相关的数据,不要再重复请求

52.Bootstrap broker xxxxx:xxxx disconnected:url错误,换成正确的url

53.nested exception is com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 8000, active 10, maxActive 10, creating 0:连接池满了?最后重启解决了

54.这几个lombok注解需要同时使用,不然可能会造成反序列化失败

代码详情
1
2
3
4
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor

54.异步落库,导致前一个步骤没有还没有初始化,mq异步更新的时候找不到数据导致消息堆积。需要注意落库的速度。

55.自己的服务查询数据库超时,有可能是受别的服务查询导致的集群压力大。可能请求数很少但是请求的数据很多(行数)。

56.数据库慢 -> 整个请求慢 -> 网关超时 -> 导致页面加载报错 -> 加载不出来

57.请求超时有可能是mq性能不行

58.范型的使用:一定要内部流程闭环,别人看代码基本上不会经常去了解T是什么。且要用面对对象的思想,不要用范型硬写面对过程的代码。

59.尽可能考虑npe的场景,并优雅处理,这直接体现了一个工程师

60.不同的数据库的manager类用来处理,可以统一管理一些constant

60.更改接口的版本,rpc框架如何分流

61.rpc增加了一个字段,api连续返回rpc的返回的话会报错

62.
在SQL中,NULL表示一个未知的或不存在的值。任何直接与NULL的比较操作都会产生一个未知的结果,即不是TRUE也不是FALSE,而是NULL。由于NULL既不等于任何值,也不不等于任何值,所以在进行字符串匹配的时候,如果字段的值为NULL,这个字段的值既不会与某个字符串匹配,也不会不匹配。

举例来说,考虑下面这个表达式:

column_name NOT LIKE ‘aa%’
这个表达式的意思是,只选择那些column_name的值不是以aa开头的记录。如果column_name的值为NULL,其实我们并不知道这个未知的值是否以aa开头。因此,这个记录不会被包含在结果集中,因为不满足NOT LIKE ‘aa%’这个条件,也就是说,该条件的结果不是TRUE。

如果希望针对NULL值进行选择,必须使用IS NULL或者IS NOT NULL操作符。这样的话,如果你想要包括NULL值在内的话,查询条件应该是:

(column_name NOT LIKE ‘aa%’) OR (column_name IS NULL)
这会选择所有不是以aa开头的值,以及所有NULL值的记录。

63.如果被cache影响了,需要保证cache最小化原则,对象隔离

64.性能优化日志也是关键一环

生存总结

只有当你能活下去的时候,才能讲设计

1.能力和岗位、职级、薪资没有太大关系。

中台架构设计的重点

接入别的服务的时候,覆盖别的服务的异常、数据报表,并在之上对外提供更优化的流程、一站式、统一的服务。

一定要注意如果有频繁变更的场景的话,一些增删改查一定要直观的有后台进行配置,尽量做到系统能够更少的由开发介入去解决问题,开发应该花更多的时间在系统建设上

关于业务类型,一个组织中会有很多业务,这个时候很多中台的服务都需要对业务做校验,算账。这时候业务关系、业务码的管理应该有一个统一的服务去管理这些关系,并且需要考虑组织架构变更等,之后自动匹配刷数据等逻辑。

性能优化

async-profiler

./profiler.sh start 758连上去的时候提示配置没有开启

详细报错
1
2
3
4

[WARN] Kernel symbols are unavailable due to restrictions. Try
sysctl kernel.perf_event_paranoid=1
sysctl kernel.kptr_restrict=0

执行sysctl kernel.perf_event_paranoid=1的时候提示sysctl: setting key "kernel.perf_event_paranoid": Read-only file system

这时候执行mount /proc/sys -o rw,remount即可。参考文献

遗留问题

  • Arthas。线上debug的使用。
  • 镜像打包脚本?

SAU VS OTA

“SAU”和”OTA”是两种不同的软件更新方法,它们主要用于智能手机、平板电脑、智能手表和其他便携式设备。下面是这两种更新方法的解释和比较:

OTA(Over-the-Air)升级

  • “Over-the-Air”的意思是通过无线网络来进行更新,不需要用到USB线或其他的物理连接方式。
  • 用户通常可以直接在设备上接收到软件更新的通知,然后选择“下载并安装”,过程通常是自动化的。
  • OTA更新方便且流程简单,用户不需要太多的技术背景就可以完成更新。
  • 这种更新方式通常由设备制造商或移动运营商推送。
  • 可以针对特定的用户群体分阶段推送,从而确保更新的稳定性,比如先给少部分用户,观察是否有问题,无问题后再大规模推送。

SAU(Software Update Assistant)升级

  • SAU是一种通过特定的软件工具来协助进行更新的方式。这个术语可能与不同制造商的专有软件更新工具有关。
  • 用户通常需要下载并安装这种更新助手到他们的电脑上,然后将设备通过USB连接到电脑进行更新。
  • SAU升级可能用于较大的更新,或者修复通过OTA更新无法解决的问题。
  • 也有时用于在设备无法启动或者无法连接到网络时进行的修复性更新。

这两种更新方式的主要区别在于,OTA更新不需要用户使用电脑,整个过程更加无缝和便捷,而SAU更新往往需要电脑的辅助,并且流程相对复杂一些。但是具体到“SAU”这个术语,不同的制造商可能有不同的具体实现和流程,所以实际操作可能与上述说明有所不同。

MVC和前后端分离

来自你的消息:

mvc中的model指什么

来自 ChatGPT 的消息:

在MVC架构中,Model指的是应用程序中的数据和业务逻辑。它负责处理数据的读取、存储、验证和计算,并且封装了与数据相关的操作。Model通常包含以下几个主要功能:

  1. 数据存储:Model负责与数据库、文件系统或其他数据源进行交互,读取和存储数据。

  2. 数据验证和处理:Model对输入的数据进行验证和处理,确保数据的有效性和完整性。例如,对于用户提交的表单数据,Model可以验证数据的格式、范围、必填项等。

  3. 业务逻辑:Model包含应用程序的业务逻辑,定义了数据的操作规则和流程。它通常包括处理用户请求、数据计算、状态管理等功能,以实现应用程序的核心功能。

  4. 数据传输:Model负责将数据传递给View进行展示,并将用户的操作传递给Controller进行处理。

总之,Model在MVC架构中充当数据和业务逻辑的核心组件,独立于View和Controller,并且与之相互通信,实现了数据和行为的分离。

来自你的消息:

mvc就是前后端耦合吗

来自 ChatGPT 的消息:

不,MVC架构的设计目的是为了实现前端和后端的解耦。它将应用程序分为三个主要的组件:Model、View和Controller,每个组件有不同的职责,各自独立于彼此。

  • Model负责处理数据和业务逻辑,它独立于前端和后端,可以在不同的环境中重用。

  • View负责展示数据给用户,通常是在前端实现,但并不涉及业务逻辑和数据处理。

  • Controller负责接受用户的输入(例如点击按钮、提交表单等),处理用户请求,并将数据传递给Model进行处理。

因为View和Controller是相互分离的,所以可以更容易地实现前端和后端之间的解耦。前端开发人员可以专注于View的设计和交互,后端开发人员可以专注于Model和业务逻辑的实现。这种分离使得前端和后端可以独立开发、测试和维护,提高了代码的可维护性和可复用性。

总的来说,MVC架构的目标是实现前后端的解耦,提高代码的可维护性和重用性。但是,在实际开发中,如果不严格遵守MVC的设计原则,可能会导致前后端之间的耦合。因此,在使用MVC架构时,需要注意合理地划分各个组件的职责,避免耦合问题的产生。

来自你的消息:

前后端分离就是mvc吗

来自 ChatGPT 的消息:

前后端分离和MVC是两个不同的概念。虽然它们可以相互结合使用,但并不代表它们是等价的。

前后端分离是一种架构设计模式,将应用程序的前端和后端完全分离开发、部署和运行。前端通常使用HTML、CSS和JavaScript等技术,负责展示数据和处理用户交互;后端则提供API接口,负责数据处理和业务逻辑。前端和后端可以独立进行开发、测试和部署,前端可以使用不同的技术栈实现,例如React、Vue、Angular等。

MVC是一种软件设计模式,用于解耦应用程序的不同组件,包括Model、View和Controller。MVC将应用程序分为三个组件,每个组件有不同的职责和关注点。Model负责数据和业务逻辑,View负责展示数据给用户,Controller负责处理用户输入和调度数据流动。

前后端分离可以与MVC结合使用,即将应用程序的前端设计为MVC架构,后端提供API接口供前端调用。前端的View部分使用MVC模式进行组织,Controller负责调用后端API获取数据,并将数据传递给View进行展示。在这种情况下,前后端分离提供了更灵活和可扩展的架构,使得前端和后端开发可以独立进行,并且可以灵活选择不同的技术栈和框架。

综上所述,前后端分离和MVC是两个不同的概念,前后端分离是一种架构设计模式,而MVC是一种软件设计模式,可以与前后端分离结合使用。

来自你的消息:

mvc和ddd的关系

来自 ChatGPT 的消息:

MVC(Model-View-Controller)和DDD(领域驱动设计)是两种不同的软件设计模式和开发思想。

MVC是一种用于组织应用程序的架构模式,通过将应用程序分为Model、View和Controller来实现解耦、分离关注点。Model负责处理数据和业务逻辑,View负责展示数据给用户,Controller负责处理用户输入和协调Model和View之间的交互。

DDD是一种面向领域模型开发的方法论,强调以领域模型为核心,将业务逻辑和规则体现在代码中。DDD提倡根据业务领域的特点和需求设计领域模型,通过领域模型来解决问题。领域模型包含业务规则、约束和相关的领域知识,它是对领域的抽象和建模。

MVC和DDD在设计层面有一些相似之处,例如都强调解耦和分离关注点,都注重业务逻辑的模块化和可复用性。但是,它们的关注点和目标略有不同。

MVC主要关注设计架构、组织代码和实现关注点分离,通过三个组件的协作来实现应用程序的开发和维护。

DDD主要关注领域模型和业务逻辑的设计,通过建模和实现领域模型来解决复杂的业务问题,以及提供灵活、可维护和可扩展的软件系统。

在实践中,MVC和DDD可以结合使用。MVC可以提供一个良好的架构模式来实现视图、控制器和模型之间的交互,而DDD可以帮助在模型的层次上更好地组织和实现业务逻辑。例如,可以在MVC架构中使用DDD的领域模型来实现业务规则和约束,并将其应用于Model组件。

综上所述,MVC和DDD是两个不同的设计模式和开发思想,各自有不同的关注点和目标。它们可以结合使用,以实现更好的应用程序开发和设计。

沟通

知识的诅咒

“知识诅咒”可能是指“知识的诅咒”(Curse of Knowledge),这是一种认知偏差,指的是一旦人们掌握了某个知识,就很难想象其他人不具备那样的知识或信息。这会导致沟通和教学上的障碍,因为知识丰富的人往往高估其他人的了解程度。

在商业、教育和日常交流中,知识的诅咒可能导致专家无法把复杂的概念简化地传达给新手或非专家,从而影响信息的有效传递。例如,一个科学家试图向非专业听众解释复杂的科学原理时,可能会不自觉地使用行话或假设听众有一定的背景知识,进而使听众难以理解。

克服知识的诅咒需要意识到它的存在并采取措施,比如:

  • 使用简单、通俗的语言来解释概念。
  • 提供背景信息,帮助听众建立知识框架。
  • 回顾和总结要点,确保信息被正确理解。
  • 鼓励问题和反馈,了解信息是否被清晰传达。

通过这些方式,一个人可以更有效地与不同知识水平的人沟通。

疑问

数据库设计的时候是统一设计成父亲找儿子,还是儿子找父亲

已知:如果1:n,n一定要记录1的id的
已知:如果子表需要被复用的话,那么就只能另一张表去记录这个关联id了

定时任务如何保活

1.当使用分布式定时任务框架的时候,定时任务怎么做到不被垃圾回收器回收的

2.如果使用guava cache/ScheduledExecutorService进行定时任务的刷新怎么保证他不被回收