Linked by Hadrien Grasland on Sun 29th May 2011 09:42 UTC
OSNews, Generic OSes It's funny how trying to have a consistent system design makes you constantly jump from one area of the designed OS to another. I initially just tried to implement interrupt handling, and now I'm cleaning up the design of an RPC-based daemon model, which will be used to implement interrupt handlers, along with most other system services. Anyway, now that I get to something I'm personally satisfied with, I wanted to ask everyone who's interested to check that design and tell me if anything in it sounds like a bad idea to them in the short or long run. That's because this is a core part of this OS' design, and I'm really not interested in core design mistakes emerging in a few years if I can fix them now. Many thanks in advance.
Thread beginning with comment 475435
To view parent comment, click here.
To read all comments associated with this story, please click here.
RE[18]: Comment by Kaj-de-Vos
by xiaokj on Wed 1st Jun 2011 11:23 UTC in reply to "RE[17]: Comment by Kaj-de-Vos"
xiaokj
Member since:
2005-06-30

As an example, one could imagine handling your scenario this way :

-Before, server process broadcasted A, version 1
-Now, server process broadcasts B and C, version x, and A version 1
-The implementation of A version 1 provided by the server is in fact just a placeholder one, that calls in turn B and C depending on the situation.

Hmm. Actually, my whole point is that this method of doing things make the server full of compatibility kludges. This is not a good idea in the long run. Compatibility causes the codebase to be slower and longer and more difficult to maintain. If you implemented it as part of the translator, you have stuff working, but incur a translation overhead. This is a good thing by design! This forms a part of the "inflation" that forces the entire ecosystem to contribute.

My idea is that, instead of piling up the precious codebase with fixes, each release should come with a small translator (it may be the same for each release, if you have time to code a general one, or many small wrappers, one for each release). This would help the code be maintainable.

"Still too crude, since you can have minor behavioural changes. Mathematica is one of such examples -- each update, it will tweak some commands a little bit, and even though the parameters are the exact same, the functionality may be drastically changed such that automated updating is impossible.

In that case, compatibility with the old code is broken, so the "breaking" version number should be incremented.

In fact, I'm not sure that a secondary "compatible" version number would be needed. If the new prototype is compatible with the old one, then one should just leave it be as if it was the old version.

Version numbers do little, especially if you run a gap of a few version numbers, depending upon the scale of the problem (determined mainly by the coder, really).

Why ? They help old code not to break as long as their API version is still supported.
"
Now that my intention is made clearer from the one above, you should catch that I think the granularity of version numbers is too coarse. I think that it is healthy for codebases to break compatibility, minor or major, once in a while. But, it also means that the minor breaking version number will increment like crazy. This, it may as well be. However, I doubt that is going to tell you anything more than "Oh, there is a breakage". This is going to be just like the original Unix codebase -- problem areas, potential or not, is just marked with a "?", without any explanations whatsoever, and the reader (hence maintainer/developer) needs to know exactly what is the problem from there. A much more sensible approach would be to have comments telling you what is wrong, and an even better one, transition plan. If you provided information about the transition in the form of spec sheet, then I think the transition would turn out to be a lot smoother than "needs recompile now", or "API is broken; get new version immediately". Not to mention that sometimes, you just want the older version for the removed features.

As per usual, I agree with the rest; case-by-case analysis tend to give better results too. I am just wary of making code be obnoxious to the users. I refer to the RPM4/5/6 ugliness that is just mind blowing. (intentional internal inconsistency is upheld? What nonsensical obnoxious behaviour!)

Reply Parent Score: 2

Neolander Member since:
2010-03-08

Hmm. Actually, my whole point is that this method of doing things make the server full of compatibility kludges. This is not a good idea in the long run. Compatibility causes the codebase to be slower and longer and more difficult to maintain. If you implemented it as part of the translator, you have stuff working, but incur a translation overhead. This is a good thing by design! This forms a part of the "inflation" that forces the entire ecosystem to contribute.

The way I see it, all you do is to move the compatibility kludges from the server to the translator, using e.g. a small interpreted language in the translator, so apart from making the translator more complex I don't see the benefit. Correct me if I'm wrong, though.

