小程序中的大道理--综述

2023-11-25 11:01
文章标签 程序 综述 大道理

本文主要是介绍小程序中的大道理--综述,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

以下将用一个小程序来探讨一些大道理, 这些大道理包括可扩展性, 抽象与封装, 可维护性, 健壮性, 团队合作, 工具的利用, 可测试性, 自顶向下, 分而治之, 分层, 可读性, 模块化, 松耦合, MVC, 领域模型, 甚至对称性, 香农的信息论等等.

为什么不用大程序来说大道理呢?

因为大程序太大了, 代码一端上来, 读者就晕菜了, 看不过来甚至压根不想去看, 这样说理就很抽象了, 效果反而不好.

小程序中也能说出大道理来吗?

我们有句话, 叫"以小见大", 我们又常常有种说法, 叫:

麻雀虽小, 五毒俱全. (咦? 好像应该是五脏俱全…总之你明白我的意思就好了. )

所以呢, 小程序也是可以来说大道理的, 而且小程序又有短小的特点, 大家看得也没那么累, 也很快能看懂. 毕竟那种代码, 叫什么来着, “意大利面条式的代码”, 大家在实际的开发中, 已经见得太多了.

意大利面(spaghetti), 翻译过来好像叫"通心粉", 非常长的一条条, 彼此缠缠绕绕的, 所以"意大利面条式的代码"就是又长又绕, 让人非常头痛的那种代码.

按我们的习惯, 也许叫它"裹脚布式的代码"大家觉得更熟悉, 更形象一点, 也正好符合"又长又臭"的特点.

啊, 说"又长又臭"可能有点刻薄了, 毕竟大家都可能写过这样的代码(本人就写过好多), 即便现在不会再写这样的代码, 想当年应该也是写过的, 除非你从一开始觉悟通天, 那我就无话可说了.

这种代码我们在工作中见得太多了, 所以这里就不再弄出来考验大家的毅力了, 闲话少提, 让我们看个简单的例子.

我们的例子

就是要打印出如下的一个三角形图案:

  ****
*****

当然了, 这只是以三行为一个示例, 我们的程序应该接受任意的正整数, 比如, 给一个 5, 就要能打出 5 行的类似的三角形来. 让我们来看看如何写出这样一个程序, 并在这个过程中借此兜售我们的大道理.

玩具式的代码

我知道很多"数学帝"可能一眼就被图案中的规律吸引过去了, 他们很快就指出星号是等差数列, 然后很快就弄出了计算每行前面要缩进多少个空格的公式, 然后呢, 一层循环, 二层循环, blablablah…然后最里面几条优雅而性感的 print 语句, 搞掂!一种智商上的优越感油然而生, 接着他们可能就要问:

这么简单的东西, 你也好意思拿出来讲?

下面是这样的一个代码, 能够完全实现以上要求(只演示了 3 行的情况):

public static void main(String[] args) {int i = 3;for (int j = 0; j < i; j++) {for (int k = 0; k < i - j; k++) {System.out.print(" ");}for (int z = 0; z < 2*j+1; z++) {System.out.print("*");}System.out.println();}
}

这里用的是 java 语言来演示, 包括以下的. 我相信像 java 这样烂大街的语言, 即使你没这个背景看懂也不是难事, 在代码中也不会用到什么高深的特性. (这一点皆因我的能力有限所导致, 而不是想装逼的意愿所能决定的~)

怎么说呢, 我们不要以上那种"玩具式"的代码(toy program), 我们要的是生产级(production, 生产环境)的代码.

生产级的代码

让我们来看看如何写出这样的代码.

可扩展性(Extensibility)

首先呢, print 语句是绝对要避免的. 你要明白, print 语句写得太死, 而需求是不断在变化的, 有句话是怎么说的?

唯一不变的就是变化本身.

客户今天跟你说的是要 print 这个图案, 你要是按着客户怎么说, 你就怎么做, 你可就惨了.

客户哪一天突然又会说, 再加点特性, 要能输出到文件;哪一天又说, 再加点 web service, 能供其它程序调用.

让我们多留点心眼, 代码如下:

public void printPattern(int lineCount) {String pattern = getPattern(lineCount);System.out.print(pattern);
}

我们先借助 getPattern 方法拿到要打印的内容, 这样, 如果哪天要输出到文件, 哪天要供 web service 调用, 我们都可以把这个 getPattern 方法提供出去.

