准确性 敏感性 特异性_如何掌握类型特异性的艺术
準確性 敏感性 特異性
Do more specific definitions result in less flexibility?
更具體的定義會導致靈活性降低嗎?
In this post I will try to avoid the debate about strong/static vs. weak/dynamic types (what more could possibly be said?), or even schema vs. schema less data structures. Instead, I want to focus on the degree of granularity of type definitions: what are the effects and trade-offs?
在這篇文章中,我將盡量避免有關強/靜態與弱/動態類型(還有什么可以說的)的爭論,甚至避免架構與架構較少的數據結構的爭論。 相反,我想關注類型定義的粒度:影響和權衡是什么?
On the one end of the spectrum, very generic definitions encompass potential properties and behavior of objects. On the other end, you have a rich hierarchy of types, of which some are only subtly different from some other.
一方面,非常籠統的定義涵蓋了對象的潛在屬性和行為。 另一方面,您擁有豐富的類型層次結構,其中某些類型與其他類型只有細微的差別。
I will touch upon duck typing, SQL table-per-type (TPT) and table-per-type-hierarchy (TPH) concepts, and parameterized APIs.
我將介紹鴨子類型,SQL表類型(TPT)和表類型級(TPH)概念以及參數化API。
When you think of generic types you might think of the Document Object Model (DOM), schemaless XML or YAML, literal objects in JavaScript, or NoSQL database documents. These are broadly generic, in that there are minimal constraints on structure, relations, and content.
當您想到泛型類型時,您可能會想到文檔對象模型(DOM),無模式XML或YAML,JavaScript中的文字對象或NoSQL數據庫文檔。 這些大致上是通用的,因為對結構,關系和內容的約束最小。
Instead, let’s discuss user-defined types. They may or may not be enforced by the program language or a schema, but there will be constraints, assumed or otherwise, in the code that deals with them. Let’s use Vehicle as an analogy.
相反,讓我們討論用戶定義的類型。 它們可能由程序語言或模式強制執行,也可能未強制執行,但是處理它們的代碼中會假設或以其他方式存在約束。 讓我們以Vehicle為例。
車輛 (Vehicle)
A vehicle is a broad concept. Even if we confine discussion to wheeled vehicles, that covers everything from tricycles to semi-trucks. Could you encompass the spectrum of properties and behaviors of those tricycles, cars, and semis in one type? Yeah, you could. Clearly, that’s going to present some problems when handling Vehicle instances in the program code.
車輛是一個廣義的概念。 即使我們只討論輪式車輛,也涵蓋了從三輪車到半卡車的所有內容。 您能以一種類型包含這些三輪車,汽車和半自動汽車的性能和行為范圍嗎? 是的,你可以 。 顯然,在程序代碼中處理Vehicle實例時,這將帶來一些問題。
車輛類型 (The Vehicle Type)
Possible properties and methods of a Vehicle:
車輛的可能特性和方法:
tires
輪胎
* number
*號
* type [pneumatic, other]
*類型[氣動,其他]
seats
座位
* number
*號
* padded [boolean]
*填充[布爾值]
- steering [wheel, handlebars] 轉向[方向盤,車把]
engine
發動機
* type [none, gas, diesel]
*類型[無,汽油,柴油]
* number of cylinders [only if type is gas or diesel]
*氣缸數(僅當類型為汽油或柴油時)
- drive() 駕駛()
- fuel() 汽油()
- lights[on|high|off] 燈[開|高|關]
With even this minimal set of properties, the Vehicle type covers a huge domain and presents some challenges, data integrity being one of them. If my Vehicle is a trike, I don’t have an engine. If I don’t have an engine, the property number of cylinders is meaningless. If I have a trike with no engine, but number of cylinders > 0, is that an error?
即使只有這些最小的屬性集,“車輛”類型也涵蓋了一個巨大的領域并提出了一些挑戰,其中之一就是數據完整性。 如果我的車輛是三輪車,那么我沒有發動機。 如果我沒有引擎,則為number of cylinders 的屬性number of cylinders number of cylinders 是沒有意義的。 如果我的三輪車沒有發動機,但是number of cylinders > 0 ,那是錯誤的嗎?
I can fuel a car or truck, but not a tricycle. What happens if fuel() is called on a tricycle instance? Throw an Error? It is possible that some application logic is confused, but can the request be handled gracefully as a no-op?
我可以給汽車或卡車加油,但不能給三輪車加油。 如果在三輪車實例上調用fuel()會發生什么? 拋出錯誤? 某些應用程序邏輯可能會混淆,但是可以將請求作為無操作者正常處理嗎?
The one perceived advantage to Vehicle is that it is flexible. If we instead split up Vehicle into subclasses MotorVehicle and PedalVehicle, we might put the following in MotorVehicle but not PedalVehicle:
Vehicle的一個明顯優勢就是靈活性。 如果改為將Vehicle分為MotorVehicle和PedalVehicle子類,則可以將以下內容放入MotorVehicle中,而不是PedalVehicle中:
- steering [wheel] 方向盤]
engine
發動機
* type [gas, diesel]
*類型[汽油,柴油]
* number of cylinders
*氣缸數
- fuel() 汽油()
- lights[on|high|off] 燈[開|高|關]
This seemingly makes sense. It is conceivable, though, that a tricycle has lights. It may not have an gas or diesel engine (not a kid’s trike, anyway), but it could have an electric engine. If these cases arise, then there’s some refactoring to do.
這似乎是有道理的。 但是可以想象,三輪車有燈光。 它可能沒有汽油或柴油發動機(無論如何不是兒童三輪車),但可能有電動發動機。 如果出現這些情況,則需要進行一些重構。
In some languages or data management systems, you can define interfaces, and compose concrete types that fulfill those interfaces. So, you might have IEnginedVehicle, which might have related interfaces IElectricVehicle and InternalCumbustionVehicle (which in turn might be broken down into IGasVehicle and IDieselVehicle).
在某些語言或數據管理系統中,您可以定義接口,并組成滿足這些接口的具體類型。 因此,您可能擁有IEnginedVehicle,它可能具有相關的接口IElectricVehicle和InternalCumbustionVehicle(它們又可能細分為IGasVehicle和IDieselVehicle)。
Interfaces are cheap to define, and good at annotation concepts, but they’re not a complete solution. Some interfaces can be incompatible with others: can a truck be both an ice cream truck and a pizza delivery truck? I suppose, if you want cold pizza or warm ice cream.
接口定義起來很便宜,并且擅長注釋概念,但是它們并不是一個完整的解決方案。 有些界面可能與其他界面不兼容:卡車既可以既是冰淇淋卡車又可以是披薩送貨卡車? 我想,如果您要冷比薩餅或熱冰淇淋。
Aside from that, more specificity boxes you in, and requires you to have some foreknowledge of the all types of vehicles you will encounter.
除此之外,您還需要更多專一性,并且要求您對將要遇到的所有類型的車輛有所了解。
It’s the exceptions that are going to get you as time marches on.
它是會得到你的時間游行例外 。
For this reason, especially when the domain is broad and in flux, it can be tempting to define vehicle entities less specifically, initially. You want to be open to anything that comes down the pike (pardon the pun).
因此,尤其是在領域很廣且不斷變化的情況下,可能會很容易在最初就不太明確地定義車輛實體。 您想對落在長矛上的任何東西開放(對雙關語)。
針對通用類型進行編碼 (Coding against generic types)
On the coding side, there can be no assumptions about what Vehicle is. You must check every property for existence. Methods that exist may be meaningless for the specific entity that is represented by Vehicle. Your best bet is to have your code assume nothing. That makes testing a challenge, though. How can you possibly encompass all reasonable Vehicle configurations in your tests?
在編碼方面,不能假設什么是車輛。 您必須檢查每個屬性是否存在。 對于由Vehicle表示的特定實體,存在的方法可能沒有意義。 最好的選擇是讓您的代碼不承擔任何責任。 但是,這使測試成為挑戰。 您如何在測試中包含所有合理的車輛配置?
On the other hand, you have a pretty flexible system; that is, if no assumptions creep into your code (more about this in “Why a duck?”).
另一方面,您擁有一個非常靈活的系統; 也就是說,如果您的代碼中沒有任何假設(有關更多信息,請參見“ 為什么選擇鴨子 ?”)。
Too much specificity requires constant adjustments to the type model, including decisions of what the taxonomy of inheritance is, what property goes at what level, and potential difficulty in changes to the model when they affect not just code at the data layer, but the presentation layer as well. If you get it way wrong (due to rushed analysis), you have a lot of continuous rework.
太多的特異性要求對類型模型進行不斷的調整,包括決定什么是繼承分類法,什么屬性在什么級別進行,以及當模型更改不僅影響數據層的代碼,而且影響表示時,更改模型的潛在困難。層。 如果您弄錯了方法(由于匆忙進行分析),則需要進行大量連續的返工。
類型及其屬性 (Types and their properties)
If you buy a grab box of stuff from an online novelty store, you can expect a box. You have a vague idea of what it contains, but you won’t know until you open it and sort out each item one-by-one. The burden is on you, the client, and there are limited assumptions you can make (one might hope for a rubber chicken, but no guarantee!).
如果您是從在線新奇商店購買物品的抓斗箱 ,則可以預料到。 您對包含的內容有一個模糊的想法,但是直到您將其打開并逐一整理每個項目,您才知道。 客戶和您的負擔很重,您可以做的假設有限(一個人可能希望得到一只橡皮雞,但不能保證!)。
A first aid kit has a narrower range of possibilities as to what it contains. It’s a more specific type of object, and you can make assumptions as to its content and proceed accordingly. It’s going to contain gauze and bandages. It will have antiseptic, and probably pain relievers. For stuff that it might contain, you at least have a better idea what to look for.
急救箱所含物品的范圍較窄。 它是對象的一種更特定的類型,您可以對其內容進行假設并據此進行。 它將包含紗布和繃帶。 它將具有防腐劑,并且可能會減輕疼痛。 對于其中可能包含的內容,您至少要更好地了解要查找的內容。
為什么是鴨子? (Why a duck?)
Duck typing operates by incidence rather than declaration. Program logic revolves around interrogation of an object: “By the way, do you have property A? Do you have method B?…”.
鴨子的分類是根據發生率而不是聲明來進行的。 程序邏輯圍繞著對對象的詢問:“順便說一下,您是否具有屬性A? 您有方法B嗎?……”。
Actions are performed based on responses to the interrogation. If it walks like a duck, quacks like a duck and has feathers, then it is probably a duck. Logic that is based on duck typing really doesn’t care, duck or no, because it assumes nothing; it operates on what it finds.
基于對詢問的響應來執行動作。 如果它走路像鴨子,嘎嘎像鴨子,并且有羽毛,那么它很可能就是鴨子。 基于鴨子類型的邏輯實際上并不在乎,無論鴨子還是不,因為它什么都不做。 它根據發現的結果進行操作。
Yet assumptions will creep into any software logic that thinks it’s getting what it expects. Perhaps as much as 50% of software maintenance involves fixing incorrect assumptions or refining the ones that are there.
然而,假設會滲入任何認為正在達到預期效果的軟件邏輯中。 也許多達50%的軟件維護涉及修正錯誤的假設或完善其中的假設。
鴨子打字和第一React者 (Duck typing and the first responder)
Say I have a fire in my kitchen and call an emergency number. The first responder has a badge, helmet, and arrives in a vehicle with siren and flashing lights. Yay! The fireman! My house is saved. I command, pointing to the kitchen: “Put out that fire!”
假設我的廚房著火了,請撥打緊急電話。 第一響應者戴著徽章,頭盔,并帶著警笛和閃爍的燈光到達車輛。 好極了! 消防員! 我的房子已保存。 我指著廚房命令:“撲滅那火!”
The policeman looks at me quizzically.
警察好奇地看著我。
I did all my duck typing interrogation, but reached the wrong assumption. Maybe the city recently decided policemen should respond to fire alarms if nearby, to aid the firemen.
我做了所有的鴨子打字詢問,但是得出了錯誤的假設。 也許是城市最近決定,如果附近有警員,應該對火警做出React,以幫助消防員。
I now have to add to my list of questions: “Do you put out fires?”
我現在必須在我的問題列表中添加:“你滅火了嗎?”
屬性,鑒別符和命名類型的 (Of properties, discriminators, and named types)
Duck typing is extremely flexible, but your code must deal with each object as if it could be anything. Instead of interrogating all properties, though, you can add a special discriminator property that identifies the type of object your code is receiving. One interrogation, and you're off to the races. Of course, the object has to have the correct discriminator value.
鴨子鍵入非常靈活,但是您的代碼必須像對待任何對象一樣處理每個對象。 但是,您可以添加一個特殊的鑒別器屬性來標識您的代碼正在接收的對象類型,而不是詢問所有屬性。 一次審訊,您就可以參加比賽了。 當然,對象必須具有正確的鑒別值。
A named type is less likely to cause you problems, as types are assigned at object creation. In a weakly typed language, such as Javascript, things may not be as they seem, but you’re somewhat safer assuming.
由于類型是在對象創建時分配的,因此命名類型不太可能引起您的問題。 在弱類型語言(例如Javascript)中,事情可能看起來并不像看起來那樣,但是您的假設會更安全。
Still, discriminators or types don’t really address the problem of specificity. The good old Object type doesn’t say much about its instances. It is a type, it does make some guarantees, but doesn’t do much by itself.
盡管如此,區分符或類型并沒有真正解決特異性問題。 好的老式Object類型對其實例并沒有多說。 這是一種類型,它確實可以保證某些功能,但是它本身并不能做很多事情。
You can pass an object literal to a method, but the method must either 1) assume what it is getting, or 2) be prepared to find out.
您可以將對象文字傳遞給方法,但是該方法必須1)假定其要獲取的內容,或2)準備進行查找。
Maintaining code that handles generic types can be an exercise in aggravation: while you can see what the client code might do, to know what it will do requires the specifics of the data it is handling.
維護處理通用類型的代碼可能會很麻煩:雖然您可以看到客戶端代碼可能會做什么,但是要知道客戶端代碼將要做什么, 則需要它正在處理的數據的詳細信息。
A debugger helps, but if your breakpoint is buried far down in the call stack, or is in response to a callback, good luck! You may have some heavy excavating to do to know how you got where you are, logic-wise.
調試器可以提供幫助,但是如果您的斷點被埋在調用堆棧的下方,或者是響應回調的,那么祝您好運! 在邏輯上,您可能需要進行大量的挖掘工作才能知道自己的位置。
表類型和表類型層次結構 (Table-per-Type and Table-per-Type-Hierarchy)
Relational databases run into this issue as well. If a table represents a type of thing, are all rows in the table type-homogenous? Or could each row reflect a more specific type, and the table represents a supertype of those things?
關系數據庫也遇到了這個問題。 如果表表示事物的類型, 那么表中的所有行是否都是同類型的 ? 還是每一行都可以反映一個更具體的類型,而表代表這些東西的超類型?
In the first case (table-per-type, or TPT), each column in each row is guaranteed to contain a valid value (NULL may be valid). Your code can anticipate query results that are consistent in their uniformity.
在第一種情況(每類型表或TPT)中,保證每行中的每一列都包含一個有效值(NULL可能是有效的)。 您的代碼可以預期查詢結果的一致性。
In the second case, some columns or column values may be valid for some types (rows) but not for others. This is table-per-type-hierarchy, or TPH.
在第二種情況下,某些列或列值可能對某些類型(行)有效,但對其他類型無效。 這是每個類型的表層次結構(TPH)。
A TPH table is a loosely defined type. The integrity of column values in each row is up to program logic. If I have a table called Vehicle containing data for all vehicles in my domain, then the column “oil weight” isn’t going to be applicable for rows representing tricycles.
TPH表是一個松散定義的類型。 每行中列值的完整性取決于程序邏輯。 如果我有一個名為Vehicle的表,其中包含我域中所有車輛的數據,則“機油重量”列將不適用于代表三輪車的行。
The burden is now on the client code to understand the various possible types of vehicles in the Vehicle table, and perform logic accordingly. This is very similar to the case of a duck typed object, where properties may or may not be applicable for each instance of the generic type.
現在,將重擔放在客戶代碼上,以了解“車輛”表中各種可能的車輛類型,并相應地執行邏輯。 這與鴨子類型對象的情況非常相似,后者的屬性可能適用于或可能不適用于泛型的每個實例。
模式,有人嗎? (Schema, anyone?)
Does a schema (or other type system) take care of this problem? Well, no. As just shown, a TPH schema in a relational database can represent a super-type entity, but the rows may each define more specific entities. A discriminator column value can help sort out the subtype of each row, but it has to be checked in program logic.
模式(或其他類型系統)是否可以解決此問題? 好吧,不。 如剛剛所示,關系數據庫中的TPH架構可以表示一個超類型實體,但各行可以定義更具體的實體。 鑒別符列值可以幫助分類每一行的子類型,但是必須在程序邏輯中檢查它。
The main benefit of using TPH is avoiding a huge schema with many tables, and lessening the number of joins required to pull together data for a type instance. There are always trade-offs to any approach.
使用TPH的主要好處是避免了包含許多表的龐大模式,并減少了將類型實例的數據匯總在一起所需的聯接數。 任何方法都必須權衡取舍。
參數列表和選項 (Parameter lists and options)
Method parameters are another issue. The most common case is where parameter type is defined by order of occurrence:
方法參數是另一個問題。 最常見的情況是參數類型按出現順序定義:
function circle(int x, int y, double radius){…}or
要么
function circle(Position xy, double radius){…}Arguments defined this way are locked-in: you can’t pass a boolean to radius, for instance. In JavaScript, there are no typed parameters, so most functions assume the type based on order of occurrence.
以這種方式定義的參數是鎖定的:例如,您不能將布爾值傳遞給radius。 在JavaScript中,沒有類型化的參數,因此大多數函數根據出現的順序來假定類型。
Not only is the type of parameter known (by declaration) or assumed (by convention), the number of parameters dictates how the method is called.
參數的類型不僅是已知的(通過聲明)還是假定的(通過約定),而且參數的數量決定了如何調用該方法。
I always feel a slight annoyance whenever I want to dump some formatted JSON to the console, and have to type JSON.stringify(obj, null, 4). That second argument, which is seldom used, is for the replacer parameter.
每當我想將一些格式化的JSON轉儲到控制臺并不得不輸入JSON.stringify(obj, null , 4)我總是會感到JSON.stringify(obj, null , 4) 。 很少使用的第二個參數是replacer參數。
選件 (Options)
In JavaScript, you can pass an object literal as an argument, and this is often used as a named parameter list. Named parameters are more flexible than an argument list, and for more complex methods they can be very useful.
在JavaScript中,您可以將對象文字作為參數傳遞,并且通常用作命名參數列表。 命名參數比參數列表更靈活,對于更復雜的方法,它們可能非常有用。
function circle(options) {const {x, y, radius, ...rest} = options;if (rest.linewidth) {...}if (rest.fillColor) {...}... }Flexible, yes, but a lot of interrogation. Plus, the arguments x, y, and radius are assumed to be there. Best practice seems to be to mix the type-specific parameter list with the more “generic” object literal:
靈活,是的,但是要進行很多詢問。 另外,假設參數x, y和radius在那里。 最佳實踐似乎是將類型特定的參數列表與更“通用”的對象文字混合在一起:
function circle(x, y, radius, options){...}Where options is typically understood to refer to an object whose properties are documented.
通常將選項理解為指的是其屬性已記錄的對象 。
該怎么辦? (What to do?)
Few practices in software are wholly good or bad (GOTO being the exception[?]). A rigid, type-rich system will no doubt prevent some coding errors, even if those types are not strongly enforced by the language or database. Code that uses specific types is more readable.
很少有軟件實踐完全是好是壞(GOTO是例外[ ? ])。 嚴格的,類型豐富的系統無疑會防止某些編碼錯誤,即使這些類型不是語言或數據庫強制執行的也是如此。 使用特定類型的代碼更具可讀性。
On the other hand, a stringent type hierarchy represents metadata that has to be maintained, and oftentimes the client knows what it is requesting and knows what it will receive. Dotting every “i” and crossing every “t” just for the sake of data transfer between two internal methods at times seems like bookkeeping work.
另一方面,嚴格的類型層次結構表示必須維護的元數據,并且通常客戶端通常知道其請求的內容并知道將接收的內容。 僅僅為了在兩個內部方法之間進行數據傳輸而對每個“ i”進行點劃線,并跨過每個“ t”似乎是簿記工作。
There is no right answer, and most programmers use types of varying (or no) specificity. A lot depends on the domain. If you’re writing code for a financial system, it would seem you’d want a rich and rigid set of type definitions; however, I understand some financial systems are written in MUMPS, so what do I know?
沒有正確的答案,大多數程序員都使用變化(或沒有)特異性的類型。 在很大程度上取決于領域。 如果您正在為金融系統編寫代碼,則似乎需要一組豐富而嚴格的類型定義。 但是,我了解一些金融系統是用MUMPS編寫的 ,那我知道些什么?
翻譯自: https://www.freecodecamp.org/news/the-art-of-type-specificity-d0fdb6918e45/
準確性 敏感性 特異性
總結
以上是生活随笔為你收集整理的准确性 敏感性 特异性_如何掌握类型特异性的艺术的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梦到蛇缠身上预示着什么
- 下一篇: 梦到井坏了怎么回事