Skip to content
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

Release Versioning Specification #29

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open

Release Versioning Specification #29

wants to merge 13 commits into from

Conversation

nibra
Copy link
Member

@nibra nibra commented Nov 20, 2021

1. Summary

This Specification describes how versions are numbered in Joomla projects.

This specification aims to help developers, code reviewers and release leads to determine, whether a new piece or a
change of code belongs to the next patch, minor or major release. It will also cover documentation requirements that are
related to versioning.

2. Why Bother?

Sometimes it is hard to tell bug fixes and features apart. The Release Leads want a comprehensive set of rules to be
able to make good and fast decisions about the target release of a contribution.

```
with X.Y being the minor version introducing the deprecation.
2. A new minor release MUST be issued with the deprecation in place. That release MUST NOT use the deprecated code
anywhere.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That release MUST NOT use the deprecated code anywhere.

Why?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding of this is as follows

Before this RFC

  1. 1.0 released
  2. amazing new functionality appears that we want to use in J to replace current functionality but it will break b/c
  3. at this point we mark the existing code as deprecated to be removed in 2.0
  4. 1.1 released with the deprecation notices
  5. 2.0 is developed in parallel not using the deprecated code and instead using the new stuff
  6. 2.0 is released replacing 1.1

After this RFC

  1. 1.0 released
  2. amazing new functionality appears that we want to use in J to replace current functionality but it will break b/c
  3. we cant just mark the code as deprecated because we are not allowed to use that code and we cant use the new code because its not written

Now we are stuck. We cant notify people in advance of a deprecation before replacement code is ready and used.
But if that replacement code requires a B/C break (perhaps something different such as php99) then it can never be released and as you cant release 1.1 with a deprecation notice while still using the deprecated code. Confused yet? Which comes first the chicken or the egg.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we cant just mark the code as deprecated because we are not allowed to use that code and we cant use the new code because its not written

Exactly, that's intended. Deprecation can take place, when the alternative code exists. It is meaningless to deprecate code, if it still is needed. In your example, the new code has to be present in 1.1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry but that makes no sense in the real world. Here is a scenario

php version 9 introduces a new feature called gimble
gimble offers some great new ability that will enable us to rewrite jbanana with a lot less code and perform faster.
We cannot use gimble until the next major release due to the php version 9 requirement but we know that we will be replacing jbanana with gimble. In fact development on the rewrite has already started in the j5 branch.

With this rule we cannot mark jbanana as deprecated until J5.0 when gimble is released. Whereas we should be giving everyone advance notice as soon as it is possible.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming that jbanana is a Joomla feature, it should not change its signature, if it is going to use gimble behind the scenes. If jbanana is a PHP feature that will be replaced by gimble, the signature of the Joomla code using jbanana should not change, when it is rewritten for gimble.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @HLeithner for the code examples! With your permission, I will include them in the meta-document with the appropriate annotations.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure @nibra but I wouldn't add it to the meta document, I would create a new document "appendix" or "examples". Because I would expect we will have a bunch of examples at some point.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Unlikely to be an outcry because that is the current behaviour
  2. The replacement can be shown in the 13.0 development

You're thinking too high level. It might be appropriate for a single library but not for the cms

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't add it to the meta document, I would create a new document "appendix" or "examples". Because I would expect we will have a bunch of examples at some point.

I put into meta document for now; we can separate the examples later on. For the current discussions, I think having two documents (the sepc and the meta) is challenging enough ;)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're thinking too high level. It might be appropriate for a single library but not for the cms

Well, for extension developers, the CMS IS a library. And we've seen a couple of times, that 3PD start late on adapting their code to CMS changes. The fact that not providing a transition phase "is the current behaviour" should not encourage us to continue behaving that way.


#### 2.2 Internal API

The "Internal API" comprises the structural elements that are supportive for the core and SHOULD NOT be used by

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you give an example

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example Registry::toFlatten(), which is used by Registry::flatten(). Extension developers (or developers using the Framework) should not use Registry::toFlatten() directly. At least in the Framework there are a couple of such things. Being able to flag them as internal would make maintenance a lot easier.

@HLeithner
Copy link
Member

Thanks niels for starting this RFC. As brian already mentioned communication is important and it would be better to have example what is meant by xyz.

I would positioned the result of this RFC as replacement/addition to https://developer.joomla.org/development-strategy.html#backward_compatibility or depending on the final outcome to adapt other parts of the development-strategy.

This RFC for example doesn't mention any exception we already have for b/c like we have no b/c promise for any PHP except the code in /libraries on the other side we have a full b/c promise for all javascript code.

So maybe a framing what this RFC should effect and what it should not effect would be good (relative to the development strategy).

@brianteeman
Copy link

I think its going to be pretty difficult to write one document, with suitable examples, that applies to the cms and the separate framework. Probably why we are having difficulty communicating

@HLeithner
Copy link
Member

I think its going to be pretty difficult to write one document, with suitable examples, that applies to the cms and the separate framework. Probably why we are having difficulty communicating

of course there can be different documents and rules for the cms,framework and extensions but I would expect that differences will only be in details and not at the baseline.

I'm much more interested in "What's a new feature, what's a bugfix, what's an UI improvment and in which version it should be merged".

For example one definition in the last discussion was, "Everything that adds a new functionality have to go into the next minor" as opposite what is when the "functionally is planed/expected but code to write was forgotten/missed/ignored simply not merged in time", then it's an expected functionality and code be handled as bug fix?!

On the other topic, at the current status of the document we have a rule that says The DocBlock MUST be annotated to document the replacement for the deprecated element. which doesn't work for functions that has no replacement. It's possible that we deprecate and remove functionality that doesn't fit in to the cms or framework anymore.

@brianteeman
Copy link

Maybe this example is better to explain my query

 * @since       3.2.0
 * @deprecated  4.0  Use the `joomla/openstreetmap` package via Composer instead
 */

This deprecated line was added to J3 over five years ago. According to my understanding of your statement this deprecation notice could not be added to J3.

### 4.3 Deprecations

The core contributors have not been very cautious about deprecations in the past.
`JObject`, for example, has

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a bad example. Because this is an example of a class we're phasing out without replacement (it was mainly about PHP4 workarounds at the time). But due to huge dependency tree was always going to be slow.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is a perfect example, We're trying to phase it out without (obviously) being able to do it. So it should remain, until we get rid of its usages. If that's not possible, it is just a proof that we can't deprecate the class.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thats where we disagree. It should be marked deprecated because we know today that it will be replaced with something else in the next major release. Under your rules it cant be marked as deprecated until the replacement code is available and in use. meaning that instead of giving developers advanced notice as soon as possible you are delaying that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case deprecation doesn't mean replacement. JObject should just be removed (since we didn't it proper enough it's now called CMSObject which I think is really impressive that we can rename something but can't remove it^^).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was not possible to remove JObject in Joomla 4. Instead, with the new rules, it could be declared as 'internal' along with a phase-out-deprecation as part of the public API. That would be a clean way to handle this. Having a public class in 4.1 which will get removed in 4.0 does by no means make any sense to me.

Copy link
Member Author

@nibra nibra Nov 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're not talking about removal here - replacement code is needed for replacements only. Removal of code is tackled in section 3.2 and offers exactly the information that you need, as soon as possible.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nibra What? Are you responding to the replies I am sending or the replies you THINK I am sending?

Let me phrase it differently.

What every single 3PD is interested in is the following:

  • WHEN is this gonna change? REQUIRED.
  • HOW is this gonna change? REQUIRED.
  • WHAT am I supposed to do when it changes? SEMI–REQUIRED.
  • WHY is it even changing? OPTIONAL.

WHEN is necessary for us to plan our releases. If we are caught by surprise because an unannounced and ill–communicated (if AT ALL communicated) change in Joomla broke something we have to waste our time telling our clients that Joomla broke something YET AGAIN which means that we have even LESS time to fix it. That's the number one reason people leave Joomla and the number one DEVELOPERS leave Joomla. There are developers who literally started working in fintech because the pressure is lower than building Joomla extensions...

HOW is necessary for us to start figuring out what to do. If it's going to be removed we're SOL and left to figure it out on our own. If it's replaced with something else what is it and how are we supposed to use it? Is it a drop–in replacement or do we hav to invent something?

WHAT is linked to the item above. If you have a replacement we'd like to know how it's supposed to be used instead of letting us figure it out on our own, possibly making wrong inferences / assumptions.

WHY is optional but it provides context. Context is great in case the change you did result in a feature we provided being removed. It's far better for us to tell our clients “We removed X because Joomla removed Y due to security concerns, here is the TL;DR version of why this makes sense” than telling our clients “We removed X because Joomla removed Y for no good reason”. The former builds trust to Joomla. The latter breaks trust to Joomla.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nikosdion We are all on the same site and has more or less the main points covered as you wrote in your last comment

https://github.com/joomla/rfc/blob/8d3e35940c41c14ae5ebdd3eac97f769cc07c7d2/proposed/release-versioning.md#32-phasing-out-features

The DocBlock MUST be annotated to document the future removal of the deprecated element. The deprecation annotation SHOULD be supplemented by a recommendation for an alternative. Example:
/**
 * ...
 * @deprecated X.Y  Will be removed in X+1.0 without replacement.
 *                  Please consider using <solution A> or <solution B> instead.
 */
with X.Y being the minor version introducing the deprecation.

WHEN is this gonna change? REQUIRED.

Version X.Y

HOW is this gonna change? REQUIRED.
WHAT am I supposed to do when it changes? SEMI–REQUIRED.

Please consider using or instead.

WHY is it even changing? OPTIONAL.

The official documentation MUST be updated to let users know about the change.

Maybe you don't see the difference but Niels split the "deprecation with replacement" and the "deprecation without replacement".

In case of phasing out a feature it's more important why we do it, normally we would have a really good reason for this like incompatible with the future of php or joomla or the web.

So yes the point 3.2 should be extended with more information for the developer. But the main needs are already in it, "how to replace or what to use instead" (if possible).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like we're on the same page ;)

WHEN is this gonna change? REQUIRED.

Covered by section 3.1 and 3.2 as required

HOW is this gonna change? REQUIRED.

Covered by section 3.1 and 3.2 as required

WHAT am I supposed to do when it changes? SEMI–REQUIRED.

Covered by section 3.1 (required) and 3.2 (optional)

WHY is it even changing? OPTIONAL.

This first and foremost belongs to the PR introducing the change, where it IMO is mandatory. But I fully agree, that we can and must do more on the documentation part outside the code.

Off Topic:

There are developers who literally started working in fintech because the pressure is lower than building Joomla extensions...

I currently make my living developing FinTech applications as Joomla extensions. Not because the pressure is lower (it is actually quite high), but the revenue is much higher.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HLeithner Yes, I was confused there. I thought section 3.2 and 3.1 applied together. Thank you for pointing out they are meant to be mutually exclusive. Now it all makes sense in my head!

@nibra Thank you!

Just to clarify about the “why did this change”. I would link to the PR in the @deprecated comment. I would also make sure that the opening comment (the PR body text at the top of the page) is updated by the maintainers upon RTC or merge — that's something up to you guys to decide — to make sure we have the When, How, What and Why.

Now, you'll tell me, why not use Git blame? I am currently doing that and it's really hard to follow this sometimes. The PR replaces another PR which solves an issue which references two other issues. Each one has 20–100 comments. Some important points are also code line comments which are easy to miss. Falling into this rabbit hole wastes half of my day and I am frequently none the wiser as to WHY it was ultimately decided to be done the way it's done and WHAT I am supposed to do instead. In fact, it's so convoluted I am usually better off following the code with XDebug which is not something we should reasonably expect 3PDs to have to do to make sense of Joomla — it's bad developer experience.

Making sure there is a link in the deprecated DocBlock annotation and that the PR tells us everything we need is a low effort way of solving that.

Even better, this allows creating meaningful changelogs (Joomla already links to the PRs in the online changelog so it's halfway there) and migration guides, the latter by tagging PRs as “Architectural Change” and collating each of these PRs' b/c break section into a nice, clean document published once every minor version.

I won't claim to have invented this method. This is pretty much what the PHP project does :)

@HLeithner
Copy link
Member

Maybe this example is better to explain my query

 * @since       3.2.0
 * @deprecated  4.0  Use the `joomla/openstreetmap` package via Composer instead
 */

This deprecated line was added to J3 over five years ago. According to my understanding of your statement this deprecation notice could not be added to J3.

That's good example for "a function without replacement" the deprecation message is not good in my opinion because it should tell you you have to find a alternative package and we have on in the framework. And it should be possible to use this right now independent from the cms. But actually I don't know if this really works.

@zero-24
Copy link

zero-24 commented Nov 21, 2021

That is a bad example as joomla/openstreetmap is deprecated and do not get a 2.x version ;)

@HLeithner
Copy link
Member

That is a bad example as joomla/openstreetmap is deprecated and do not get a 2.x version ;)

actually the examples are good because we should tackle exactly these. Things that happen and what we do to make it better next time.

@chmst
Copy link

chmst commented Nov 21, 2021

I am interested in quite simple and very concrete cases. For example: Params which are not used in core.
Maybe they were used log time ago and 3rd party developers are using these params for their own extensions. Removing params cannot be announced via deprecation.

@nibra
Copy link
Member Author

nibra commented Nov 21, 2021

On the other topic, at the current status of the document we have a rule that says The DocBlock MUST be annotated to document the replacement for the deprecated element. which doesn't work for functions that has no replacement. It's possible that we deprecate and remove functionality that doesn't fit in to the cms or framework anymore.

That's called 'phase out a feature' in the document (Section 3.2). So removel without replacement is absolutely possible.

@nibra
Copy link
Member Author

nibra commented Nov 21, 2021

Maybe this example is better to explain my query

 * @since       3.2.0
 * @deprecated  4.0  Use the `joomla/openstreetmap` package via Composer instead
 */

This deprecated line was added to J3 over five years ago. According to my understanding of your statement this deprecation notice could not be added to J3.

Please look at Section 3.2 wich deals with removal of features.

@nibra
Copy link
Member Author

nibra commented Nov 21, 2021

I am interested in quite simple and very concrete cases. For example: Params which are not used in core. Maybe they were used long time ago and 3rd party developers are using these params for their own extensions. Removing params cannot be announced via deprecation.

Well, yes and no. Signatures could be deprecated and for example be replaced by another one with less parameters. In those cases, the method in question must accept and work with both signatures until the next major version, and the core must use only the new signature. However, since PHP is not polymorphic, this is rarely doable, and a new method needs to be introduced with the new signature, while deprecating the old method.

@nibra
Copy link
Member Author

nibra commented Nov 21, 2021

That release MUST NOT use the deprecated code anywhere.

Why?

I elaborated section 4.3 of the meta document to answer this.

@nibra
Copy link
Member Author

nibra commented Nov 23, 2021

Maybe this example is better to explain my query

 * @since       3.2.0
 * @deprecated  4.0  Use the `joomla/openstreetmap` package via Composer instead
 */

This deprecated line was added to J3 over five years ago. According to my understanding of your statement this deprecation notice could not be added to J3.

Of course it could, because that is "phasing out a feature" refer to section 3.2 of the spec. Just any internal usage of the deprecated code should have (and maybe has) been removed immediately.

@nibra
Copy link
Member Author

nibra commented Nov 23, 2021

I am interested in quite simple and very concrete cases. For example: Params which are not used in core.
Maybe they were used log time ago and 3rd party developers are using these params for their own extensions. Removing params cannot be announced via deprecation.

@chmst , do you have a code sample, on which the handling can be demonstrated?

@weeblr
Copy link

weeblr commented Nov 26, 2021

Hi all,

Thanks for this document. As a 3rd-party dev, and considering my past experience with various CMS features, I'd like to second this statement:

Deprecation can take place, when the alternative code exists.

To me, having an @deprecate notice is not useful if it does not tell me what's the alternative and when the alternative is going to be available. Also, removal is a viable alternative (you call it "phase out").

Examples:

Good:

@deprecated  5.0 Use the cache controller factory instead

Good:

 *
 * @deprecated  5.0 Without replacement
 */
protected static $gmt;

Bad:

 * @since       4.0.0
 * @throws      \InvalidArgumentException
 * @deprecated  5.0
 */
public function triggerEvent($eventName, $args = [])
{

This means the replacement code, if any, has to exist when the deprecation notice is added because it's right when the deprecation notice is added that I can start using the replacement.

The CMS forcing itself to use the new code at the time of the deprecation obviously ensures the replacement (or removal) is a valid solution.

Cheers

into a patch release.

Unfortunately, Joomla has no official definition of "public API". Section 2 of the specification makes up for the
omission. It describes, how public and internal API are told apart using the `@api` and `@internal` annotations as

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will lead to very few parts of the Joomla CMS being considered a public API. For example, in a discussion of an issue of mine I was told that all plugins are internal. Someone could say that the same applies to all of the core components. In this case 3PDs are expected to have their code break at any given time because they cannot depend on the behavior or the code of anything belonging to core being the same even between patch releases. This mathematically leads to all 3PDs needing to reinvent the wheel.

For example, if I cannot trust com_users to work the same way throughout, say, the 4.x versions then my social login extension and my e–commerce extension are NOT going to go through its models to create users, they are going to be creating database entries directly. This of course means that no events are going to be called with unpredictable results. The alternative is to have my code randomly breaking in patch releases.

Before you start adding tags to code you need to sit down and think REALLY HARD how Joomla is used IN THE REAL WORLD and which parts of it are de facto public APIs. I would posit that every core component model's public methods are a de facto public API.

Further to that, the database schema is a de facto public API. Same goes for core JavaScript.

Just focusing on adding tags to PHP code will be very rightly be seen as a preposterous attempt of the project to deflect responsibility for its breaking changes back to third party developers i.e. victim blaming of the worst kind.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I actually want to tackle with this RFC.

As sad the moment we have near zero b/c coverage for the php code (except the library folder).

and actually it's a thing of adding api and internal tag to the functions but not blindly. Instead it have to be well thought as you said. Also triggers should be part of the b/c promise because they actually the only direct way joomla interact with 3rd party extensions...

That said we already do all this and try not to break anything but it's written nowhere which makes it hard to say "the reason this feature request is rejected or deferred because of policy xy".

If you use a extension model with set state it's not guaranteed that the name of the state you set is still the same in the next bugfix release.

The Database structure is not and shouldn't be part of the public api also because of the reasons you already mentioned (events). If something can't be done thru our php api then it should be talked about it why this is the case and if should allow it. But allowing to change the data directly doesn't sound like a good idea.

The JS code is already in the b/c policy which is a bit strange for some code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was told that all plugins are internal. Someone could say that the same applies to all of the core components.

That's absolutely not intended. Thank you for identifying the definition gap!, I'll update the spec accordingly.

Further to that, the database schema is a de facto public API.

Here we disagree. The model is the accessor for the underlying persistence layer and should never be bypassed.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nibra It would appear that you have never written ANY extension for Joomla and it shows.

I have a ticket component. Tickets are submitted by users. I am storing the user ID with the ticket like a good developer.

How am I supposed to search for a ticket given a partial username or email address if I cannot trust the schema to remain stable within the same major version of Joomla? If I have to first use a model method, the first problem is that this method might not exist. If it exists, it might return a number of results that does not fit in memory. Even if it does, it might be so big that using it in a whereIn query makes the resulting query longer than the MySQL max packet size. All these cause my component to be super slow and/or throw fatal errors. These are OBVIOUS issues to anyone who has built a mass distributed extension. Your lack of experience is telling here.

Another thing is, we create extensions which extend Joomla, it's in the bloody name. If I cannot trust Joomla to have a stable schema how can I do this? If I cannot trust that user IDs will be BIGINT how can I write ANY kind of extension which supports more than one user on the site? I wouldn't know what to store in the bloody database table of mine!

If I can't trust Joomla to have an asset ID for each article, something which is a BIGINT, how can I write a comment extension?

If I can't trust Joomla to store fields in a table, how can I build an extension which searches through the fields given the fact that you do not give me a feature to do that?

If I can't trust Joomla to store extensions a specific way in the database how can I write code which works around Joomla's bugs that the Joomla project refuses to even acknowledge, let alone fix?

OF COURSE THE SCHEMA IS A PUBLIC API, FOR CRYING OUT LOUD!!! If you consider the schema to NOT be a public API then 3PDs cannot trust Joomla for ANYTHING AT ALL, WHATSOEVER! We would have to implement a CMS from scratch and our extensions would only work with it. If that's the case why use Joomla and not build an entire CMS from scratch, one we can control so we don't have to put up with idiotic maxims like this?

Before you implement anything in the Joomla project talk to the people who build sites and mass distributed extensions. If you remove from Joomla what makes it useful — the ability to extend it in ways you cannot have possibly imagined — you will be creating the world's most useless CMS.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to get personal. Let's stick to the subject at hand.

Before you implement anything in the Joomla project talk to the people who build sites and mass distributed extensions.

That's exactly, what we're doing here. I will think about your (legitimate) questions and then answer them accordingly. Unfortunately - despite my not inconsiderable experience - this is not something I can just pull out of my sleeve.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry about that, it's been a VERY long day.

I am going to insist that the database schema needs to be treated as a public API throughout a major version of Joomla. Otherwise it is impractical for 3PDs. Without 3PDs you don't have Joomla.

Let me give you examples from my own experience, since I am 90% done converting all of my software to Joomla 4 native API and nobody can accuse me anymore that I am not using core features.

The example I gave previously from the ticket system is something I was implementing just a month ago. I need to display a list of tickets. This list has to be produced fast. Each ticket has two user IDs stored: created_by (who submitted it) and modified_by (who last replied to it). By default, I am displaying 20 tickets per page. Therefore I need to display information about 40 user record entries.

If I use the Joomla API (user factory) I get 41 queries to the database. In most cases the last replying user is one of a handful of people (let's say 2 people) or the same as the user who created the ticket. If I implement a caching user factory in my own code I now need 23 queries. This is still pretty darn slow. If I instead use a LEFT JOIN with he users table I can shave off 40% of the load time of the component page. I am making one query against indexed columns. For this optimization to work I need to know that the schema is going to be stable. If you cannot guarantee that I am back to slow queries and now my Joomla site is no better than a WordPress site. Since the tickets visible to any given user other than Guest may be different than every other user's rendering of that page I can't even use caching.

Besides, if I cannot trust Joomla to have a stable schema throughout a major release what exactly am I storing in the created_by and modified_by columns?! If I cannot trust this to be an integer I will have to save it as a MEDIUMTEXT which will give me enough leeway for whatever you decide to use as the user identifier. However, this column can no longer be indexed and ordered efficiently. Combined with the previous problem my tickets page now goes from 150msec rendering time to over two seconds.

The more you think about it the more you see it's an exercise in absurdity.

The schema MUST be treated as a public throughout a major release. That is to say, you can add to it or do backwards compatible changes to it but you cannot remove anything or rename / change things in a way that causes a b/c break. If you cannot guarantee that then just put a big notice "JOOMLA IS UNSTABLE AND ANYONE USING IT WILL HAVE A BROKEN SITE SEVERAL TIMES A YEAR" and call it a day instead of writing rules and regulations.

You are wrong in saying that the only canonical way to access the data is through the Model. The Models in Joomla are tied to the extreme at the specific features implemented in core components, without any leeway for anything beyond that. I want to create a new user and have Joomla send out notification emails as configured. Do you think that's possible with the current Model? IT. IS. NOT!!! I kid you not!

One of my ticket system features is guest tickets. You are a guest user, you file a ticket, a new user account is created for you. I wanted to use Joomla's model. Joomla's model is, however, tied to the features of com_users and even commits the cardinal sin of looking at the request parameters! YIKES! I had to use Reflection and waste 3 hours working around its limitations to beat it into submission. If I had foregone the core Model I would have been done in a hour but someone out there, especially a certain someone from your country, would be loudly complaining that I am not using the core and ask for my head on a silver platter. You feeling me here? Good.

For reasons like these, to me as a 3PD and someone building sites this RFC seems like a massive leap backwards. Instead of making Joomla more stable, at least through the course of a major version, and defining a sensible way to offer a bridge between two successive major versions this RFC is preoccupied with how to best make most of Joomla unstable by default and pass the buck to the 3PDs and users. Well, 3PDs and users will abandon Joomla in that case.

The simple points you need to address are:

  • The schema needs to be stable throughout a major version.
  • The public API needs to be stable throughout a major version.
  • What is the public API? If it's different than all public methods in classes not marked as @internal, what is the deprecation plan and how are you going to consult with the 3PDs instead of making a unilateral decision?
  • Deprecations must be documented well in advance, along with what is the alternative or whether the feature is going to die completely dropped
  • How to create a Migration Notice document (like PHP does) for each minor and major version
  • Most importantly: there will ALWAYS be a case where you need to violate these rules — typically because of a security fix, as it's happened several times in the past. Who has the final say on that and what it the communication plan to 3PDs and users well in advance of that change?

This is 80% about transparent decision making and good communication and 20% about technical implementation. You only focus on the technical implementation. It's not wrong, it's just not actually solving anything. Most of the technical implementation has been long standardized in PHP and to a certain extent it's already used in Joomla. The decision making and communication has remained as problematic as it's been 16 years ago.

public function makeTea($addSugar = false, $addMilk = false)
{
// Feature switch
if (compare_version(PHP_VERSION, '8.1', '>=')) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would implement this differently. If the PHP version is earlier than 8.1 use a private method makeTea_PHP_LT_81 which is marked @internal. Using a common suffix would make it easier to locate all of that PHP version dependent code without trawling the code for all version_compare instances (BTW, it's version_compare, not compare_version).

For example, a few years later we increase the minimum PHP version requirement to PHP 8.2. We can look for all _PHP_LT_81, _PHP_LT_80, _PHP_LT_74, ..., _PHP_LT_72 suffixes. We can remove these methods and the if–block that calls them blindly, without worrying we are breaking something non–obvious.

We could possibly use some other annotation instead of ugly suffixes but the spirit is the same.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally a good idea

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(BTW, it's version_compare, not compare_version).

I wrote it from top of my head without an ide ;-)

For example, a few years later we increase the minimum PHP version requirement to PHP 8.2. We can look for all _PHP_LT_81, _PHP_LT_80, _PHP_LT_74, ..., _PHP_LT_72 suffixes. We can remove these methods and the if–block that calls them blindly, without worrying we are breaking something non–obvious.

right makes it more clear.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HLeithner No worries. I have written this method name so many times that it's been a second nature to me :D

the compatibility promise. As soon as an external API officially becomes part of the public API, as in the case of
Bootstrap, the rules of Semantic Versioning do apply.

## 5. Examples

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is another thing you need to consider, method signatures. Most of Joomla still doesn't use static typing for method parameters and their return type. However, it is possible to do that without breaking b/c and without doing any of the alternate method names / different classes in this example. This will be the most common use case and I feel it should be documented.

Let's talk about the two separate issues.

Static types of method parameters must match. This will throw an error in PHP 8.0 and later if there's a mismatch. However, this is not the full story. PHP 8 will only throw a fatal error if the override uses a narrower type scope than the parent (I find it backwards even after reading the RFC but it is what it is...).

Let me illustrate. This throws an error:

class MyParent
{
	public function test($foo, $bar)
	{}
}

class myChildOne extends MyParent
{
	public function test(int $foo, object $bar)
	{}
}

This DOES NOT throw an error:

class MyParent
{
	public function test(int $foo, object $bar)
	{}
}

class myChildOne extends MyParent
{
	public function test($foo, $bar)
	{}
}

Given that most of Joomla's public(–ish) methods DO NOT have static typing you CAN add static typing WITHOUT causing a b/c issue. I think this is a non–obvious point and possibly the reason so much of Joomla is still non–typed. The only caveat is that you can't use union types until you drop PHP 7 support but I'd also say that in most cases you should steer clear of union types (with the glaring exception of query classes where string|array is very useful and does make sense, e.g. in the where() method). Union types can keep being defined in docblocks and enforced in the code, checking for the non–array type before the array type (strings are still treated as implicit arrays in PHP, because who needs logic and consistency when dealing with 20+ years of legacy...).

The second concern is the method return type. If there's a mismatch PHP 8.1 will throw a warning. However, you can use the #[ReturnTypeWillChange] annotation to circumvent this issue, at least for the foreseeable future.

Therefore having two separate classes is not required in most practical cases where we need to introduce static typing.

@brianteeman
Copy link

I tried to explain the following during the JUG London meetup last night but as many people had already left the meeting or were not attending I am posting it here (I believe it be the most logical place but feel free to move it)

@brianteeman
Copy link

Timed Releases and a Continuous Upgrade Policy

Summary

By following a continuous upgrade policy any upgrade to a major release should be no more disruptive than that between minor releases. Removing the perceived pain of an upgrade to a major release is beneficial to both users and extension developers. In most cases it will also remove the need for an extension developer to maintain multiple versions of their own code.

A new major release just becomes another release in the existing schedule with a few extra requirements and deprecated code removal. It may require more effort from a Marketing perspective than a minor release but it places little or no additional effort for those involved in pre-release testing.

A new major is just the next scheduled release in a timed release policy and allows for a new major to be moved earlier (or later) in the schedule as required.

A continuous upgrade policy removes the need to maintain two major releases as required currently as a user does not require additional time to upgrade to a major any more as it is not disruptive.

Note this might imapact any current policy on the release of security patches.

A change is disruptive if it :-

  • Introduces a BC break that will impact many extensions, or require many extensions to make non-trivial changes
  • Introduces behaviour or functionality changes that may significantly impact sites
  • Will require refactoring or rewriting of core code, as these changes tend to introduce technical debt and regressions - especially with the lack of automated tests.
  • Will require changes to site owner process, core development processes, or core release processes
  • Will require a data upgrade path.

New Features and APIs

Any non-disruptive new feature or API should be added in a minor release and should not be held back for the next major release. This is fundamental to the concept of continous upgrades and is basically the current practice in the 4.x timed release schedule.

Deprecation

APIs and features may be deprecated at any point in the release cycle but may only be removed in a Major release.

Whenever possible a deprecated API or feature should first be replaced (in parallel) with the new preferred API or feature in a Minor release before removal in the next Major. This might require the new API or feature to be added in a BC way in the Minor release before further changes in the next Major.

Breaking Changes

To enable “continuous upgrades” in the most pain free way a Major release should only include

  • Increased system requirements
  • Upgraded dependencies
  • Code marked for deprecation in the previous release

cc @nibra @HLeithner @bembelimen

@nikosdion
Copy link

@brianteeman This can very easily topple over for “Upgraded dependencies” unless we can revise the minimum PHP version requirements throughout a major version's lifecycle. Look at the WebAuthn feature which depends on a third party library. We will eventually have to fork it and all of its dependencies to make them compatible with newer PHP versions without removing PHP 7.2 compatibility (which the newer versions of that library do).

Situations like that are what make me dispute the use of Composer for third party dependencies in a mass distributed product like Joomla.

I don't have a solution. The only thing I could do on my products is avoid using 3PD dependencies if I can help it and when I can't use Rector to upgrade my forked version of the dependency to support the full range of PHP versions my software supports. It's a pain and nullifies a lot of the potential gains from using 3PD dependencies. Something to mull over while planning for 5.0.

@brianteeman
Copy link

This can very easily topple over for “Upgraded dependencies” unless we can revise the minimum PHP version requirements throughout a major version's lifecycle

Thats the point. A major version has no defined lifecycle. By removing the disruptive changes you can mark any release as a new major

@nikosdion
Copy link

@brianteeman Isn't dropping support for a PHP version a “disruptive change”? Imagine this scenario. Joomla 4.1 supports PHP 7.2 to 8.1. Let's say Joomla 4.2 only supports PHP 7.4 to 8.2 because we had to upgrade a third party dependency which no longer supports PHP 7.2 and 7.3. Someone who's on PHP 7.3 (an EOL version of PHP!) would see an immediate error. That's pretty disruptive.

Bumping the major version to 5 on short notice will, however, be disastrous for 3PDs. You see, legacy MVC and legacy plugin support is deprecated in 4.0 and will be removed in 5.0. We know that. However, most 3PDs use the legacy MVC and legacy plugin support to have a common package for Joomla 3.10 and 4.x to make updates from 3.10 to 4.x possible! They can't rewrite their software until 3.10 becomes EOL because it's impractical maintaining two versions of every extension (I can attest to that from personal experience). Bumping the version to 5.0 less than ~6 months after 3.10 becomes EOL is extremely disruptive to 3PDs as they will have neither adequate time to make that change, nor will they be able to provide a way to support users on the ostensibly still-supported 3.10 version of the CMS. The end result of following this versioning policy to the letter is that you end up with a new major CMS version with little to no software ready for it, in other words people are stuck in the unsupported and EOL'ed Joomla 4 branch with everything that entails for security. Therefore the version bump is also very disruptive in this case.

There needs to be some provision about the transitional period from the old versioning policy to the new one to prevent Joomla shooting its feet. There needs to be an outreach to 3PDs to find out what are their challenges trying to negotiate client expectations and Joomla's release cycle. There needs to be a lot of good, hard thinking about how to deal with third party dependencies which do not share the width of PHP version compatibility with the core CMS. In the end of the day bumping the major version is not as straightforward as it appears to be because Joomla is not used in the real world in the same clinical way assumed by a policy document. There needs to be some planning and communication long before a major version bump — at the very least during the transition period.

@brianteeman
Copy link

They can't rewrite their software until 3.10 becomes EOL because it's impractical maintaining two versions of every extension

The idea of a Continuous Upgrade Policy is that a version is EOL as soon as the next is released. Because they are non-disruptive.

There needs to be some planning and communication long before a major version bump — at the very least during the transition period.

I posted this comment because

  • As described last night J5 would be released in 18 months time.
  • As described by Neils it would be massively disruptive
  • As described by Harald it would be less disruptive

Before the Production department vote on each of the proposed changes and publish the roadmap we need to have this conversation.

@nibra
Copy link
Member Author

nibra commented Feb 16, 2022

As described by Neils it would be massively disruptive

This is probably a serious misunderstanding. The fact that we want to open up new possibilities for developers, that we want to make the code more maintainable, that we want to eliminate the untestability of many core classes, does not mean that everything that has worked so far will no longer work. We don't want to build a new CMS, but rather make the existing one fit for the future.

@brianteeman
Copy link

This is probably a serious misunderstanding.

I can only comment based on what you said at the meeting and what you wrote in the magazine article

@nikosdion
Copy link

does not mean that everything that has worked so far will no longer work. We don't want to build a new CMS, but rather make the existing one fit for the future.

Thank you for this clarification! There were mixed signals coming from the Joomla project, e.g. the magazine article.

Knowing that 5.0 would have a modicum of b/c to make it possible for 3PDs to simultaneously support J4 and J5 is good news, indeed. This is what we need to be able to make extensions in a way that makes it feasible for end users to upgrade their sites without going through a painful migration process. We don't want to go back to the Joomla 1.0 / 1.5 days where a major Joomla version upgrade was a nightmare straight out of hell 😄

Use "release managers" instead of "release leads"
@nibra nibra marked this pull request as ready for review August 24, 2022 10:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants