Java和Golang到底哪個語言更簡單? - sivalabs

banq發表於2021-12-30

一旦您開始使用多種語言,您可能會開始質疑現狀。您可能會以不同的方式看待事物,併為您鍾愛的程式語言帶回一些良好的習慣。我認為“程式碼簡單”是軟體開發的一個被低估的特性,我們需要更加關注程式碼的可讀性和簡單性。
Java 是並且一直是我在整個職業生涯中使用的主要程式語言。如果我想為原型快速構建一些東西,或者如果我需要在緊迫的期限內選擇技術堆疊,那麼 Java 是我的第一選擇。特別是在 Java 8 之後,它的功能變得越來越豐富和強大。
當來自非 Java 社群的人抱怨 Java 冗長而複雜時,我實際上不明白這是什麼意思?
近年來,我有機會在我的官方專案中使用GoDotNet Core。除此之外,我還使用了NodeJS和Python,供我個人使用。
我理解為什麼很多人喜歡NodeJS和Python,因為它們是一種包含電池的東西。對於 Java 中的相同任務,您可能需要包含外部庫,而在 Python/NodeJS 中,標準庫本身以非詳細的方式提供大多數常用功能。如果您熟悉Kotlin,那麼在使用C時您會感到賓至如歸
我對 Go 有過這樣的經歷。我第一次使用它時不太喜歡它,但關於 Go 的簡單讓我印象深刻!

我們來看下面的Java/SpringBoot程式碼。

@Service
@Transactional
@RequiredArgsConstructor
public class CustomerService {
    private final CustomerRepository customerRepository;
    private final AddressRepository addressRepository;

    public void createCustomer(Customer customer) {
        customerRepository.save(customer);
        addressRepository.saveCustomerAddress(customer.getAddress());
    }
}


對於至少使用過一次 SpringBoot 的任何 Java 開發人員,這段程式碼應該不需要任何解釋。但是這裡發生了很多事情。
  • 在為CustomerService被標記為一個Spring bean可以注入到其它Spring Bean
  • 由於 Spring 4.x 不需要在建構函式上新增@Autowired註釋。如果只有一個建構函式,它將自動用於建立 bean。
  • 該類使用@Transactional進行註釋,這意味著當有人呼叫createCustomer()方法時,將啟動並在成功完成後提交資料庫事務。
  • 如果customerRepository.save()或addressRepository.saveCustomerAddress()方法丟擲任何RuntimeException,則事務將自動回滾。
  • 如果CustomerService.createCustomer()是從不同類的另一個事務方法呼叫的,那麼它將在父事務中執行而不是啟動新事務。

雖然這看起來很熟悉且易於閱讀,但在幕後發生了很多事情。
 
讓我們看看下面的 Go 程式碼,它的作用與上面相同:

type CustomerService struct {
   customerRepository CustomerRepository
   addressRepository AddressRepository
}

func (c CustomerService) createCustomer(customer Customer) error {
    // Get a Tx for making transaction requests.
    tx, err := db.BeginTx(ctx, nil)
    if err != nil {
        return err
    }
    // Defer a rollback in case anything fails.
    defer tx.Rollback()
    
    err := customerRepository.save(tx, customer)
    if err != nil {
        return err
    }
    err = addressRepository.saveCustomerAddress(tx, customer.Address)
    if err != nil {
        return err
    }
    // Commit the transaction.
    if err = tx.Commit(); err != nil {
        return err
    }
    return nil
}


嗯,這是我們上面實現的相同功能的典型 Go 實現。假設它做了它打算做的事情,乍一看,這就是我的感覺:
  • 每次第三條語句的錯誤檢查都非常冗長
  • DB 事務處理無處不在,我們可能需要對所有 DB 互動方法重複相同的操作。
  • 業務邏輯和底層技術細節(錯誤/事務處理)糾纏不清

這裡沒有魔法:沒有隱藏的魔法。一個有 20 多年經驗的開發人員可以閱讀和理解這段程式碼,就像一個有 6 個月經驗的畢業生可以閱讀和理解它一樣。
但是,沒有魔法意味著:……只有當你不明白它是如何運作的時候,它才是魔法。
這一點將我引向我想討論的下一點。但首先讓我們不要急於得出哪種語言更好的結論,因為這不是本文的意圖。
 

開發人員在軟體開發過程中面臨的最大挑戰是什麼?
我們都知道,與編寫新程式碼相比,我們花在閱讀現有程式碼上的時間更多。在典型的長期企業應用程式開發中,現有開發人員離開,新開發人員加入專案,最大的挑戰是理解現有程式碼。如果程式碼很簡單,那麼它很容易理解。
但是量化“程式碼簡單性”並不容易。對你來說看起來更簡單的東西,對我來說可能看起來很複雜,反之亦然。所以我們(開發人員和社群)盡最大努力尋找儘可能簡單地編寫程式碼的方法。不同的社群根據上下文、時間、需求等採取不同的方法。
下面是我對 Java 和 Go 如何採用不同方法來實現程式碼簡單性的看法。
 

