component

Ziad Salah 2022-08-19T15:56:29.600749Z

Hi all, happy Friday! Am I expected to implement Lifecycle in all of my components, even ones for which I have no state nor anything to setup and teardown?

2022-08-19T16:04:17.223299Z

no, Lifecycle has a no-op extension to Object

👍 1
Ziad Salah 2022-08-19T16:04:57.138139Z

Was just about to say I've reread the readme and saw the following:

The default implementation of Lifecycle is a no-op. If you omit the Lifecycle protocol from a component, it can still participate in the dependency injection process.
Thanks for confirming. I do have a follow-up question though:

Ziad Salah 2022-08-19T16:08:19.023359Z

The readme also mentions:

Components which do not need a lifecycle can be ordinary Clojure maps.
In my case, say I have a component SomeThirdPartyApi, I've made it a defrecord which implements a custom protocol, for example:
(defprotocol SomeThirdPartyProtocol
  (get-info-from-third-party [this email] "Get info for user with email"))
Is this 'overkill' at all? How do I reconcile what I'm trying to do with the message above about components with no need for a lifecycle potentially working as a map?

2022-08-19T16:09:44.541569Z

there are several different constraints depending on what you are doing

2022-08-19T16:10:07.249609Z

you can put anything at all in the system map

👍 1
2022-08-19T16:10:59.156639Z

but in order to depend on anything else in the system map, because of the way component injects dependencies, it has to be map like

👍 1
2022-08-19T16:11:09.727889Z

(a defrecord is map like)

👍 1
Ziad Salah 2022-08-19T16:11:21.658569Z

Awesome, thanks for explaining that

Ziad Salah 2022-08-19T16:12:16.766999Z

I suppose a related question is that the docs mention:

Define the functions implementing the behavior of the component to take an instance of the component as an argument.
In my case I've opted to do that via a protocol definition that the defrecord implements. When would you opt for a good old function vs one defined in a protocol and implemented in a record?

2022-08-19T16:12:36.073179Z

an extremely useful feature of clojure protocols when combined with component is the ability to make protocols extendable via metadata

2022-08-19T16:15:48.243159Z

protocol vs. just a function is going to depend on if I have more than one implementation (often the second implementation is a kind of mocked version of the component for tests)

👍 1
Ziad Salah 2022-08-19T16:17:51.749679Z

Thank you so much for all of this. So it may make sense for me to default towards 'just a function' and only go down the protocol route either if I find myself needing to mock behaviour for tests, or make use of protocol extensions. Thank you also for the links on protocol extensions. I think I will need to do some reading and look at examples to wrap my head around when I might find that useful.

seancorfield 2022-08-19T17:51:56.963769Z

@ziad_salah https://github.com/seancorfield/next-jdbc/blob/develop/src/next/jdbc/connection.clj#L320-L328 -- uses an empty hash map with start attached via metadata and it returns a function with stop attached via metadata. Since there are no dependencies, any Clojure "object" can be used (as long as it can carry metadata).

👍 1