为什么声明性编码使您成为更好的程序员
在許多情況下,具有功能組成的聲明式解決方案提供了優于傳統命令式代碼的優越代碼度量。 閱讀本文并了解如何使用具有功能組成的聲明性代碼成為更好的程序員。
在本文中,我們將仔細研究三個問題示例,并研究用于解決這些問題的兩種不同技術(命令式和聲明式)。
本文中的所有源代碼都是開源的,可以在以下位置獲得
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 。 以下接口定義了問題:
當務之急
以下解決方案使用命令式技術實現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的代碼指標(通常越低越好):
| 勢在必行 | 12 | 5 | 2 | 1個 |
| 功能性 | 11 | 2 | 2 | 0 |
這是它在圖形中的外觀(通常越低越好):
并行匯總值
該問題示例的對象是將“ Person對象分組到不同的存儲桶中,其中每個存儲桶構成一個人的出生年份和一個工作的國家/地區的唯一組合。對于每個組,應計算平均工資。 聚合應使用公共ForkJoin池并行計算。
(不變的) Person類是這樣的:
勢在必行我們還定義了另一個稱為YearCountry不變類,該類將用作分組鍵:
勢在必行定義了這兩個類之后,我們現在可以通過以下接口定義此問題示例:
勢在必行當務之急
對GroupingBy示例問題實施命令式解決方案并非難事。 這是解決問題的一種解決方案:
勢在必行聲明式解決方案
這是一個使用聲明性構造實現GroupingBy的解決方案:
勢在必行 在上面的代碼中,我使用了一些靜態導入
Collectors類(例如Collectors::groupingBy )。 這不會影響代碼指標。
分析
SonarQube提供以下分析:
下表顯示了GroupingBy的代碼指標(越低越好):
| 勢在必行 | 52 | 27 | 11 | 4 |
| 功能性 | 17 | 1個 | 1個 | 0 |
相應的圖形如下所示(通常越低越好):
實施REST接口
在這個示例性問題中,我們將為Person對象提供分頁服務。 出現在頁面上的人員必須滿足某些(任意)條件,并且必須按照給定的順序進行排序。 該頁面應作為不可修改的“個人”對象列表返回。
這是捕獲問題的接口:
勢在必行頁面的大小在一個單獨的實用程序類RestUtil :
勢在必行當務之急
這是Rest接口的命令性實現:
勢在必行聲明式解決方案
下列類以聲明的方式實現Rest接口:
勢在必行分析
SonarQube提供以下分析:
下表顯示了Rest的代碼指標(通常越低越好):
| 勢在必行 | 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
總結
以上是生活随笔為你收集整理的为什么声明性编码使您成为更好的程序员的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何在Flutter(REST API)
- 下一篇: linux命令删除文件夹(linux 命