-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat!: CID as an interface #211
Conversation
@@ -82,13 +82,6 @@ describe('CID', () => { | |||
assert.throws(() => CID.create(0, 113, hash), msg) | |||
}) | |||
|
|||
it('throws on trying to base encode CIDv0 in other base than base58btc', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test has moved to test-link.spec.js
assert.deepStrictEqual(newCid.toString(), cidStr) | ||
}) | ||
|
||
it('.link() should return this CID', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test has moved to test-link.spec.js
This is an attempt at implementing #203, converting the CID class into a minimal interface and having factory functions to return objects that conform to the CID interface. I've preserved all the generics the `Link` interface introduced and there are functions in `link.js` that add the extra methods to turn something that conforms to `CID` into something that can be used as a `Link` so existing code using the `Link` API should not have to change. Notably there was no need to update any of the `Link` tests. The static methods on CID have been exported as individual functions - the names remain the same (`decode`, `parse`, etc) in an attempt to be less disruptive. Code using these methods should mostly just need to change: ```js import { CID } from 'multiformats/cid' ``` to: ```js import * as CID from 'multiformats/cid ``` Types can be imported as: ```ts import type { CID } from 'multiformats/interface' ``` or as before: ```ts import type { CID } from 'multiformats/cid' ``` BREAKING CHANGE: the CID class is now an interface
2043975
to
8152e34
Compare
|
||
it('toJSON()', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test has moved to test-link.spec.js
@achingbrain it seems to me that CID and Link interface are almost compatible at this point, and I'm not sure we need both. Only difference between two seems to be a following set of methods That said changes here seem to exhibit robustness principle design which in our code often manifests in specific pattern that I think is worth sharing as it might provide useful food for thoughts when evaluating this. PatternWe often find yourself defining two distinct interfaces for the same data type. I tend to call the first one model of the data type (which is usually just a data needed to represent a type) and the second a view of the data type (naming isn't ideal because it may get you thinking about MVC, but I'm open to better terms). modelModel in most cases is just a struct with fields to represent a data. Only exceptions to this rule are:
All or our code that produces instances of this type takes model in arguments, which keeps requirements minimal for a caller. Since module can produce instances of the type it already has a dependency on a module that defines a type and there for it has access to all the functions (in static forms) to operate on that data. viewMost our types exposed to the end user have view interface that extends it's model interface. This allows us to expose all of the library functions using methods, which happens to be an idiomatic in JS. I do want to emphasize however that this not just to pleasing folks that want method chaining it has real value: By hanging relevant lib functionality on the instances we free a user that consumes or incorporates them from dependence on our library. In other words if library
genericsCode that incorporates data type into a larger structure as opposed to producing or consuming would ideally take const box<T extends Lib.Model> (value:T): { box: T } = ({ box: value }) That allows Now there are cases where above does not work e.g. because you have to use some functionality of the value. In that case it's usually up to the author to compare pros and cons of introducing dependence on How does this apply here ?It looks to me that with changes here @achingbrain it seems that you have came to a different conclusion thinking that CID as defined in PR would be useful enough and other methods while sometimes useful aren't that necessary in practice. I think I would like to better understand why we came to different conclusions on this. What I do fail to understand however is motivation for removing those methods from the class. Specifically sticking methods on class prototype has no downsides that I can tell and even in the face of model and view interfaces we tend to have a same instance implementing both, here you have chosen to have one wrap the other which comes with performance implications (JS engines can do aggressive optimizations on classes but not as much on structs like you do in I think it would really help to understand what do you think about pattern described above and then how do you think this relates to it or whether it should at all. If you'll find described pattern to be useful here, I'd be happy to work with you on aligning this PR with it (regardless of which one will act as model and which one as view). On the other hand if you do think described pattern is irrelevant to this, it would help to better understand motivation because it's lost on me. If this needs to go forward I would very much prefer to not do what |
I guess this is a shift in thinking away from the current implementation. The primary motivation is to have If the It's harder to go in the other direction and remove functionality while expecting it to behave the same. By which I mean, you could declare extra fields in the * By extra fields, I mean, what is the minimum set of fields a thing needs to be used as a CID? I think it's a The fewer fields we require, the more likely we are to be backwards compatible too so there's less need to convert between older/newer implementations.
In terms of patterns, the change to CID here makes it more of a value object. As an aside, we could double down on that and remove I take your point about not wanting to have to depend on
They are, except there are a bunch of extra fields and methods on
|
I understand the motivation, yet I don't think trimming bunch of methods going to help with this. The problem in my experience is never stuff on If we do want to drop For the background
I think your are conflating problems here. Equality problem comes from own properties and is unrelated to methods and getters on the prototype. If equality check considers prototypes it would also fail if I have CID from different version of library and therefor this would not solve that problem.
I would much rather trim Link interface and happy to work with you on that. Non of the methods are really MUST for us, it was just a set that made sense to me. I'm happy to revisit that |
fwiw this is my preference too, |
closing because I think this is redundant now? if not, maybe re-attempt it on master and we can have a discussion on the changes cause they may still be worth it |
This is an attempt at implementing #203, converting the CID class into a minimal interface and having factory functions to return objects that conform to the CID interface.
I've preserved all the generics the
Link
interface introduced and there is a function inlink.js
that add the extra methods to turn something that conforms toCID
into something that can be used as aLink
so existing code using theLink
API should not have to change.Notably there was no need to update any of the
Link
tests, though I did move some across from theCID
tests and add some extra ones.The static methods on CID have been exported as individual functions - the names remain the same (
decode
,parse
,asCID
etc) in an attempt to be less disruptive.Code using these methods should mostly just need to change:
to:
Types can be imported as:
or as before:
Fixes #208
BREAKING CHANGE: the CID class is now an interface