Back to all reviewers

Defer expensive operations

logseq/logseq
Based on 5 comments
Other

Avoid performing expensive computations until they are actually needed, and eliminate redundant work in hot code paths. This includes delaying database pulls, moving expensive object creation outside functions, and removing unnecessary operations.

Performance Optimization Other

Reviewer Prompt

Avoid performing expensive computations until they are actually needed, and eliminate redundant work in hot code paths. This includes delaying database pulls, moving expensive object creation outside functions, and removing unnecessary operations.

Key strategies:

  • Delay expensive operations: Only perform costly operations like database pulls when actually needed, especially in exception/error branches
  • Hoist expensive computations: Move expensive object creation (like compiled regexes, composed functions) outside of frequently called functions
  • Use defonce for static values: For expensive computations that produce static results, use defonce to avoid recomputation
  • Eliminate redundant operations: Remove unnecessary function calls, file system operations, or data transformations

Example of delaying expensive operations:

;; Bad - always pulls data even if not used
(let [full-data (d/pull db pattern entity-id)]
  (if error
    (throw (ex-info "Error" {:data full-data}))
    (process full-data)))

;; Good - only pull when needed
(if error
  (let [full-data (d/pull db pattern entity-id)]
    (throw (ex-info "Error" {:data full-data})))
  (process (d/pull db pattern entity-id)))

Example of hoisting expensive computations:

;; Bad - recreates function on every call
(defn remove-nils [nm]
  (into {} (remove (comp nil? second)) nm))

;; Good - create function once
(def remove-nils
  (let [f (comp nil? second)]
    (fn [nm]
      (into {} (remove f) nm))))
5
Comments Analyzed
Other
Primary Language
Performance Optimization
Category

Source Discussions