自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

對于程序員來說,怎樣才算是在寫有“技術(shù)含量”的代碼?

開發(fā) 新聞
在追求寫“有技術(shù)含量”的代碼之前,必須要具備的一個能力。而且是比寫出“有技術(shù)含量”的代碼更加重要的一個基礎(chǔ)能力。

你好呀,我是歪歪。

我最近其實在思考一個問題:

對于程序員來說,怎樣才算是在寫有“技術(shù)含量”的代碼?

為什么會想起思考這個看起來就很厲(裝)害(逼)的問題呢?

因為這就是知乎上的一個問題:

https://www.zhihu.com/question/37093538

圖片

第一次看到這個問題的時候,我很快的就劃過去了,完全就沒有關(guān)注這個問題。但是就是看了那么一眼,這個問題就偶爾不經(jīng)意間在腦海中浮現(xiàn)出來。

然后隔了一段時間,中午刷知乎的時候這個問題又冒出來了。

好巧不巧,也是那天中午,我看到了這樣的一個面試題:

圖片

看到這個面試題的第一眼,我就想起了 Dubbo 服務(wù)中的一個預(yù)熱功能。

在結(jié)合知乎這個問題,我當(dāng)時就覺得:Dubbo 服務(wù)的預(yù)熱源碼在我看來就是一個“有技術(shù)含量”的代碼呀。

這一塊功能編碼確實一點也不復(fù)雜,主要是能體現(xiàn)出編碼的人對于 JVM 和 RPC 方面的“內(nèi)功”,能夠意識到,由于 JVM 的編譯特點,再加上 Dubbo 在架構(gòu)中充當(dāng)著 RPC 框架的角色,所以為了服務(wù)最大程度上的穩(wěn)定,可以在編碼的層面做一定的服務(wù)預(yù)熱。

但是寫完相關(guān)回答之后,從評論區(qū)來看,基本上是清一色的吐槽,說我舉得這個例子和問題相悖。

比如我截取點贊最高的兩個評論:

圖片

看完這些吐槽之后,我覺得這些吐槽是有道理的,我的例子舉得確實不好,非常的片面。

開始我還不服氣,但是現(xiàn)在我也是真心的覺得“別人說的對”。

為了更好的引出這個話題,我先搬運并擴充一下我當(dāng)時的回答吧。

順便也算是回答一下剛剛說的那個面試題。

服務(wù)預(yù)熱

下面這個方法,只有兩行,但是這就是 Dubbo 服務(wù)預(yù)熱功能的核心代碼:

org.apache.dubbo.rpc.cluster.loadbalance.AbstractLoadBalance#calculateWarmupWeight

圖片

看一下這個方法在框架里面調(diào)用的地方:

圖片

當(dāng)我們不指定參數(shù)的情況下,入?yún)?warmup 和 weight 是有默認(rèn)值的:

圖片

也就是在用默認(rèn)參數(shù)的情況下,上面的方法可以簡化為這樣:

static int calculateWarmupWeight(int uptime) {
//int ww = (int) ( uptime / ((float) 10 * 60 * 1000 / 100));
int ww = (int) ( uptime / 6000 );
return ww < 1 ? 1 : (Math.min(ww, 100));
}

它的入?yún)?uptime 代表服務(wù)啟動時間,單位是毫秒。返回參數(shù)代表當(dāng)前服務(wù)的權(quán)重。

基于這個方法,我先給你搞個圖。

下面這個圖,x 軸是啟動時間,單位是秒,y 軸是對應(yīng)的權(quán)重:

圖片

從圖上可以看出,從服務(wù)啟動開始,每隔 6 秒權(quán)重就會加一,直到 600 秒,即 10 分鐘之后,權(quán)重變?yōu)?100。

比如當(dāng) uptime 為 60 秒時,該方法的返回值為 10。

當(dāng) uptime 為 66 秒時,該方法的返回值為 11。

當(dāng) uptime 為 120 秒時,該方法的返回值為 20。

以此類推...

600 秒,也就是十分鐘以及超過十分鐘之后,權(quán)重均為 100,代表預(yù)熱完成。

那么這個權(quán)重是干啥用的呢?

這個就得結(jié)合著負載均衡來說了。

Dubbo 提供了如下的五種負載均衡策略:

  • Random LoadBalance :「加權(quán)隨機」策略
  • RoundRobin LoadBalance:「加權(quán)輪詢」策略
  • LeastActive LoadBalance:「最少活躍調(diào)用數(shù)」策略
  • ShortestResponse LoadBalance:「最短響應(yīng)時間」策略
  • ConsistentHash LoadBalance:「一致性 Hash」 策略