Java實現簡單程式碼的方式:抽象
我覺得 Java 的標準庫太低階和冗長,無法執行許多常見任務,例如讀取檔案、進行 HTTP 呼叫等。為了避免樣板和冗長,建立了commons-lang、Guava等庫,提供更高階別的抽象遮蔽開發人員的所有低階細節。
最重要的是,許多企業應用程式需要一組通用的功能,如日誌記錄、配置、監控等。因此建立框架來解決這些通用需求,抽象出通用應用程式級樣板程式碼。
隨著時間的推移,抽象之上有抽象之上的抽象……
但是,這些抽象透過處理應用程式級樣板程式碼並讓您專注於業務邏輯來幫助您更快地構建業務應用
這樣做的缺點是:程式設計師如果很好奇,需要“瞭解這些抽象在幕後如何工作,並在框架/庫中發揮作用”。

 
在我看來,這就是事情嚴重出錯的地方

現在,每家公司都希望全棧開發人員能夠編寫前端、後端和一些基礎設施即程式碼。沒有時間正確學習所有這些抽象在幕後是如何工作的。為了滿足交付時間表,開發人員希望儘快完成工作。在那裡新增這 2 個註釋,在此處新增這 4 行配置,如果它正在工作,那麼它就完成了。如果遇到任何錯誤,請搜尋 stackoverflow 中的第一個建議,如果它有效,則完成。工作已經完成,但沒有任何關於它實際工作方式的線索。
隨著時間的推移,這種工作模式讓人害怕說“Java 很複雜”。
 

Go實現簡單的方式:清晰/詳細勝過聰明
Go 社群更喜歡透過“no-magic”來保持程式碼簡單,這意味著沒有註釋、沒有反射、沒有 ORM 等。有很多用於 ORM、Http 路由器等的庫,但 Go 社群更喜歡“如果可能的話堅持標準庫”方法。

Go 社群似乎更喜歡編寫更清晰和冗長的程式碼,而不是建立巧妙的更高抽象。 
最好的部分是使用 Go 的標準庫,您可以在不需要外部依賴的情況下實現大部分應用程式需求,當然還有更多的程式碼行。
冗長的好處是“任何對 Go 有點熟悉的人都可以輕鬆閱讀任何慣用的 Go 程式碼並理解它”!
如果你現在是 Go 的崇拜者,你可能會因為一遍又一遍地閱讀“冗長”而生氣,並問“冗長”是什麼意思?
上面程式碼中幾乎每三行實現一次錯誤檢查,我們檢查Map是否包含鍵等的方式在我看來都很冗長。
基於我對 Go 的有限經驗,我非常喜歡它,因為它的“無聊”性質。為了學習 Go,我在 GitHub 上閱讀了許多文章和開原始碼庫,沒有太多新東西要學習。
在看到幾個 Go 程式碼儲存庫後,認為:從企業長期應用程式開發的角度來看,這是一件了不起的事情。學習的魔力更少,新開發人員更容易入職。
 

我們如何讓 Java 變得“更簡單”?
Java 是大型企業的首選是有原因的。開發速度快,上市速度快。我可以自信地說,您可以在幾個小時內使用 SpringBoot/Quarkus/Micronaut 建立生產級 Java 應用程式,而不是幾周或幾個月。由於這些框架已經提供了包含電池的應用程式框架,您需要做的就是編寫業務邏輯。
如果我能從 Go 中汲取一些想法並將它們帶到 Java,特別是 SpringBoot,那麼這些將是:

  • 除非是簡單的 CRUD 應用程式,否則不要用ORM。我更願意花費編寫更多程式碼的一次性成本而不是重複除錯成本。我更喜歡JOOQ 而不是JPA。
  • 我知道向後相容性是 Java/SpringBoot 成功的關鍵原因之一。但我喜歡從 SpringBoot 中剝離一些東西
    • 支援 XML 配置,我沒有看到任何使用 XML 配置的綠地專案。XML 支援可以作為單獨的模組提取。
    • 無需從 14 個不同來源載入配置屬性
    • 使用和除錯 AOP 的一些更簡單的方法(如果您曾經嘗試過除錯 AOP 程式碼,那麼您就知道我在說什麼)
    • Quarkus喜歡實時重新載入和連續測試
  • 我們真的需要“com.mycompany.myproject.mymodule”的私有業務應用程式封裝結構嗎?對於開源庫是的,但是對於商業應用程式??

 

總結
如果您是從未嘗試過 Go 的 Java 開發人員,我強烈建議您看看 Go。你可能完全喜歡也可能不喜歡 Go,但你會愛上的東西卻很少。
說了這麼多,“Java 是並將永遠是我最喜歡的語言”,從其他語言中學習東西的感覺很好。

 

相關文章