成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

強(qiáng)靜態(tài)類型,真的無敵

譯文 精選
開發(fā) 前端
我可以在許多話題上看到雙方的爭論,比如vs.,制表符vs.空格,甚至更具爭議性的主題。盡管在這種情況下,與收益相比,成本是如此之低,以至于我不明白為什么有人會選擇不使用類型。我不知道自己忽略了什么,我只知道,強(qiáng)類型是我愿意死在上面的一座山。

作者丨Tom Hacohen

編譯丨千山

我寫軟件已經(jīng)有20多年了,隨著時間的推移,我越來越確信強(qiáng)靜態(tài)類型不僅是一個好主意,而且?guī)缀蹩偸钦_的選擇。

非類型化語言(或語言變體)肯定有用途,例如,當(dāng)使用REPL時,或者在已經(jīng)無可救藥的無類型環(huán)境(例如shell)中使用一次性腳本時,它們會更好。然而,在幾乎所有其他情況下,強(qiáng)類型都是首選。

不使用類型是有好處的,比如更快的開發(fā)速度,但與所有的好處相比,它們就顯得微不足道了。對此,我要說:

編寫沒有類型的軟件可以讓你全速前進(jìn)——全速沖向懸崖。

關(guān)于強(qiáng)靜態(tài)類型的問題很簡單:你是愿意多做一點工作,在編譯時檢查不變量(或非編譯語言的類型檢查時間),還是愿意少做一點工作,在運行時強(qiáng)制執(zhí)行它們,或者更糟糕的是,即使在運行時也不強(qiáng)制執(zhí)行(JavaScript,我在看著你…)。

在運行時出錯是一個糟糕的想法。首先,這意味著在開發(fā)過程中你不會總是抓住它們。其次,當(dāng)你抓住他們的時候,它會以面向客戶的方式發(fā)生。是的,測試有幫助,但是考慮到無限的可能性,為每一個可能的錯誤類型函數(shù)參數(shù)編寫測試是不可能的。即使可以,擁有類型也比測試錯誤類型容易得多。

1、類型導(dǎo)致更少的錯誤

類型還為代碼提供注釋,使人類和機(jī)器都受益。擁有類型是一種更嚴(yán)格地定義不同代碼段之間協(xié)定的方法。

請考慮以下四個示例。它們都做完全相同的事情,只是契約定義級別不同。

// Params: Name (a string) and age (a number).
function birthdayGreeting1(...params) {
    return `${params[0]} is ${params[1]}!`;
}

// Params: Name (a string) and age (a number).
function birthdayGreeting2(name, age) {
    return `${name} is ${age}!`;
}

function birthdayGreeting3(name: string, age: number): string {
    return `${name} is ${age}!`;
}

第一個甚至沒有定義參數(shù)的數(shù)量,因此如果不閱讀文檔,很難知道它的作用。我相信大多數(shù)人都會同意第一個是令人討厭的,不會寫這樣的代碼。雖然它的思想與類型非常相似,但它是關(guān)于定義調(diào)用者和被調(diào)用者之間的契約。

至于第二個和第三個,由于類型的原因,第三個將需要更少的文檔。代碼更簡單,但不可否認(rèn),優(yōu)點相當(dāng)有限。好吧,直到你真正更改這個函數(shù)前......

在第二個和第三個函數(shù)中,作者假設(shè)年齡是一個數(shù)字。因此,更改代碼絕對沒問題,如下所示:

// Params: Name (a string) and age (a number).
function birthdayGreeting2(name, age) {
    return `${name} will turn ${age + 1} next year!`;
}

function birthdayGreeting3(name: string, age: number): string {
    return `${name} will turn ${age + 1} next year!`;
}

問題是使用此代碼的某些位置接受從HTML輸入(因此始終是字符串)收集的用戶輸入。這將導(dǎo)致:

> birthdayGreeting2("John", "20")
"John will turn 201 next year!"

雖然類型化版本將無法正確編譯,因為此函數(shù)將年齡除外,否則年齡是數(shù)字,而不是字符串。