除了一致性哈希策略外,其他的四個策略都得用到權(quán)重這個參數(shù):

圖片

權(quán)重,就是用來決定這次請求發(fā)送給哪個服務(wù)的一個關(guān)鍵因素。

我給你畫個示意圖:

圖片

A、B、C 三臺服務(wù),A,B 的權(quán)重都是 100,C 服務(wù)剛剛啟動。

作為一個剛剛啟動的服務(wù),是不適合接受突發(fā)流量的,以為運行在服務(wù)器上的代碼還沒有經(jīng)過充分的編譯,主鏈接上的代碼可能還沒有進入編譯器的 C2 階段。

所以按理來說 C 服務(wù)需要一個服務(wù)預(yù)熱的過程,也就是剛剛啟動的前 10 分鐘,應(yīng)該有逐步接受越來越多的請求這樣的一個過程。

比如最簡單的加權(quán)隨機輪詢的負載均衡策略中,關(guān)鍵代碼是這樣的:

org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance#doSelect

圖片

看不明白沒關(guān)系,我再給你畫個圖。

在 C 服務(wù)啟動的第 1 分鐘,它的權(quán)重是 10:

圖片

所以代碼中的 totalWeight=210,因此下面這行代碼就是隨機生成 210 之內(nèi)的一個數(shù)字:

int offset = ThreadLocalRandom.current().nextInt(totalWeight);

在示意圖中有三個服務(wù)器,所以 for 循環(huán)中的 lenght=3。

weights[] 這個數(shù)組是個啥玩意呢?

看一眼代碼:

圖片

每次循環(huán)的時候把每個服務(wù)器的權(quán)重匯總起來,放到 weights[] 里面。

在上面的例子中也就是這樣的:

  • weights[0]= 100(A服務(wù)器的權(quán)重)
  • weights[1]= 100(A服務(wù)器的權(quán)重)+100(B服務(wù)器的權(quán)重)=200
  • weights[2]= 100(A服務(wù)器的權(quán)重)+100(B服務(wù)器的權(quán)重)+10(C服務(wù)器的權(quán)重)=210

當(dāng)隨機數(shù) offset 在 0-100 之間,A 服務(wù)器處理本次請求。在 100-200 之間 B 服務(wù)器處理本次請求。在 200-210 之間 C 服務(wù)器處理本次請求:

圖片

也就是說:C 服務(wù)器有一定的概率被選上,來處理這一次請求,但是概率不大。

怎么概率才能大呢?

權(quán)重要大。

權(quán)重怎么才大呢?

啟動時間長了,權(quán)重也隨之增大了。

比如服務(wù)啟動 8 分鐘之后,就變成這樣了,C 服務(wù)器被選中的概率就大了很多:

圖片

最后到 10 分鐘之后,三臺服務(wù)器的權(quán)重一致,承擔(dān)的流量也就幾乎一致了。

C 服務(wù)器承擔(dān)的請求隨著服務(wù)啟動時間越來越多,直到 10 分鐘后到達一個峰值,這就算是經(jīng)歷了一個預(yù)熱的過程。

前面介紹的就是一個預(yù)熱的手段,而類似于這樣的預(yù)熱思想你在其他的一些網(wǎng)關(guān)類的開源項目中也能找到類似的源碼。

但是預(yù)熱不只是有這樣的一個實現(xiàn)方式。

比如阿里基于 OpenJDK 搞了一個 Alibaba Dragonwell,其實也就是一個 JDK。

https://github.com/alibaba/dragonwell8

其中之一的特性就是預(yù)熱:

圖片

除了預(yù)熱這個點之外,我還在知乎的回答中提到了最少活躍數(shù)負載均衡策略的實現(xiàn) LeastActiveLoadBalance.java:

圖片

從初始化提交之后,一共就沒修改過幾次。

你也可以對比一下,初始版本和當(dāng)前最新的版本,核心算法、核心邏輯基本沒有發(fā)生變化:

圖片

除了這個策略之外,其他的幾個策略也是差不多類似的“穩(wěn)定”。

從評論說起

我在知乎回答這個問題的時候,沒有上面這一小節(jié)寫的那么多,但是核心內(nèi)容大概就是上面這些。

在回答說提到預(yù)熱,我是想表達看似不起眼的兩行代碼,背后還是蘊含了非常多的深層次的原因,我覺得這是有“技術(shù)含量”的。

而提到負載均衡策略的實現(xiàn),多年來都沒有怎么變化,我是想表達這些重要的、底層的、基礎(chǔ)的代碼,寫好之后,長年沒動,說明最開始寫出來的代碼是非常穩(wěn)定的。能寫出這樣穩(wěn)定的代碼,我覺得這也是有“技術(shù)含量”的。

