And just so you know how huge this problem is:
https://infra-reports.apache.org/#ghactions

For all non-members, that don’t have access to that resource:
It shows how much of the GitHub Actions resources each project is using.
Apache IoTDB is currently using 95% of all GitHub Actions resources, leaving 
less than 5% for the other 200 projects we have.

Chris


Von: Christofer Dutz <christofer.d...@c-ware.de>
Datum: Donnerstag, 18. Juli 2024 um 10:41
An: dev@iotdb.apache.org <dev@iotdb.apache.org>
Betreff: AW: AW: AW: AW: Possible pattern for reducing the negative effects of 
using singletons and improving testability
I think for some tests, it might be worth migrating them back from an IT to an 
UT.
I’m currently trying to get resource-consumption stats from infra and wanted to 
start finding out which are our most “expensive” Its and possibly start a 
discussion on converting them to unit-tests. Right now, it feels as for every 
bit of functionality we add more Its, which all require spinning up of small 
instances of IoTDB.
Also is it really challenging to test the unhappy path in integration-test, 
which comes with other problems.

So yeah … I hope by removing the singletons from a component, we can make it 
Unit-Testable and then we can gradually reduce the load on the integration-test 
suite.

Chris


Von: Tian Jiang <jt2594...@163.com>
Datum: Donnerstag, 18. Juli 2024 um 10:35
An: dev <dev@iotdb.apache.org>
Betreff: Re: AW: AW: AW: Possible pattern for reducing the negative effects of 
using singletons and improving testability
Certainly, I am not actually expecting a really perfect solution, just hoping 
when someone else sees this discussion, he may provide a better trade-off.


And as I have said, I am happy with both solutions, as long as they can get rid 
of the singletons.


Mocking is helpful in tests. But the modifications (when actually removing 
singletons from the main source code) in constructors may still be painful.
Of course, it is enough just for testing purpose.


However, for the problem concerning resource consumption, are you going to 
remove some current ITs if your changes are applied?

If no, the resource consumption is still there; if yes, it may be challenging 
to guarantee the equivalence of the ITs and UTs.


Tian Jiang


| |
Tian Jiang
|
|
jt2594...@163.com
|
---- Replied Message ----
| From | Christofer Dutz<christofer.d...@c-ware.de> |
| Date | 7/18/2024 16:19 |
| To | dev@iotdb.apache.org<dev@iotdb.apache.org> |
| Subject | AW: AW: AW: Possible pattern for reducing the negative effects of 
using singletons and improving testability |
Hi Tian,

I think – as usual – there probably is no perfect solution.
I guess it comes down to deciding which things you are willing to do in order 
to solve some other problems on the other side.

I personally think our biggest problem right now (At least this is what’s 
making my Life a lot harder working on IoTDB) is the inability to run 
unit-tests and I see how much resources we are wasting on GitHub Actions. 
Constructor-Injection solves that problem.

Of course, could be build some sort of Factory, that helps initialize some 
methods, but admittedly I think a simple:

SomeService someService = Mockito.mock(SomeService.class);

Is not too challenging to do.

Chris

Von: Tian Jiang <jt2594...@163.com>
Datum: Donnerstag, 18. Juli 2024 um 09:55
An: dev <dev@iotdb.apache.org>
Betreff: Re: AW: AW: Possible pattern for reducing the negative effects of 
using singletons and improving testability


A template (or util) method can provide basic contexts, and the developers just 
need to override the parts they need (of course they should know which parts 
they need).
In the constructor-way, the developer should know what instances they will use, 
create them, and pass them to the constructor;
while in the context-way, the developer should know what fields they will use, 
create them, and override them in the context.
I do not think they are essentially different.


The problem is, for high level structures like DataRegion,  they will have many 
many more fields because their children use many different ones, and the 
constructor will be very long for them.
Certainly, you may further migrate the constructor-way to the builder-way, 
which may solve the problem. However, it requires much more extra work.


I am not particularly fond of either one and I just want to point out the 
problems, hoping someone may give a perfect solution.
If none is given, I am happy to accept either one.


Tian Jiang


---- Replied Message ----
| From | Christofer Dutz<christofer.d...@c-ware.de> |
| Date | 7/18/2024 15:39 |
| To | dev@iotdb.apache.org<dev@iotdb.apache.org> |
| Subject | AW: AW: Possible pattern for reducing the negative effects of using 
singletons and improving testability |
However, then you need to construct these contexts with loads of parameters for 
unit tests … I personally don’t think passing in explicitly what you need into 
a constructor is bad.
So, if you have this service that you want to test: How can you tell the 
developer writing the test which services are needed and therefore need to be 
mocked in the context?
I would strongly opt for explicit dependency injection in the constructor and 
not using some context.