在調(diào)用方和被調(diào)用方之間建立協(xié)定對于代碼庫非常重要,這樣調(diào)用方就可以知道被調(diào)用方何時更改。這對于開源庫尤其重要,因為調(diào)用方和被調(diào)用方不是由同一組人編寫的。沒有這個合同,就不可能知道事情在發(fā)生時是如何變化的。

2、類型帶來更好的開發(fā)體驗

IDE和其他開發(fā)工具也可以使用類型來極大地改善開發(fā)體驗。如果你的任何期望是錯誤的,你將在編寫代碼時得到通知。這大大降低了認(rèn)知負(fù)荷。你不再需要記住上下文中所有變量和函數(shù)的類型。編譯器將與你同在,并在出現(xiàn)問題時告訴你。

這也帶來了一個非常好的額外好處:更容易重構(gòu)。你可以相信編譯器會讓你知道你所做的更改(例如上面示例中的更改)是否會破壞代碼中其他地方所做的假設(shè)。

類型還可以使新工程師更容易加入代碼庫或庫:

  • 他們可以遵循類型定義來了解事物的使用位置。
  • 修改東西要容易得多,因為更改會觸發(fā)編譯錯誤。

讓我們考慮對上述代碼進(jìn)行以下更改:

class Person {
  name: string;
  age: number;
}

function birthdayGreeting2(person) {
    return `${person.name} will turn ${person.age + 1} next year!`;
}

function birthdayGreeting3(person: Person): string {
    return `${person.name} will turn ${person.age + 1} next year!`;
}

function main() {
  const person: Person = { name: "Hello", age: 12 };

  birthdayGreeting2(person);

  birthdayGreeting3(person);
}

很容易查看(或使用IDE查找)所有使用過的位置。你可以看到它被啟動,你可以看到它被使用。然而,為了知道它的用途,你需要閱讀整個代碼庫。

這樣做的另一方面是,在看的時候,很難知道它期望a作為參數(shù)。其中一些問題可以通過詳盡的文檔來解決,但是:(1)如果使用類型可以實現(xiàn)更多的功能,為什么還要費心呢?(2)文檔過時,這里的代碼是document。

這與你不編寫代碼的方式非常相似:

// a is a person
function birthdayGreeting2(a) {
    b = a.name;
    c = a.age;
    return `${b} will turn ${c + 1} next year!`;
}

你可能希望使用有用的變量名。類型也是一樣的,它只是steriods上的變量名。

3、我們對類型系統(tǒng)中的所有內(nèi)容進(jìn)行編碼

在Svix,我們喜歡類型。事實上,我們嘗試在類型系統(tǒng)中對盡可能多的信息進(jìn)行編碼,以便在編譯時捕獲所有可以在編譯時捕獲的錯誤;同時也要壓縮開發(fā)者體驗改進(jìn)的額外里程。

例如,Redis是一個基于字符串的協(xié)議,沒有固有的類型。我們使用Redis進(jìn)行緩存(以及其他功能)。問題是,我們所有的優(yōu)秀的類型優(yōu)勢將在Redis層丟失,并且可能發(fā)生bug。

考慮下面這段代碼:

pub struct Person {
    pub id: String,
    pub name: String,
    pub age: u16,
}

pub struct Pet {
    pub id: String,
    pub owner: String,
}


let id = "p123";
let person = Person::new("John", 20);
cache.set(format!("person-{id}"), person);
// ...
let pet: Pet = cache.get(format!("preson-{id}"));

代碼片段中有幾個bug:

  • 第二個鍵名稱有個拼寫錯誤。
  • 我們正在嘗試將一個人裝入寵物類型。

為了避免這樣的問題,我們在Svix做了兩件事。首先,我們要求鍵是某種類型的(不是泛型字符串),要創(chuàng)建這種類型,需要調(diào)用一個特定的函數(shù)。我們做的第二件事,是將鍵與值強(qiáng)制配對。

所以上面的例子看起來像這樣:

