在许多情况下,具有功能组成的声明式解决方案提供了优于传统命令式代码的优越代码度量。 阅读本文并了解如何使用具有功能组成的声明性代码成为更好的程序员。

在本文中,我们将仔细研究三个问题示例,并研究用于解决这些问题的两种不同技术(命令式和声明式)。

本文中的所有源代码都是开源的,可以在以下位置获得
https://github.com/minborg/imperative-vs-declarative 。 最后,我们还将看到如何将本文的知识应用于数据库应用程序领域。 我们将使用Speedment Stream作为ORM工具,因为它提供了与数据库中的表,视图和联接相对应的标准Java Streams,并支持声明性构造。

从字面上看,有无数个示例候选可用于代码度量评估。

问题范例

在本文中,我选择了开发人员在工作期间可能会遇到的三个常见问题:

SumArray

遍历数组并执行计算

分组

并行汇总值

休息

通过分页实现REST接口

解决技术

正如本文开头所暗示的,我们将使用以下两种编码技术来解决上述问题:

势在必行

一种命令式解决方案,其中我们使用带有for循环和显式可变状态的传统代码样式。

陈述式

声明性解决方案,其中我们组合了各种功能以形成可以解决问题的高阶复合功能,通常使用
java.util.stream.Stream或其变体。

代码指标

然后,想法是使用适用于SonarQube(此处为SonarQube社区版,版本7.7)的不同解决方案的静态代码分析,以便我们可以为问题/解决方案组合得出有用的标准化代码度量。 然后将这些指标进行比较。

在本文中,我们将使用以下代码指标:

LOC

“ LOC”表示“代码行”,是代码中非空行的数量。

陈述

是代码中语句的总数。 每条代码行上可能有零到多条语句。

圈复杂度

指示代码的复杂性,是对通过程序源代码的线性独立路径数量的定量度量。 例如,单个“ if”子句在代码中提供了两条单独的路径。
了这里的维基百科。

认知复杂性

SonarCube声称:“认知复杂性不同于使用数学模型评估软件可维护性的实践。 它从Cyclomatic Complexity设定的先例开始,但是使用人工判断来评估应如何计算结构并决定应向模型整体添加哪些内容。 结果,它得出的方法复杂性得分比以前的模型更能使程序员对可维护性进行相对公平的评估。” 在SonarCube自己的页面上了解更多信息 。

通常,最好构想一个解决方案,其中这些指标较小,而不是较大。

作为记录,应该注意的是,以下设计的任何解决方案只是解决任何给定问题的一种方法。 让我知道您是否有更好的解决方案,并随时通过https://github.com/minborg/imperative-vs-declarative提交拉取请求。

遍历数组

我们从一个简单的开始。 该问题示例的对象是计算int数组中元素的总和,并将结果返回为
long 。 以下接口定义了问题:

 public interface SumArray { long sum( int [] arr);  } 

当务之急

以下解决方案使用命令式技术实现SumArray问题:

 public class SumArrayImperative implements SumArray { @Override public long sum( int [] arr) { long sum = 0 ; for ( int i : arr) { sum += i; } return sum; }  } 

声明式解决方案

这是使用声明性技术实现SumArray的解决方案:

 public class SumArrayDeclarative implements SumArray { @Override public long sum( int [] arr) { return IntStream.of(arr) .mapToLong(i -> i) .sum(); }  } 

注意, IntStream::sum只返回一个int,因此我们必须应用中间操作mapToLong()

分析

SonarQube提供以下分析:



下表显示了SumArray的代码指标(通常越低越好):

技术 LOC 陈述 圈复杂度 认知复杂性
势在必行 12 5 2 1个
功能性 11 2 2 0

这是它在图形中的外观(通常越低越好):


并行汇总值

该问题示例的对象是将“ Person对象分组到不同的存储桶中,其中每个存储桶构成一个人的出生年份和一个工作的国家/地区的唯一组合。对于每个组,应计算平均工资。 聚合应使用公共ForkJoin池并行计算。

(不变的) Person类是这样的:

势在必行

