my strategy is to define a class hierarchy, but build sufficient flexibility into the schema and generators that i can override it where it doesn't fit the target environment
this matters especially in LDAP, for example, where there are abstract, structural, and auxiliary classes, with associated rules about which can subclass what, and i need them to co-exist with all the (de facto, at least) standard ones, which dictates which ones will need to be auxiliary
for example, i say that a "Realm" is a subclass of "Container"
but in an LDAP context, "Container" is a structural class — you can create a Container object in the directory at will
a "Realm", on the other hand, actually just augments an organization, organizationalUnit, or a domain (possibly others too) — if it wasn't auxiliary, it would mean that you'd have to completely change how people tend to model stuff in directories or have some very messy subclasses: organizationalRealm, domainRealm…
this does come with warnings: if code expects realms to be subclasses of containers, then it will expect the properties of containers to be present on a realm — and so care must to be taken to ensure you don't end up in a situation where entirely valid directory information appears to be nonsense from a programmer's point of view
but these are avoidable pitfalls
(object models of different data and programming environments do not match up neatly, this i knew from the outset)
strictly speaking all LDAP objects are (depending on directory policies) able to act as containers, so i may end up drawing a distinction between an LDAP "container" objectClass which basically does nothing special, and the Container (API) class, which any object fetched from a directory would implement
so there's probably a bit more jiggery-pokery required before everything lines up properly, i'm just not sure how much is "define two separate things" versus "one thing with LDAP overrides"
that list incidentally leads me to the standards-track RFC7532 from NetApp, IBM, and Oracle in 2015 on federated NFSv4 with LDAP lashing it all together which i had no idea existed but considering i fully planned to run NFSv4 across clusters with LDAP lashing it together… that's another thing i don't need to define myself
attempting to auto-generate class diagrams is a frustrating exercise largely because all of the diagram-generating tooling out there is woefully limited in terms of your ability to provide useful layout hints such as describing nested namespaces
generating the mermaid diagram file is easy; generating one which results in a readable diagram is not
separate but related: the thought occurs (or rather, did occur about 10 years ago) that if i have class and property definitions expressed as both LDAP schema AND JSON schema then you could probably stitch together a RESTful CRUD interface to an LDAP server without a monstrous amount of effort, with some minor constraints
i think i should give up on the diagram thing, i have a far clearer picture in my head than mermaid is able to generate, not to mention the weird rendering errors which only manifest in Mermaid's "fullscreen" view, bizarrely
@tommorris i'm sure there was a reason i abandoned Graphviz in frustration but i can't remember what it was, in any event the effort required to try it is low so i should
i wonder if i excluded "top" it would have an easier time of it, mind you — mandatory base classes are a bit of a bane of inheritance diagrams if you have a broad class base
i think it's probably most useful showing a single (derived) class's inheritance chain… which i could do, tbh: i can generate a separate diagram file for each class without much fuss
i do not claim it to be +good+ or even necessarily idiomatic Python, it is the epitome of a quick and dirty tool to do a job, the last thing i want to do is end up sinking hours upon hours of effort into it for the sake of "cleanliness"; as long as it generates consistent output and isn't a monster to add new generators to, it should remain fairly stable whilst the class library itself develops
JSON schema output now correctly emits descriptions if present and also turns multi-value attributes into an "anyOf" allowing either 1 value or an array of values to be provided
more importantly i can override the type definition for a particular flavour: in LDAP a userPKCS12 value is just a binary blob, in JSON that's not useful, but nor is it the case that all things stored as "Binary" in LDAP should be represented as URLs in JSON — some should be conveyed as objects instead
what i can't yet do (mainly because i haven't decided on the appropriate way to express it in the XML) is to say "yes the class definition states that this is a required property, but in a [JSON] context it should be considered optional" — one environment's required attribute is another's inferred property
i am procrastinating a little because i would make more immediate progress by writing the class implementations or Rust (or even Python…) bindings than i would LDAP and JSON schema BUT
if i have to reorganise my class hierarchy in order to make it fit neatly around these things later then it will be a royal pain in the ass, especially as i actively want to make use of a number of these classes as the basis of system objects because they are in heavy widespread use
but ALSO that you can extend that to the sorts of things you use "objects" (more realistically OOP) for more generally, and indeed whilst it's true that some types of objects will only ever really exist within the heap of a particular process, and others will only really exist in a database server somewhere 99.999999% of the time, that still leaves a big ol' rump of broadly-applicable stuff that could and can be and is represented in more than one of those contexts
i say "my theory is that" but tbh these are design principles which have been reasonably well-tested by commercial platform vendors — Sun/Oracle, DEC/Compaq/HP, IBM, Red Hat, Novell, Microsoft all built platforms recognising that delivering value hinges on allowing their customers to operate at an abstraction which is meaningful and consistent across an enterprise
a lot, if not most, OSS (fairly, to a degree) leaves that out: it's all a bit too much into the realms of being opinionated
i should in the interests of expectation management note that i've been attempting to do something like this on and off for the best part of twenty-five years and invariably hit a wall each time for plenty of reasons including, but not limited to: my state of mental wellbeing, hardware failure and poor backup regimes, life upheaval, infinite yak shaving, not understanding enough of the problem, and procrastination
but i've learned a lot in that twenty-five years, i know where all the walls are
i can't remember exactly which magazine but i think it was Personal Computer World in what i imagine was around 1994 ran an article on this guy Tim Berners-Lee's HyperText Transfer Protocol and included some request/response transcripts
and little teenage me who had read the never-ending stream of articles up to this point on the rise of OOP and object-oriented platforms read it and thought "huh, that looks like an object-RPC protocol with global addressing"
i guess if i'd written into the magazine i to say this i could have got the credit for inventing web services but tbh it seemed so obvious i was weirded out for a while when i actually got regular Internet access how the Web was not being used that way at all (this was another reason besides its monstrous complexity that SOAP altogether broke my brain when it came along to join the party)
i did always like the fact that RTSP — an old media streaming protocol — basically embodied this concept
if you've never seen it, it looks a LOT like HTTP, but with tweaks so it can work over UDP and be asynchronous; the actual media is carried in a separate stream (often from a different source); and its verbs weren't GET and POST but PLAY, PAUSE, RECORD, etc.
as i envisaged it way back then, you could assign URLs to your object instances, and then map methods to HTTP verbs, and advertise them to clients via OPTIONS
so foo.bar(...) becomes BAR /path/to/foo?…
there is no technical reason why you couldn't implement this on most web servers and client libraries
it'd be as ugly as hell and honestly i wouldn't advocate it now but i was young
you could PROBABLY sneaky sneaky extend HTTP a teeeeny tiiiiiny bit without breaking literally everything by introducing an extended "METHOD:operation"-type syntax if you were dead set on something of this ilk (altho why not just convey the operation in a header if you're gonna do that)
Add comment