My idea is that, instead of piling up the precious codebase with fixes, each release should come with a small translator (it may be the same for each release, if you have time to code a general one, or many small wrappers, one for each release). This would help the code be maintainable.

But as more and more incompatible release happen, the size of the translation layer grows, unless compatibility with old software is regularly dropped. This is why I think that even in your model, breaking compatibility implies a need to write "compatibility code" and as such remains a bad thing if done too frequently.

Now that my intention is made clearer from the one above, you should catch that I think the granularity of version numbers is too coarse. I think that it is healthy for codebases to break compatibility, minor or major, once in a while. But, it also means that the minor breaking version number will increment like crazy.

It depends. If compatibility is only broken "once in a while", then the breaking version number will only increase once in a while, too.

Then there's the compromise of what is versioned : is it the server's remote call interface, as a whole, that is versioned, or is it each individual function that is versioned. That's a subtle design choice : the latter choice leads to version numbers that increase less often (because each individual function is updated less often), and offers more fine-grained information on what compatibility has been broken, but puts more burden on the server's developer (because now each individual function has to be versioned) and is in the end mostly beneficial to "large" server software which offers a very wide range of remote calls, not exactly the kind of thing which I want to favor.

This, it may as well be. However, I doubt that is going to tell you anything more than "Oh, there is a breakage".

See above. If designed for this purpose, it can tell you which function exactly has seen its compatibility broken. From that point, it's time to go and see the API reference, in order to see what has changed in this function and how to adapt the client software in order to make it compatible with the new version.

A much more sensible approach would be to have comments telling you what is wrong, and an even better one, transition plan.

So if I get it right, you'd like to broadcast not only a version number, but a full changelog, along with each function prototype, explaining in details why compatibility has been broken and how to switch to the new version, instead of leaving that to the API's doc ? Well, at least, it could make server developers fear breaking compatibility much more ;)

Just one question : would it be a full changelog in the strict sense of the term ("To migrate from version 2 to 3, do this; to migrate from version 3 to 4, do this; etc..."), or would you want something that directly explains how to migrate from the old version used by the client to the new version provided by the server ?

If you provided information about the transition in the form of spec sheet, then I think the transition would turn out to be a lot smoother than "needs recompile now", or "API is broken; get new version immediately". Not to mention that sometimes, you just want the older version for the removed features.

Transition information is certainly neat, but does it have its place in a remote call mechanism, or should it rather be left to the API documentation, avoiding work duplication, since this one will have to be updated anyway ?

Edited 2011-06-01 12:34 UTC

Reply Parent Score: 1

RE[20]: Comment by Kaj-de-Vos
by xiaokj on Wed 1st Jun 2011 14:37 in reply to "RE[19]: Comment by Kaj-de-Vos"
xiaokj Member since:
2005-06-30

Yes, I mean to shift the compatibility kludges to the translator. The idea is that you can make a major version translator and many minor version translators. In this way, the server code can march forward as it likes; once a translator has been created, breakage is next to free of cost. At the end, when major releases are made, all the minor translators can go to nirvana whereas all the old code can just use the major version translators. There will be a V1 -> V2 translator, a V2 -> V3 translator, so on and so forth, and once that is done, there will be no need for any modifications to them. They must, of course, be able to be chained, so that the maintainer does not need to make V1->V3 translators and such nonsense.

In this method, the size of the translator is bounded by how often major releases are made. It actually encourages major releases, not discourage. And given that it is major releases, major breakages are encouraged too.

I intend this to look more like when you upgrade packages on apt -- the system would try its best to seamlessly upgrade the machines' configuration along with the packages. When it gets into trouble, the user can be asked, or some other appropriate measure can be taken on a case-by-case basis. If seamless translation can be done, so be it. If not, the world will not end.

Leaving things to the API doc means manual intervention is required by the original author. I hope to minimise this to a minimum. If you have a machine parse-able transition plan, then the machine can hobble on as it goes, only dying when it really needs to. Sometimes, you don't even have access to the original codebase / author, so this is actually not so far-fetched.

Of course, the final granularity of the implementation is up to the coder to decide, so I hope I did give you some interesting ideas.

Reply Parent Score: 2