pub struct PersonCacheKey(String);

impl PersonCacheKey {
    fn new(id: &str) -> Self { ... }
}

pub struct Person {
    pub id: String,
    pub name: String,
    pub age: u16,
}

pub struct PetCacheKey;

pub struct Pet {
    pub id: String,
    pub owner: String,
}


let id = "p123";
let person = Person::new(id, "John", 20);
cache.set(PersonCacheKey::new(id), person);
// ...
// Compilation will fail on the next line
let pet: Pet = cache.get(PersonCacheKey::new(id));

這已經(jīng)好多了,并且不可能出現(xiàn)前面提到的任何錯誤。雖然我們可以做得更好!

請考慮以下函數(shù):

pub fn do_something(id: String) {
    let person: Person = cache.get(PersonCacheKey::new(id));
    // ...
}

它有幾個問題。首先是不太清楚id應(yīng)該用來做什么。是一個人嗎?一個寵物嗎?很容易意外地用錯誤的名稱調(diào)用它,就像下面的例子一樣

let pet = ...;
do_something(pet.id); // <-- should be pet.owner!

第二,我們正在失去可發(fā)現(xiàn)性。很難知道寵物與人有關(guān)系。

因此,在Svix,我們?yōu)槊總€類型都有一個特殊的類型,以確保沒有錯誤。調(diào)整后的代碼如下所示:

pub struct PersonId(String);
pub struct PetId(String);

pub struct Person {
    pub id: PersonId,
    pub name: String,
    pub age: u16,
}

pub struct Pet {
    pub id: PetId,
    pub owner: PersonId,
}

這確實比我們之前的例子要好得多。

4、那么為什么不是每個人都喜歡類型呢?

反對類型一方論證的主要依據(jù)是:

  • 開發(fā)速度
  • 學(xué)習(xí)曲線和類型復(fù)雜性
  • 所需的工作量和樣板

首先,我認(rèn)為即使上述所有情況都是真的,上面提到的優(yōu)勢也值得麻煩。

首先是開發(fā)速度。沒有類型的原型設(shè)計肯定要快得多。你可以注釋掉代碼片段,并且不會讓編譯器向你抱怨。你可以為某些字段設(shè)置錯誤的值,直到你準(zhǔn)備好找出正確的字段等。

雖然就像我上面說的:“編寫沒有類型的軟件可以讓你全速前進(jìn)。全速向懸崖走去。”問題在于,這只是激進(jìn)且不必要的技術(shù)債務(wù)。當(dāng)你需要調(diào)試代碼無法正常工作的原因時(無論在本地、測試套件或生產(chǎn)環(huán)境中),你都需要多次支付這筆費用。

至于學(xué)習(xí)曲線:是的,學(xué)習(xí)更多的東西需要時間。不過我得說,大多數(shù)人不需要成為類型專家。他們可以使用非常簡單的類型表達(dá)式過日子,并詢問他們是否曾經(jīng)遇到瓶頸。然而,如果你讓事情保持簡單,你可能很少會碰到一個。

此外,人們已經(jīng)被要求學(xué)習(xí)如何編碼,學(xué)習(xí)框架(React,Axum等),以及許多其他東西。我認(rèn)為學(xué)習(xí)負(fù)擔(dān)并不像人們想象的那么重。

最后,但并非最不重要的是,關(guān)于學(xué)習(xí)曲線:我堅信,不必了解類型而減少學(xué)習(xí)曲線的好處遠(yuǎn)遠(yuǎn)小于在特定代碼庫上使用類型腳本的好處。特別是因為學(xué)習(xí)類型是一次性的成本。

最后一點是關(guān)于在代碼庫中使用類型所需的工作量和樣板。我堅信,比起不寫類型所需要的工作量,這種工作量實際上要少得多。

不使用類型需要大量的文檔和測試,才能達(dá)到基本的健康水平。文檔可能會過時,測試也會過時;無論哪種方式,它們都比添加正確的類型需要更多的努力。閱讀帶有類型的代碼也更容易,因為你可以內(nèi)聯(lián)獲取類型,而不是在函數(shù)文檔中獲取類型,在函數(shù)文檔中,它的格式不一致,并且增加了很多干擾。