接著帶你看看評論區(qū):

圖片

評論幾乎是清一色的不認(rèn)可這個回答。但是我前面說了,在回答這個問題的時候,確實覺得我的回答是比較貼近主題的。

但是看了評論之后我想明白了,為什么這是一個不好的答案,正如評論區(qū)說的:

例子舉得不行,只不過是因為要解決的問題一直沒有發(fā)生改變,所以解決方案也就相對穩(wěn)定。

首先這樣的代碼本來就和絕大部分程序員實際工作中寫的代碼差距過大,框架的源碼值得學(xué)習(xí),但是在實際開發(fā)中的借鑒意義不大。

而且評論區(qū)也提到了,絕大多數(shù)程序員根本就沒有機會去寫這樣的比較考驗“技術(shù)能力”的代碼。

這也確實是事實,少部分中間件的開發(fā)和絕大部分業(yè)務(wù)邏輯的開發(fā),是兩個思維模式完全不一樣的程序員群體。

然后我看了一下這個話題下的高贊回答:

圖片

其實高贊回答就這一句話:

一個優(yōu)秀的程序員,在接到一個要編寫“毀滅地球”的任務(wù)的時候,他不會簡單的寫一個destroyEarth()的方法;而是會寫一個destroyPlanet()的方法,將earth作為一個參數(shù)傳進去。

這才是比較貼近我們實際工作的一個例子。

就著這個例子,我換個常規(guī)一點的需求來說,比如讓你接入一個微信支付的需求:

你可能會這樣去定義一個類:

public class WechatPayService {

public void wechatPayment(){
//微信支付相關(guān)邏輯
}
}

當(dāng)要使用的時候,就把 WechatPayService 注入到需要使用的地方,沒有任何毛病。

但是隨著而來的一個需求是讓你接入支付寶支付。

你當(dāng)然是自然而然的搞了一個類似的類:

public class AliPayService {

public void aliPayment(){
//支付寶支付相關(guān)邏輯
}
}

但是你寫著寫著發(fā)現(xiàn):誒,怎么回事,感覺支付寶的這套邏輯和微信的有很多相似之處啊,開發(fā)的關(guān)鍵步驟感覺都一模一樣?

于是你定義了一個接口,使用策略模式來專門干“支付”相關(guān)需求:

public interface IPayService {

/**
* 支付抽象接口
*/
public void pay();
}

在我看來,這是一個非常常規(guī)的開發(fā)方案,我甚至在拿到“微信支付”這個需求的時候,我就輕車熟路的知道應(yīng)該使用策略模式來做這個需求,為了方便以后的開發(fā)。

但是,我這個“輕車熟路”也是有一個熟悉的過程的,我也不是一開始,一入行,一工作就知道應(yīng)該這樣去寫的。

我是在工作之后,看了大量的實際項目里面的代碼,看到項目在用,覺得這樣很實用,項目結(jié)構(gòu)也很清晰,才在其它的類似的需求中,刻意的模仿學(xué)習(xí)、理解、運用、打磨,慢慢的融入到了自己的編碼習(xí)慣中去,由于太過熟悉,我漸漸的認(rèn)為這是沒有技術(shù)含量的東西。

直到后來,有一次我?guī)е粋€實習(xí)生做一個項目,項目中有一個排行榜的功能,排行榜需要支持各個維度,前端請求的時候會告訴我當(dāng)前是需要展示哪個排行榜。

在需求分析、系統(tǒng)設(shè)計以及代碼落地階段我都自然而然的想到了前面說到的策略模式。

后來實習(xí)的同學(xué)看到了這一段邏輯,給我說:這個需求的實現(xiàn)方式真好。如果讓我來寫,我絕對想不出這樣的落地方案。

但是我覺得這就是個常規(guī)解決方案而已。

我舉這個例子是想表達的意思就是對于“技術(shù)含量”這個東西,每個人,每個階段的理解是截然不同的。

與我而言,站在我現(xiàn)在正在寫這篇文章的時間節(jié)點上,我覺得有技術(shù)含量的代碼,就是別人看到后愿意使用,愿意模仿,愿意告訴后面來的人:這個東西真不錯,你也可以用一用。

它可以小到一個項目里面的只有寥寥幾行的方法類,也可以大到一套行業(yè)內(nèi)問題的完整的技術(shù)解決方案。

除了這個例子外,我還想舉我剛剛參加工作不久,遇到過的另外一個例子。

需求說來也很簡單,就是針對一個表的增刪改查操作,也就是我們常常吐槽的沒有技術(shù)含量的 crud。

但是,我當(dāng)時看到別人提交的代碼時我都震驚了。

