To clarify, if you have a plan on how to help the maintainability and security 
of your container with modules, then of course we’d be happy to help. But using 
a feature when you’re not clear on how to benefit from it is helpful to no one. 
I’ve seen this happen with virtual threads, too. If you use a feature just to 
tick a box, then you’re unlikely to see much value in it. You need to have a 
plan for how to enjoy it.

> On 17 Dec 2024, at 16:05, Ron Pressler <ron.press...@oracle.com> wrote:
> 
> 
> 
>> On 17 Dec 2024, at 14:21, David Lloyd <david.ll...@redhat.com> wrote:
>> 
>> 
>> 
>> You're confusing the idea of modular encapsulation with the idea of platform 
>> integrity. I'm talking specifically about the encapsulation of modules that 
>> are loaded by a custom ClassLoader. If the user defines their own version of 
>> a string class which purports to be immutable, and that class is defined 
>> within my ClassLoader, then yes, I can mutate it if I want to. There are 
>> many ways to do this.
> 
> The “platform integrity” is, itself, enforced by the same module capabilities 
> available to libraries. The point is that modules give you the ability — 
> which didn’t exist previously — to enforce your own invariants, not that you 
> can *choose* not to enforce them. The choice not to enforce invariants is 
> still available, what’s new is the ability to choose to enforce them.
> 
>> 
>> When I load a module in a class loader, I can basically do whatever I want 
>> with it, if I'm willing to do some tedious (and possibly 
>> performance-degrading) work. All I'm proposing is to make the work of doing 
>> *certain* things less tedious and performance degrading.
> 
> Good, so because most programs will have just a single layer, we clearly have 
> to focus on not making many modules per layer be performance-degrading. 
> *That* seems to be the claimed core issue here.
> 
>> 
>> However, to give a counter-example, `Module` has `addUses` as well. But if I 
>> want to call `addUses` on behalf of a module I've defined, there is no 
>> corresponding `ModuleLayer.Controller` method so I do have to define the 
>> extra class, and that's a bit silly. This is an example of an easy 
>> enhancement that would not affect the integrity of the platform, would not 
>> significantly increase maintenance burden (since the logic would be nearly 
>> identical to its sibling methods), and would be easy to achieve.
> 
> But to me this sounds like a sunk-cost argument. If the choice is between 
> putting effort into supporting a rather baroque architecture, that itself is 
> justified by a performance problem, wouldn’t it be better to focus on the 
> performance problem, which could then support a much more common architecture 
> and make the more baroque one unnecessary?
> 
> If you could show how the performance issue materialises, that would be very 
> helpful.
> 
>> 
>> 
>> From our perspective, we started off with an open system, and the system has 
>> been made less and less open over time. Strictly speaking, the only 
>> "feature" here is fancy stack traces. Everything else arises out of adding 
>> restrictions. I'm not saying this to complain about modularity, but to 
>> remind you that we are presently only weakly incentivized to use modules at 
>> all, so dangling intangible "benefits" before me does not entice me much. We 
>> get more "features" by not using it. I'm essentially trying to be a team 
>> player here, but only out of a sense of cooperation.
> 
> 
> But I’m not trying to entice you to use a feature which may or may not be 
> appropriate for your situation. I’m only presuming that since you seem 
> interested in using the feature, you’re already incentivised.
> 
> Modules add powerful capabilities with very important benefits to 
> maintainability and security, and will likely add more benefits. These 
> benefits are available to users who wish to enjoy them. The feature doesn’t 
> exist to serve itself, and using it to tick a box if you don’t believe it 
> helps you certainly doesn’t help us. The JDK already enjoys these benefits.
> 
>> 
>> I'm not sure yet. But I think so.
> 
> I would advise against that. If there’s a problem with a more straightforward 
> architecture, let’s try and resolve that.
> 
>> 
>> Imagine a layer of 1000 modules, packaged in JAR files. To load a single 
>> class from the layer, the layer must be defined. To do this, the graph must 
>> be resolved, and to accomplish that, the descriptors of every module must be 
>> created. To get the descriptors, each of the 1000 JAR files has to be opened 
>> and the bytes of the descriptors must be read from each one. Because of 
>> eager resolution, the load time of a module layer will always scale in 
>> linear proportion to the potential number of modules in the layer, no matter 
>> how optimized each step in the process is made to be. The only possible 
>> optimization strategies involve paring down the root set - something which 
>> requires ahead-of-time analysis which again would not be necessary if 
>> modules were loaded and linked lazily, like classes are. Loading modules on 
>> demand would solve this performance issue fairly decisively; it would also 
>> not forbid ahead-of-time assembly of a module graph if that is what the user 
>> wants.
> 
> But the JDK has to support any reasonable number of modules in a single 
> layer, as that’s the common case, anyway. There is no need to hypothesise. 
> Either it works with acceptable performance or it doesn’t, and if it doesn’t, 
> that requires addressing. Indeed, there’s significant ongoing effort on 
> improving startup time, not just relative to modules’ current state, but 
> relative to that of all Java applications, modular or otherwise.
> 
> — Ron


Reply via email to