是的,在不支持推理的語言中,類型可能是一種痛苦,例如Java可能很乏味:

Person person1 = newPerson();
Person person2 = newPerson();
Person child = makeChild(person1, person2);

而其他具有推理功能的語言(如 Rust)則要好得多:

let person1 = new_person();
let person2 = new_person();
let child = make_child(person1, person2);

因此,擁有合適的工具肯定會有所幫助。說到工具,為了獲得類型的好處,你可能需要使用支持語言感知的現(xiàn)代代碼完成的代碼編輯器(或 IDE)。

5、結(jié)語

我可以在許多話題上看到雙方的爭論,比如vs.,制表符vs.空格,甚至更具爭議性的主題。盡管在這種情況下,與收益相比,成本是如此之低,以至于我不明白為什么有人會選擇不使用類型。我不知道自己忽略了什么,我只知道,強(qiáng)類型是我愿意死在上面的一座山。

參考鏈接:https://www.svix.com/blog/strong-typing-hill-to-die-on/

責(zé)任編輯:武曉燕 來源: 51CTO技術(shù)棧
相關(guān)推薦

2009-09-08 14:56:55

強(qiáng)類型DataContLinq to SQL

2010-09-26 09:01:18

SQL強(qiáng)類型查詢

2019-10-08 11:09:33

網(wǎng)絡(luò)5GWi-Fi

2009-08-04 17:52:25

ActorLite強(qiáng)類型

2011-04-13 08:49:33

DataSet強(qiáng)類型化

2021-04-21 07:53:14

云原生PulsarGo

2020-08-31 19:17:24

Python強(qiáng)類型語言弱類型語言

2017-11-20 10:21:17

量子點顯示器OLED

2024-07-09 08:00:48

C#var?關(guān)鍵字

2012-07-02 10:43:49

JVMGroovyJava

2023-10-29 16:18:26

Go接口

2021-07-21 09:15:57

Python工具編程語言

2009-06-11 17:54:00

Visual StudDataSet

2019-06-04 09:30:30

PythonSQL數(shù)據(jù)庫

2014-04-01 15:25:18

2025-04-09 11:00:00

NAT網(wǎng)絡(luò)網(wǎng)絡(luò)地址轉(zhuǎn)換

2011-06-07 18:34:13

SEO

2023-10-23 06:47:37

Redis磁盤存儲

2015-04-16 16:04:32

云計算微軟云Azure
點贊
收藏

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

主站蜘蛛池模板: 日韩成人| 午夜天堂精品久久久久 | 国产精品入口 | 亚洲一区二区免费电影 | 国产99视频精品免视看9 | 国产精品国产精品国产专区不卡 | 成人免费观看男女羞羞视频 | www亚洲免费国内精品 | 一级毛片成人免费看a | 国产精品片 | 青青草亚洲 | 国产高清一二三区 | 无毛av| 久久久久一区二区三区 | 精品一区久久 | 欧美国产一区二区 | 日韩一区二区av | 欧美电影一区 | 国产精品不卡一区二区三区 | 欧美日韩国产一区二区三区 | 欧美激情欧美激情在线五月 | 国产在线精品一区二区三区 | 91精品国产综合久久久久久蜜臀 | 久久9视频 | 91麻豆精品国产91久久久久久 | 综合久 | 久久中文字幕一区 | 久久久国产精品一区 | 一区二区三区免费网站 | 欧美国产精品一区二区三区 | 日日夜夜精品免费视频 | 九九免费观看视频 | 小h片免费观看久久久久 | 欧美一区二区激情三区 | 亚洲自拍偷拍视频 | 久久久久久久久久久久久9999 | 一级二级三级在线观看 | 亚洲精品视频在线看 | 人人做人人澡人人爽欧美 | 国产精品久久二区 | 国产乱码精品一区二区三区五月婷 |