对我来说有两种情况,要么函数描述了其输入,调用者必须以正确的形状提供它们,要么函数利用现有的应用程序实体(数据模型),并且应该通过名称引用其定义。
在函数不操作实体的情况下,我确保有好的参数名称,以描述doc-string中的形状,并在获取map或tuple时使用解构来命名每个元素。有时我也可能有一个针对它的规范,尽管那通常只是当我想用生成测试或对其执行验证时。
在函数操作实体的情形下,我将参数名称与实体定义的名称设置为一致。
我使用构造函数定义实体,或者使用名为make-foo的函数创建实体实例,该函数将记录它创建的形状,或者从查看其代码中很容易看出。或者我用记录定义定义它们,其中记录定义描述了形状。或者我用规范来定义它们,规范名称就是实体名称。
(defn make-item
"Makes an item which is a map of key
:id UUID of the todo-list
:name - the user readable string name of the item
:content - the user provided string content of the item"
[name content]
{:id (java.util.UUID/randomUUID)
:name name
:content content})
(defn make-todo-list
"Makes a todo-list which is a map of key
:id - UUID of the todo-list
:name - the user readable string name of the list
:items - an ordered vector of item"
[name & items]
{:id (java.util.UUID/randomUUID)
:name name
:items (vec items)})
(defn insert-item
"Inserts an item in a todo-list at given 0-based position"
[todo-list item position]
(apply conj
(subvec todo-list 0 position)
item
(subvec todo-list position (count todo-list))))
(defn sanitize-input
"Given an untrusted input string, return a sanitized version.
Takes an optional options map with options:
:extra-denylist - a seq of string words to delete on top of default sanitization."
[input-string & {:keys [extra-denylist] :as options}]
(some-lib/sanitize input-string extra-denylist)
所以,正如你在我简短的例子中看到的那样,《sanitize-input》是一个不操作应用程序域模型的函数的示例,它仅使用好的参数名称、解构和良好的doc-string来描述其输入。
另一方面,insert-item
是一个在应用域模型上操作的功能,因此它只使用了它作为输入的域实体的同名,它的附加参数position
则简单地通过一个好的名称和文档字符串进行描述。
最后,通过各自的make-
函数描述域实体。我可以用记录代替它们,或者选择使用Spec。