我们还定义了另一个称为YearCountry不变类,该类将用作分组键:

势在必行

定义了这两个类之后,我们现在可以通过以下接口定义此问题示例:

势在必行

当务之急

GroupingBy示例问题实施命令式解决方案并非难事。 这是解决问题的一种解决方案:

势在必行

声明式解决方案

这是一个使用声明性构造实现GroupingBy的解决方案:

势在必行

在上面的代码中,我使用了一些静态导入
Collectors类(例如Collectors::groupingBy )。 这不会影响代码指标。

分析

SonarQube提供以下分析:



下表显示了GroupingBy的代码指标(越低越好):

技术 LOC 陈述 圈复杂度 认知复杂性
势在必行 52 27 11 4
功能性 17 1个 1个 0

相应的图形如下所示(通常越低越好):


实施REST接口

在这个示例性问题中,我们将为Person对象提供分页服务。 出现在页面上的人员必须满足某些(任意)条件,并且必须按照给定的顺序进行排序。 该页面应作为不可修改的“个人”对象列表返回。

这是捕获问题的接口:

势在必行

页面的大小在一个单独的实用程序类RestUtil

势在必行

当务之急

这是Rest接口的命令性实现:

势在必行

声明式解决方案

下列类以声明的方式实现Rest接口:

势在必行

分析

SonarQube提供以下分析:



下表显示了Rest的代码指标(通常越低越好):

技术 LOC 陈述 圈复杂度 认知复杂性
势在必行 27 10 4 4
功能性 21 1个 1个 0

在这里,相同的数字显示在图表中(再次降低通常会更好):


Java 11的改进

上面的示例是用Java 8编写的。使用Java 11,我们可以使用LVTI(局部变量类型推断)来缩短声明性代码。 这会使我们的代码短一些,但不会影响代码指标。

势在必行

与Java 8相比,Java 11包含一些新的收集器。 例如,
Collectors.toUnmodifiableList()可以使我们的声明式Rest解决方案更短:

势在必行

同样,这不会影响代码指标。

摘要

对我们的三个示例性问题的代码度量取平均会得出以下结果(通常越低越好):


考虑到本文的输入要求,当我们从命令式构造到声明式构造时,所有代码度量都有显着改进。

在数据库应用程序中使用声明性构造

为了从数据库应用程序中获得声明式构造的好处,我们使用了Speedment Stream 。 Speedment Stream是基于Stream的Java ORM工具,可以将任何数据库表/视图/联接转换为Java流,从而使您可以在数据库应用程序中运用声明性技能。

您的数据库应用程序代码将变得更好。 实际上,针对数据库的具有Speedment和Spring Boot的分页REST解决方案可能表示如下:

势在必行

Speedment提供Manager<Person> persons ,并构成数据库表“ Person”的句柄,并且可以通过Spring @AutoWired进行管理。

结论

选择声明式而不是命令式解决方案可以大大降低通用代码的复杂性,并可以提供许多好处,包括更快的编码,更好的代码质量,提高的可读性,更少的测试,减少的维护成本等等。

为了从数据库应用程序中的声明性构造中受益,Speedment Stream是一种可以直接从数据库提供标准Java Streams的工具。

如今,对于任何当代的Java开发人员来说,必须掌握声明性构造和功能组成。

资源资源

文章源代码: https : //github.com/minborg/imperative-vs-declarative

SonarQube: https ://www.sonarqube.org/ Speedment Stream: https ://speedment.com/stream/ Speedment初始化程序: https ://www.speedment.com/initializer/

翻译自: https://www.javacodegeeks.com/2019/08/declarative-coding-makes-better-programmer.html