比如一個新增操作,所有的邏輯都在一個 controller 里面,沒有所謂的 service 層、dao 層,一把梭直接把 mapper 注入到了 controller 里面,在一個方法里面從數(shù)據(jù)校驗到數(shù)據(jù)庫交互全部包圓了。

功能能用嗎?

能用。

但是這樣代碼是有“技術(shù)含量”的代碼嗎?

我覺得可以說是毫無技術(shù)含量了,用現(xiàn)在的流行語來說,我甚至覺得這是程序員在“擺爛”。

我要基于對于這一段代碼繼續(xù)開發(fā)新功能,我能做什么呢?

我無能為力,原來的代碼實在不想去動。

我只能保證在這堆“屎山”上,我新寫出來的代碼是干凈的、清晰的,不繼續(xù)往里面扔垃圾。

后來我讀了一本書,叫做《代碼整潔之道》,里面有一個規(guī)則叫做“童子軍軍規(guī)”。

軍規(guī)中有一句話是這樣的:讓營地比你來時更干凈。

類比到代碼上其實就是一件很小的事情,比如只是改好一個變量名、拆分一個有點過長的函數(shù)、消除一點點重復(fù)代碼,清理一個嵌套 if 語句...

這是讓項目代碼隨著時間流逝而越變越好的最簡單的做法,持續(xù)改進也是專業(yè)性的內(nèi)在組成部分。

我覺得我對于這一點“規(guī)則”落實的還是挺好的,看到一些不是我寫的,但是我覺得可以有更好的寫法時,而且改動起來非常簡單,不影響核心功能的時候,我會主動去改一下。

我能保證的是,這段代碼在經(jīng)過我之后,我沒有讓它更加混亂。

把一段混亂的代碼,拆分的清晰起來,再后來的人愿意按照你的結(jié)構(gòu)繼續(xù)往下寫,或者繼續(xù)改進。

你說這是在寫“有技術(shù)含量”的代碼嗎?

我覺得不是。

但是,我覺得這應(yīng)該是在追求寫“有技術(shù)含量”的代碼之前,必須要具備的一個能力。而且是比寫出“有技術(shù)含量”的代碼更加重要的一個基礎(chǔ)能力。

延伸

以上就是我個人的一點觀點,但是我還想延伸出一些別的東西。

比如在寫文章之前,我也在思否網(wǎng)站上提出了這個問題:

https://segmentfault.com/q/1010000042111980

圖片

大家見仁見智,從各個角度給出了不同的回答。

這也再次印證了前面我說的觀點:

對于“技術(shù)含量”這個東西,每個人,每個階段的理解是截然不同的。

我把大家給我的回復(fù)貼過來,希望能對你也有幫助:

圖片

圖片

圖片

再比如我最近在知乎上看到了這樣的一個視頻:

https://www.zhihu.com/zvideo/1542577108190068737?page=ogv

圖片

里面的主人公黃玄,說了這樣的一段話:

圖片

這已經(jīng)是另外一個維度的程序員,對于“什么是有技術(shù)含量的代碼”的另外一個維度的解答了。

我遠遠達不到這個高度,但是我喜歡這個回答:

不斷的傳承下去,成為下一代軟件,或者說下一代人類文明的基石。我覺得能夠去參與這樣的東西,對我來說,可能是程序員的一種浪漫。

所以你呢,對于這個問題,你會給出什么樣的答案呢?

好了,那本文的技術(shù)部分就到這里啦。

責(zé)任編輯:張燕妮 來源: why技術(shù)
相關(guān)推薦

2017-12-07 16:13:18

程序員編程代碼

2009-12-24 15:52:09

Fedora Core

2020-08-23 08:58:57

依賴注入代碼程序員

2015-05-19 14:41:22

2009-12-03 16:50:58

Visual Basi

2012-05-25 10:54:24

程序員

2015-07-28 10:47:53

天旦云計算

2015-05-18 10:59:38

程序員選擇比努力更重要

2019-11-07 22:00:22

程序員代碼規(guī)范

2014-07-30 13:44:57

2022-08-28 20:07:17

Docker后端

2019-04-10 16:17:02

程序員結(jié)構(gòu)源代碼

2017-11-10 12:43:43

整潔代碼開發(fā)程序員

2014-12-31 10:53:34

2009-02-17 10:12:10

ASP面試技術(shù)

2009-02-23 13:05:32

程序員學(xué)習(xí)方法

2012-12-03 10:22:24

程序員

2020-12-11 07:10:03

程序員

2015-06-03 11:15:20

程序員真相

2015-06-24 09:58:11

點贊
收藏

51CTO技術(shù)棧公眾號