Chris

Von: Tian Jiang <jt2594...@163.com>
Datum: Donnerstag, 18. Juli 2024 um 09:27
An: dev <dev@iotdb.apache.org>
Betreff: Re: AW: Possible pattern for reducing the negative effects of using 
singletons and improving testability
Yes, maybe we could have leveled context like DataNodeContext, 
DataRegionContext, TsFileProcessorContext... and put the former singletons in 
these contexts.


This may avoid constructors with dozens of parameters.


Tian Jiang


| |
Tian Jiang
|
|
jt2594...@163.com
|
---- Replied Message ----
| From | Christofer Dutz<christofer.d...@c-ware.de> |
| Date | 7/18/2024 15:22 |
| To | dev@iotdb.apache.org<dev@iotdb.apache.org> |
| Subject | AW: Possible pattern for reducing the negative effects of using 
singletons and improving testability |
Ideally,

we could inspect the usages of the constructors using the singletons and apply 
the same pattern there. Once all usages have been migrated that way, we could 
even eliminate the Singleton-using constructor. In the end getting a system for 
which we can finally write sensible unit-tests again and don’t need to rely on 
Integration tests.
Integration tests that have problems running in paralell, while unit-tests can 
run perfectly in paralell.

Chris


Von: Christofer Dutz <christofer.d...@c-ware.de>
Datum: Donnerstag, 18. Juli 2024 um 09:03
An: dev@iotdb.apache.org <dev@iotdb.apache.org>
Betreff: AW: Possible pattern for reducing the negative effects of using 
singletons and improving testability
Ok …

So, as there was no objection here, I’ll trat that as consensus and I’ll just 
do this for every component that I touch and hereby need to write tests for.

Chris

Von: Christofer Dutz <christofer.d...@c-ware.de>
Datum: Montag, 15. Juli 2024 um 11:49
An: dev@iotdb.apache.org <dev@iotdb.apache.org>
Betreff: Possible pattern for reducing the negative effects of using singletons 
and improving testability
Hi all,

I am currently working on some functions and when writing tests for these, I 
had problems sensibly testing things, as the singletons were preventing that.
As I mentioned before … I consider the usage of singletons the probably worst 
design decision done in IoTDBs core. Even if it simplifies “composition”, it 
really makes everything else more complicated.

Knowing how deeply rooted in IoTDB the use of singletons is, I always thought 
this would be a never-ending story.
But I just recently had an idea of how we could probably find a way to get the 
testability that we need without having to give up on singletons.
Possibly this path could also provide a path to getting rid of singletons over 
time.

As I was just working on DataNodeServerCommandLine I did an experiment with 
that, and it worked nicely.

So, I searched for all singletons used in the component and defined private 
final member variables for each of them.
In the no-args constructor I initialize these via the singletons, but I also 
add a second constructor, that allows passing in explicit versions.


private final ConfigNodeInfo configNodeInfo;
private final IClientManager<ConfigRegionId, ConfigNodeClient> 
configNodeClientManager;
private final DataNode dataNode;

/** Default constructor using the singletons for initializing the relationship. 
*/
public DataNodeServerCommandLine() {
configNodeInfo = ConfigNodeInfo.getInstance();
configNodeClientManager = ConfigNodeClientManager.getInstance();
dataNode = DataNode.getInstance();
}

/**
* Additional constructor allowing injection of custom instances (mainly for 
testing)
*
* @param configNodeInfo config node info
* @param configNodeClientManager config node client manager
* @param dataNode data node
*/
public DataNodeServerCommandLine(
ConfigNodeInfo configNodeInfo,
IClientManager<ConfigRegionId, ConfigNodeClient> configNodeClientManager,
DataNode dataNode) {
this.configNodeInfo = configNodeInfo;
this.configNodeClientManager = configNodeClientManager;
this.dataNode = dataNode;
}

With this was I now able to write real unit-tests for the component, without 
having to require writing an Integration-test which costs a lot more resources 
and which makes implementing unhappy-path tests really challenging.

With this approach, I think we can really improve testability in IoTDB … 
considering a class test coverage of only 24% and a method coverage of just 19% 
in the data node, we really need this.

What do you all think?


Chris

Reply via email to