我们只要多抽象出那么一层来, 就会给我们带来很多方便.

抽象与封装(Abstraction & Encapsulation)

抽象与封装同时也是很多其它特性的基础, 在后面我们还会不断说到这一主题.

getPattern 就是一个抽象, 是对一系列动作的一个封装.

可能有人会比较教条地认为抽象与封装只能在类层次中进行, 这常常导致在类的内部缺少必要的抽象层次, 常常是一大件事情在一个方法里完成, 方法巨大巨长无比, 这样的所谓面向对象编程不过是虚有其表, 其模块性甚至还比不上那些用面向过程语言写就的代码.

printPattern 层面, 我们不需要知道 getPattern 的细节, 我们只需要传入所需参数及定义好需要的返回值即可.

大道理: 定义好输入与输出, 描述清楚想要做的事, 先不用去管细节.

然后呢, 我们是不是需要手动去把这个方法写出来呢?

利用好你的工具(Tools)

你不用手动去做这些, 以 eclipse 为例, 只要把光标定位到错误的地方(可以按Ctrl+“.”(点)快速定位), 然后按下"Ctrl+1", 然后选择"Create Method"即可:

eclipse create method

工具将根据传入参数及返回值自动为我们生成方法, 结果如下:

eclipse create method

只要输入与输出定义清楚了, 工具就能自动帮我们生成方法定义, 这里默认它是 private 的, 我们可以把它改成 public.

这里说的是 Eclipse 这个 IDE, 其它的我相信也会有类似的功能. 如果你偏好轻量级的文本编辑器, 那我就不敢说也一定有这些功能了.

利用好任务标识(Task Tags)

我们可以看到, 生成的代码里有个 TODO, 显示出了特别的颜色, 这是个任务标识.

类似的标识还有 FIXME, XXX, 甚至你还可以自定义标识.

打开 eclipse 的菜单-- windows–preferences, 在过滤框中输入"task tag":

eclipse task tag

这些有什么用呢? 我们可以看下, 在编辑器的左右侧, 都有显著的标志提示有个任务标识存在;在 Markers 视图里, 有列举出这些标识:

eclipse todo task tag

在代码质量分析工具 sonar 中, 它也会追踪这些标识. 下图是我在 sonar.oschina.net 上的一个项目的截图:

sonar todo tag

这些有什么用呢? 我们在写代码中, 写到一半, 很可能被某些难题卡住了, 为了不中断正常的流程, 我们先用个 TODO 来标识, 然后就可以继续地把一些简单的问题先处理完, 再回过头来对付这些.

又或者像现在这样, 我们生成了出来了这个方法, 工具为我们自动加了入"TODO"的标识, 毕竟方法的主体还没有, 可不巧的是, 现在到了下班时间了, 然后呢, 我们就可以存盘并提交到 svn 或者 git 上去了. 有人可能要说: "啊? 不是吧, 你的代码都没写完你怎么就提交了? "

没关系, 我们已经标识好了 TODO, 所以它会提醒我们还有工作是没做完的. 另外我们为何如此着急提交呢? 因为我们并不是在单打独斗:

团队合作(Teamwork)

我们前面说了, 我们可能还要做输出图案到文件的需求, 很可能你有个同事哥们, 他就正做着这个模块, 而他现在呢, 就在等着你这个 getPattern 方法. 你提交了, 他就可以继续写他的代码了:

