【问题标题】:Clojure style / idiom: creating maps and adding them to other mapsClojure 风格/成语:创建地图并将其添加到其他地图
【发布时间】:2014-11-10 15:05:42
【问题描述】:

我正在编写一个 Clojure 程序来帮助我执行安全风险评估(终于厌倦了 Excel)。

我有一个关于 Clojure 习语和风格的问题。

为了在风险评估中创建关于资产的新记录,我传递了我目前正在使用的风险评估(地图)和一堆关于资产的信息,我的 make-asset 函数创建了资产,将其添加到 RA 并返回新的 RA。

(defn make-asset
  "Makes a new asset, adds it to the given risk assessment
  and returns the new risk assessment."
  [risk-assessment name description owner categories
   & {:keys [author notes confidentiality integrity availability]
      :or   {author "" notes "" confidentiality 3 integrity 3 availability 3}}]
  (let [ia-ref (inc (risk-assessment :current-ia-ref))]
    (assoc risk-assessment
      :current-ia-ref ia-ref
      :assets (conj (risk-assessment :assets)
                    {:ia-ref ia-ref
                     :name name
                     :desc description
                     :owner owner
                     :categories categories
                     :author author
                     :notes notes
                     :confidentiality confidentiality
                     :integrity integrity
                     :availability availability
                     :vulns []}))))

这看起来是一种明智的做法吗?

我可以让它更惯用、更短、更简单吗?

我正在考虑的具体事情是:

  • 是否应该将资产添加到风险评估中? (资产在风险评估之外毫无意义)。
  • 有没有更简单的方法来创建资产;和
  • 将其添加到风险评估中?

谢谢

【问题讨论】:

标签: clojure styles idioms


【解决方案1】:

Clojure(以及任何其他 Lisp 方言)的核心原则是创建小的可组合函数。

如果资产是在风险评估之外创建的,只要该资产在被添加到风险评估之前没有暴露于期望完全形成的资产的代码,这不是问题。

所以我建议以下(未经测试):

(defn add-asset-ra
  [{:keys [current-ia-ref] :as risk-assessment} asset]
  (let [ia-ref (if current-ia-ref
                 (inc current-ia-ref)
                 1)] 
    (->  risk-assessment
         (assoc :current-ia-ref ia-ref)
         (update-in [:assets] #(conj % (assoc asset :ia-ref ia-ref))))))

(defn make-asset
  [name description owner categories
   & {:keys [author notes confidentiality integrity availability]
      :or   {author "" notes "" confidentiality 3 integrity 3 availability 3}}]
  {:name name
   :desc description
   :owner owner
   :categories categories
   :author author
   :notes notes
   :confidentiality confidentiality
   :integrity integrity
   :availability availability
   :vulns []})

您还可能会发现 Schema 库对验证函数参数的形状很有用。

【讨论】:

  • 谢谢:我确实考虑过拆分它们,但没有考虑,因为正如您的代码所示,结果是更复杂的代码。
【解决方案2】:

一些建议,可能适用也可能不适用。

  1. no value 的 Clojure 习语是 nil。使用它。
  2. 将asset 显示为平面地图。位置和位置的混合 关键字参数令人困惑并且容易受到内容变化的影响 使资产有效。
  3. 正如@Symfrog 建议的那样,将资产的验证与其 与风险评估相关联。
  4. 不要费心将:current-ia-ref 作为风险条目 评估。这只是资产数量。
  5. 将资产的默认条目拉出到一目了然的地图中。 您可以根据需要更改假定的默认值。

这给了我们类似以下的东西(未经测试):

(def asset-defaults {:confidentiality 3, :integrity 3, :availability 3})

(defn asset-valid? [asset] (every? asset [:name :description :owner]))

(defn add-asset [risk-assessment asset]
  (if (asset-valid? asset)
    (update-in
      risk-assessment
      [:assets]
      conj (assoc
             (merge asset asset-defaults)
             :ia-ref (inc (count (:assets risk-assessment)))
             :vulns []))))

评论回复

:current-ia-ref 不算数。如果资产被删除,它不应该减少:current-is-ref。

那么 (4) 不适用。

我不确定你所说的 Clojure 成语无价值是 nil 的相关性。请在这种情况下进一步解释一下吗?

引用Differences with other Lisps:在 Clojure 中 nil 表示“无”。它表示不存在任何类型的值,并且不特定于列表或序列。

在这种情况下,我们不需要给:author 或:notes 空字符串值。

'平面图':你是在谈论函数中的参数,如果是这样,那么我同意。

是的。

我不确定你为什么要定义 asset-valid? 函数。这似乎在某种程度上超出了最初的需求:我个人更喜欢确保只能创建有效资产,而不是事后检查。

您的add-asset 函数使用其参数列表的结构来确保风险评估、名称、描述、owner 和 categories 存在(我忘了检查 categories)。如果您将数据呈现为地图 - 无论是作为单个参数还是通过解构 - 您将失去此约束。所以你必须明确地检查数据(是否在单独的函数中这样做是没有实际意义的)。但也有好处:

  • 您可以检查的不仅仅是某些参数的存在。
  • 您不必记住参数的顺序。

难道你的版本不是意味着如果我决定将来让资产成为记录,我必须更改所有调用 add-asset 的代码吗?

没有。记录表现为地图 - 它实现IPersistentMap。显然,您必须更改make-asset。

...而我的方法隐藏了资产的详细信息?

资产的内容在什么意义上隐藏?资产是需要具有特定键的映射,并且可能具有其他几个特定键。资产是否“真的”是一个记录并不重要。

【讨论】:

  • 感谢您的回复。 :current-ia-ref 不算数。如果资产被删除,它不应该减少 :current-is-ref。
  • 我不确定你关于没有价值的 Clojure 成语是 nil 的说法是否恰当。请在这种情况下进一步解释一下?
  • 'Flat map':你说的是函数中的参数吗,如果是,那我同意。
  • :current-ia-ref 不是一个计数。如果资产被删除,它不应该减少:current-ia-ref。
  • 我最初确实考虑过拆分它们,但查看@Symfrog 建议的更改证实了我的观点,即这样做实际上会使代码更加复杂。那就是说我确实喜欢您的片段的外观,尽管我不确定您为什么定义资产有效?功能。这似乎在某种程度上超出了最初的需求:我个人更喜欢确保只能创建有效资产,而不是事后检查。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多