为什么声明性编码使您成为更好的程序员相关推荐

  1. 程序员 rs编码_为什么声明性编码使您成为更好的程序员

    程序员 rs编码 在许多情况下,具有功能组成的声明式解决方案提供了优于传统命令式代码的出色代码指标. 阅读本文并了解如何使用具有功能组成的声明性代码成为一名更好的程序员. 在本文中,我们将仔细研究三个 ...

  2. 什么是伪代码,它如何使你成为更好的程序员?

    努力学习编程?通过学习伪代码来掌握代码.但是什么是伪代码,它真的有帮助吗? 当你第一次开始学习编程时,在构建第一个应用程序之前,需要学习很多东西.像程序员一样思考可以帮助你将问题分解为算法来解决问题. ...

  3. 程序员如何学习更好的知识_如何保持学习并成为更好的程序员

    程序员如何学习更好的知识 by Kevin Gardner 凯文·加德纳(Kevin Gardner) 如何保持学习并成为更好的程序员 (How to keep learning and become ...

  4. 比程序员更好的职业_立即成为更好的程序员的20条技巧

    比程序员更好的职业 目录: (Table of contents:) Think Before You Code 编码前先思考 Understand the Business Behind Every ...

  5. 编码之道(六):程序员的修练之道

    程序员对具体的技术的掌握的确很重要,因为程序员就是使用这些技术来编码代码的.但真正决定一个程序员的能力及未来的可朔性的,只能是编码之道. 那究竟做为一个程序员,我们要如何追求编码之道呢? 本周,继续聊 ...

  6. 如何成为更优秀的程序员?程序员进阶的8种途径

    本文讲述了8种方式帮助你如何从一名普通的程序员进阶成为一名伟大的程序员,让我们就从此时此刻开始提高自己的开发技能吧. 是时候开始认真考虑一下如何升级你的java开发技术了.让我们来认真地学习一下吧. ...

  7. 如何成为一个更好的程序员,或者说是学习者?给你七个建议!

    点击关注上方"五分钟学算法", 设为"置顶或星标",第一时间送达干货. 转自编码之外 今天庆哥就来和大家聊聊,如何成为一个更好的程序员,毕竟别人都说程序员都是屌 ...

  8. 如何编写好的代码/成为一个更好的程序员

    如何编写好的代码/成为一个更好的程序员 几个月前,有一位演讲者来到公司谈论优美的代码,他的论点是优美的代码以许多不同的形式出现.简单中有优美,折衷中有优美,稳定性上有优美,功能上有优美,坚固性上有优美 ...

  9. deep work_如何使用Deep Work成为更好的程序员

    deep work by Victor Cassone 由Victor Cassone 如何使用Deep Work成为更好的程序员 (How to use Deep Work to become a ...

最新文章

  1. Django error信息邮件通知功能配置部署
  2. 正值实系数多项式函数所对应的导数累加和是否非负?
  3. linux系统编码修改
  4. Mysql与Sql Server查询数据库中表以及表字段
  5. nrf51822-主从通信分析2
  6. cell操作-matlab
  7. NClay框架MVC应用入门
  8. 【Linux】Linux的关机和虚拟机克隆、快照
  9. jpeg图片格式详解
  10. Linux 服务器配置 ASF 云挂卡
  11. 2021-07-03 dd命令拷贝数据错误的问题定位及解决方法
  12. OBS开源免费桌面视频直播工具/直播推流工具使用指南
  13. 怎么做应力应变曲线_如何用Origin画应力应变曲线 - 图文 -
  14. vertica基本操作
  15. MOOC-大型开放式网络课程massive open online courses
  16. 移动开发之设计模式- 中介者模式(IOSAndroid)
  17. 【机器人运动学/姿态角】欧拉角和RPY角
  18. windows server 2008r2 oracle11g安装
  19. Wio Terminal 读取 AHT10 传感器
  20. 交通外场及内场设备 前端中端后端设备

热门文章

  1. 二分图相关结论及口胡证明
  2. P3980 NOI2008志愿者招募
  3. 漫画:什么是计数排序
  4. 隐马尔科夫模型-前向算法
  5. 3分钟内看完这,bootstraptable表格控件,受益匪浅!
  6. 面向对象VS面向过程
  7. 2018蓝桥杯省赛---java---A---9(倍数问题)
  8. 2017蓝桥杯省赛---java---B---9(分巧克力)
  9. Rest风格---ElasticSearch
  10. nbiot开发需要掌握什么_学习软件开发需要准备什么?