package org.jcc.core.demo;public class PatternFile {private Pattern pattern;public PatternFile(Pattern pattern) {this.pattern = pattern;}public void generatePatternFile(int lineCount) {String content = pattern.getPattern(lineCount);saveInFile(content);}private void saveInFile(String content) {// TODO Auto-generated method stub//System.out.println(content);}
}

可以看到, 他的类依赖你的类, 在他的方法 generatePatternFile 里还调用了 getPattern 方法, 你没实现, 那又怎样呢? 接口好了就行了!

面向接口编程(Interface)

有人可能比较死板, 比较教条主义, 以为呢, 说到接口就一定要弄个 interface, 其实呢, 我们这个方法 getPattern 就是一个承诺, 一个约定, 一个协议, 也是一个广义上的接口.

有人可能要问, 你方法细节还没有实现, 他怎么测试? 别担心, 办法会有的:

利用 Mockito 来测试

代码如下:

@Test
public void testGeneratePatternFile() {// 用mockito来模拟接口的行为, 为此我们手动构建一个三行的图案Pattern pattern = Mockito.mock(Pattern.class);String mockContent = "  *" + System.lineSeparator() + " ***" + System.lineSeparator() + "*****" + System.lineSeparator();// 当调用getPattern方法时, 就返回这里定义好的内容. Mockito.when(pattern.getPattern(3)).thenReturn(mockContent);// 测试generatePatternFile方法, 在它的里面将会调用getPattern方法PatternFile pf = new PatternFile(pattern);pf.generatePatternFile(3);// TODO 断言文件存在并且文件中的内容与mockContent一致// assert that file is exists and content in file is equals the mock content
}

以上我们用一个 mock 对象以及 when, thenReturn 来主动模拟一个尚未实现的方法.

你也许对 Mock 之类的技术还不太了解, 但这些词表达的意思我想大家都不难明白. Mock 的更详细介绍请自行百度之.

借助 Mockito, 这个哥们就可以这样写好他的代码, 并完成他的测试了, 然后可以提交他的代码, 宣布工作完成, 接着他就可以飞到马尔代夫去度假去了.

可以看到, 尽管我们的功能八字还没一撇, 可只要我们坚持面向接口编程, 时时想着团队合作, 经常提交已经写好的代码, 特别是公共接口方面的代码, 我们的同事就能及时推进他们的工作, 甚至比我们还早完成, 这都是有可能的, 都是正常的, 也是我们应该追求的.

而利用好抽象及封装, 我们还能得到好几个好处:

可测试性(Testability)

通过以上举例, 可以看到, 我们可以手动构建一个图案, 并交给程序去判断(注: 为了简短起见, 代码中省略了具体的 assert 细节). 而如果是开头那样直接就打印了呢? 你根本没法让程序去判断, 只能通过人眼去观察输出, 这样就给 自动化的测试(Automatic Test) 带来了困难.

可重用性(Reusability)

getPattern 被抽象出来之后, 可以看到, 不但可以在 printPattern 方法里使用, 也可以在 generatePatternFile 方法里使用. 而如果按开头那样呢? 你没法复用, 你还是不得不重构;又或者你可能只是简单地把代码复制一遍了, 再作些改动.

当然, 现在这个程序很小, 全部拷贝一遍好像也很快, 但如果是很大的程序呢? 又或者我们又要拓展到可供 web service 调用, 难道就这样拷贝下去? 哪一天程序要做些小调整, 难道又要一一去修改吗?

不要重复(DRY: Don’t Repeat Yourself)

管理重复性一直都是程序开发中的重大关切, 在目前这个小程序里, 这一问题还不是那么迫切, 这个在此就不作详述, 以后会另写一些文章来做些介绍.

好了, 说了一大通, 绕了一大圈, 测试也测了, 同事也度假去了, 我们也要赶紧我们的工作. 那么接下来是不是赶紧写那些实现呢? 不!

我们已经介绍了不少的"ility"结尾的单词, 接下来还要说到!我有点担心大家说我"zhuangbility", 有句话说: “Don’t zhuangbility, zhuangbility leads to leipility”(莫装逼, 装逼遭雷劈), 没办法, 为了阐述这些大道理, 我也只好冒着被 leipility 的危险.

可维护性(Maintainability)

你首先把注释写好:

怎么说呢? 现在 IT 工作强度很大, 过劳死是不稀奇的事, 写着写着说不定哪天人就挂了. 一个人挂了不要紧, 工作可不能挂!(不是在说笑话, 貌似有些公司或老板表现出来的态度就是这样的~)

别人要能顺利接手你的活, 这是关键.

其实没必要说"挂了"这些不吉利的话, 也可能是有人要生了, 比如你老婆要生了, 你也休产假去了, 你写到一半, 老板把你的工作转交给你的同事.

试想, 要是一点注释都没有, 你的同事接手起来就很困难, 他要加班加点才能早点弄清你的代码的意图. 所以呢, 不要害了你的同事!把代码的可维护性做好, 大家的健康也才有更好的可维护性!

代码如下:

/*** 获取指定行数的图案, 比如3行时: *   **  **** ******  * @param lineCount 指定的行数* @return 图案的字符串表示, 包括换行符在内*/
public String getPattern(int lineCount) {// TODO Auto-generated method stubreturn null;
}

其实, 良好的命名同样也是可维护性的关键, 比如上面的 getPattern, lineCount, 而不是像最前面那个示例中的 i, j, k, z 等乱七八糟的名字.

另外, 丰富的抽象层次也是如此, 这点我们后续还会不断提及.

好了, 注释也写完了, 然后呢, 现在该轮到写那个该死的等差数列了吧? 不!

健壮性(Robustness)

Robustness 又常常音译成鲁棒性.

作者在大学时读的是自动化专业, 在那些自动控制理论里, 老出现什么鲁棒性, 看了让人犯晕, 不如直接叫健壮性.

我倒是想起了小时候老爸常买给我喝的 Robust(即乐百氏, 与娃哈哈类似的饮品), 味道是不错, 不过喝完身体挺没见得健壮到哪去, 也许喝得还不够多~

我们先要把判断做好, 输入负数或者输入的数字太大了, 你要拒绝它们, 同时在注释中也作出说明:

/*** 获取指定行数的图案, 比如3行时: *   **  **** ******  * @param lineCount 指定的行数, 1-20之间* @return 图案的字符串表示, 包括换行符在内*/
public String getPattern(int lineCount) {if (lineCount < 1) {throw new IllegalArgumentException("行数不能小于1!");}if (lineCount > 20) {throw new IllegalArgumentException("行数不能大于20!");}// TODO return null;
}

我知道我在这里说这些, 有些人可能已经不耐烦了, 他们想着的是写那些有技巧的代码, 那些有挑战性的部分, 那些 tricky 的部分, 那些能体现出他们智商上的优越感的部分.

有个词是怎么说的, “rocket science”(火箭科学, 喻指那些高精尖的技术), 特别的有些刚毕业的心气很高的学生, 满脑子想的可能就是这些. 可是呢, 类似情况不是没有, 但通常是很少的:

骚年, 不是我在打击你, 你也许真的想多了. 工作上, 我们多数时候处理的都是一些细节的问题, 一些琐碎的事情, 一些按部就班的样板式的代码, 需要的不是多高的智商, 多么 tricky 的技巧, 要是是耐心, 细致, 严谨, 一丝不苟.

为何一开始就要把这些做好呢? 因为到了后面, 你就没时间去做了. 这一点你一定要相信我, 以下引自 wiki 的"90-90法则":

前 90% 的代码要花费你 90% 的开发时间, 剩余的 10% 的代码要花费你另一个 90% 的开发时间.

The first 90 percent of the code accounts for the first 90 percent of the development time. The remaining 10 percent of the code accounts for the other 90 percent of the development time.

–Tom Cargill, 贝尔实验室

而最后如果因为时间紧急, 就这样没保护就上了生产环境, 一旦出了问题, 你会花更多的时间去收拾这些烂摊子, 而最终你还是不得不将这些补上.

有一个"墨菲定律"(Murphy’s Law)大意是这么说的:

有可能出错的的东西一定会出错.

现在不擦屁股, 后面还有得擦. 你省掉了纸尿裤, 你的程序就裸奔了, 你就等着洗更多的外套.

我们也常说: "该来的一定会来. "如果用电影<<无间道>>里的话来说呢, 那就是:

“出来混, 迟早要还的”. (哇塞, 说得太精彩了. 这些编导或者剧作家不去写教科书太可惜了. )

所以呢, 不要有侥幸的心理, 把程序从一开始就写健壮才是正道.

小结

说了半天, 我们甚至连一行核心代码都没写, 不过, 文章至此倒是要先做一个阶段了结了. 我们说写代码有个原则, 那就是方法不能太长, 最好一个屏幕就能显示完, 否则看起来就很累了;自然的, 文章也不能写得太长, 否则写起来, 读起来都很累人.

所以呢, 虽然一开始那里提了好多的道理, 本来也是想一扒到底的, 但扒到一半发现已经很长了, 所以上半身扒完, 就此腰斩, 下半身留待后面继续扒, 下半身更精彩, 我们下回再见.

下一篇, 见 小程序中的大道理之二 .

这篇关于小程序中的大道理--综述的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/423674

相关文章

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

EMLOG程序单页友链和标签增加美化

单页友联效果图: 标签页面效果图: 源码介绍 EMLOG单页友情链接和TAG标签,友链单页文件代码main{width: 58%;是设置宽度 自己把设置成与您的网站宽度一样,如果自适应就填写100%,TAG文件不用修改 安装方法:把Links.php和tag.php上传到网站根目录即可,访问 域名/Links.php、域名/tag.php 所有模板适用,代码就不粘贴出来,已经打

跨系统环境下LabVIEW程序稳定运行

在LabVIEW开发中,不同电脑的配置和操作系统(如Win11与Win7)可能对程序的稳定运行产生影响。为了确保程序在不同平台上都能正常且稳定运行,需要从兼容性、驱动、以及性能优化等多个方面入手。本文将详细介绍如何在不同系统环境下,使LabVIEW开发的程序保持稳定运行的有效策略。 LabVIEW版本兼容性 LabVIEW各版本对不同操作系统的支持存在差异。因此,在开发程序时,尽量使用

CSP 2023 提高级第一轮 CSP-S 2023初试题 完善程序第二题解析 未完

一、题目阅读 (最大值之和)给定整数序列 a0,⋯,an−1,求该序列所有非空连续子序列的最大值之和。上述参数满足 1≤n≤105 和 1≤ai≤108。 一个序列的非空连续子序列可以用两个下标 ll 和 rr(其中0≤l≤r<n0≤l≤r<n)表示,对应的序列为 al,al+1,⋯,ar​。两个非空连续子序列不同,当且仅当下标不同。 例如,当原序列为 [1,2,1,2] 时,要计算子序列 [

这些心智程序你安装了吗?

原文题目:《为什么聪明人也会做蠢事(四)》 心智程序 大脑有两个特征导致人类不够理性,一个是处理信息方面的缺陷,一个是心智程序出了问题。前者可以称为“认知吝啬鬼”,前几篇文章已经讨论了。本期主要讲心智程序这个方面。 心智程序这一概念由哈佛大学认知科学家大卫•帕金斯提出,指个体可以从记忆中提取出的规则、知识、程序和策略,以辅助我们决策判断和解决问题。如果把人脑比喻成计算机,那心智程序就是人脑的

uniapp设置微信小程序的交互反馈

链接:uni.showToast(OBJECT) | uni-app官网 (dcloud.net.cn) 设置操作成功的弹窗: title是我们弹窗提示的文字 showToast是我们在加载的时候进入就会弹出的提示。 2.设置失败的提示窗口和标签 icon:'error'是设置我们失败的logo 设置的文字上限是7个文字,如果需要设置的提示文字过长就需要设置icon并给

基于SpringBoot的宠物服务系统+uniapp小程序+LW参考示例

系列文章目录 1.基于SSM的洗衣房管理系统+原生微信小程序+LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统+LW参考示例 3.基于SpringBoot+Vue的企业人事管理系统+LW参考示例 4.基于SSM的高校实验室管理系统+LW参考示例 5.基于SpringBoot的二手数码回收系统+原生微信小程序+LW参考示例 6.基于SSM的民宿预订管理系统+LW参考示例 7.基于

Spring Roo 实站( 一 )部署安装 第一个示例程序

转自:http://blog.csdn.net/jun55xiu/article/details/9380213 一:安装 注:可以参与官网spring-roo: static.springsource.org/spring-roo/reference/html/intro.html#intro-exploring-sampleROO_OPTS http://stati

未来工作趋势:零工小程序在共享经济中的作用

经济在不断发展的同时,科技也在飞速发展。零工经济作为一种新兴的工作模式,正在全球范围内迅速崛起。特别是在中国,随着数字经济的蓬勃发展和共享经济模式的深入推广,零工小程序在促进就业、提升资源利用效率方面显示出了巨大的潜力和价值。 一、零工经济的定义及现状 零工经济是指通过临时性、自由职业或项目制的工作形式,利用互联网平台快速匹配供需双方的新型经济模式。这种模式打破了传统全职工作的界限,为劳动

Java程序到CPU上执行 的步骤

相信很多的小伙伴在最初学习编程的时候会容易产生一个疑惑❓,那就是编写的Java代码究竟是怎么一步一步到CPU上去执行的呢?CPU又是如何执行的呢?今天跟随小编的脚步去化解开这个疑惑❓。 在学习这个过程之前,我们需要先讲解一些与本内容相关的知识点 指令 指令是指导CPU运行的命令,主要由操作码+被操作数组成。 其中操作码用来表示要做什么动作,被操作数是本条指令要操作的数据,可能是内存地址,也