Skip to content

Make CRUDOptions use interface to reduce code duplications#418

Merged
dkasimovskiy merged 11 commits intomasterfrom
gh-417
Sep 26, 2023
Merged

Make CRUDOptions use interface to reduce code duplications#418
dkasimovskiy merged 11 commits intomasterfrom
gh-417

Conversation

@nickkkccc
Copy link
Copy Markdown
Contributor

@nickkkccc nickkkccc commented Sep 10, 2023

I haven't forgotten about:

  • Tests
  • Changelog
  • Documentation
  • Commit messages comply with the guideline
  • Cleanup the code for review. See checklist

Related issues:

Closes #417

@nickkkccc nickkkccc linked an issue Sep 10, 2023 that may be closed by this pull request
@nickkkccc nickkkccc requested review from ArtDu and akudiyar September 10, 2023 21:47
Copy link
Copy Markdown
Contributor

@ArtDu ArtDu left a comment

Choose a reason for hiding this comment

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

Speaking about enum and wrappers.
First of all, it is a breaking change.
The second one is why we use wrapper before enum. It makes code more complicated.

-.withMode(new ModeValue(ModeValue.WRITE))
+.withMode(ModeValue.WRITE)

I'm asking you to separate changes on two pull request:

  1. "Make CRUDOptions use interface to reduce code duplications"
  2. "Use enum for proxy client parameters"

@nickkkccc nickkkccc changed the title Make CRUDOptions unified Make CRUDOptions use interface to reduce code duplications Sep 11, 2023
Copy link
Copy Markdown
Collaborator

@akudiyar akudiyar left a comment

Choose a reason for hiding this comment

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

Overall: let's not introduce new entities (except enums) if the values do not have any special operations defined on them. IIf there is a strict necessity to do that, let's then

  1. not make the user write new every time (use factory methods like MyClass.of(value))
  2. allow the user to use simple (built-in) types where it is possible

Anyway, any such changes are breaking so let's discuss them first. We will need to explain that in a doc and ideally add a memo/page in the wiki to show the users how to fix their code after the update.

Regarding the option names: having CRUD in them is logical, but let's therefore make them easily separable from the rest driver code to eventually make a new library package only for the tarantool/crud support.

Add OperationWithAfterOptions and OperationWithFirstOptions classes.

Needed for #417.
- Add OperationWIthBatchSizeOptions class.
- Change ProxySelectOptions, SelectOptions classes.
- Add package-info.

Needed for #417.
Add asMap() general method in BaseOptions, Options classes.

Needed for #417.
- Remove CRUD<name>Options classes like a duplicates.
- Add options directly to the argument list without CRUD<name>Options class builders.
- Change Map:toString() test in the ProxyOperationBuildersTest class with EnumMap specific.
- Add test in ProxySpaceSelectOptionsIT class with after and first options.

Closes #417.
@nickkkccc
Copy link
Copy Markdown
Contributor Author

I think I was able to get rid of the duplication of the CRUDOptions classes (identical to the ProxyOptions classes) by moving the options directly into the argument list.

@nickkkccc nickkkccc self-assigned this Sep 13, 2023
Copy link
Copy Markdown
Contributor

@ArtDu ArtDu left a comment

Choose a reason for hiding this comment

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

We need to think how these changes modify cluster client working pipeline

return Optional.ofNullable((T) resultMap.get(option));
}

public Map<String, Object> asMap() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we need cope of the map only for prechecking null values? If it's true we can add null checking in addOption method and remove copying

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we need an immutable map here

import io.tarantool.driver.api.SingleValueCallResult;
import io.tarantool.driver.api.TarantoolCallOperations;
import io.tarantool.driver.api.space.options.Options;
import io.tarantool.driver.api.space.options.interfaces.Options;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If this change involves user API we need to add it as breaking change in changelog

- Add OperationWith<option-name>Options contract interfaces.
- Add ProxyOperationArgument enum class for parts of arguments list.
- Change <operation-name>ProxyOperation classes for using with contract interfaces.
- Move ProxyOperation interface from `io.tarantool.driver.core.proxy` package to `io.tarantool.driver.core.proxy.interfaces` package.

Closes #417.
@nickkkccc nickkkccc requested a review from ArtDu September 18, 2023 17:04
@ArtDu ArtDu marked this pull request as ready for review September 19, 2023 10:04
Copy link
Copy Markdown
Collaborator

@akudiyar akudiyar left a comment

Choose a reason for hiding this comment

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

Almost good, however I don't get why we need to change the package names. Would you mind elaborating a bit about the purpose of the new packages? A lines-and-boxes diagram may be useful

CHANGELOG.md Outdated
- Add "mode" option for crud select operation ([#107](https://github.com/tarantool/cartridge-java/issues/107))
- Change using of proxy client parameters (mode, rollback_on_error, stop_on_error) with enum classes ([#419](https://github.com/tarantool/cartridge-java/issues/419))

- Add `"mode"` option for crud select operation ([#107](https://github.com/tarantool/cartridge-java/issues/107))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Just "select operation" perhaps? Is we are actually making unified API not only for tarantool/crud

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good point.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just "select operation" perhaps? Is we are actually making unified API not only for tarantool/crud

Yeap, we need to separate options between proxy and cluster clients. For example I suggest to make SelectOptions without API extending only Options interface(addOption/getOption and asMap methods) because we use only these methods in inner API. But inheritance interfaces will involve specific methods like mode.

Options (interface)
  |
  V
SelectOptions (interface)
  |                                                                              |
  V                                                                              V
ProxySelectOptions (interface)                         ClusterSelectOptions (interface)

import io.tarantool.driver.api.metadata.TarantoolMetadataOperations;
import io.tarantool.driver.api.metadata.TarantoolMetadataProvider;
import io.tarantool.driver.api.space.TarantoolSpaceOperations;
import io.tarantool.driver.api.space.options.interfaces.TarantoolSpaceOperations;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why do we need to make the packet names longer?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I wanted a more organized arrangement of interfaces and classes that implement those interfaces. A contract is a contract that interfaces-options expose to classes that implement it.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

All this .api. package is about contracts. Adding more contract sub-layers here seems an overkill

return Optional.ofNullable((T) resultMap.get(option));
}

public Map<String, Object> asMap() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we need an immutable map here

@@ -1,6 +1,8 @@
package io.tarantool.driver.api.space.options;
package io.tarantool.driver.api.space.options.contracts;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What does this new package name mean, what does it give to the users?


return new DeleteProxyOperation<>(
this.client, this.functionName, arguments, this.argumentsMapper, this.resultMapper);
this.client, this.functionName, new ArrayList<>(arguments.values()), this.argumentsMapper,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why do we have that additional wrapping here? It will result in significant overhead for memory and GC time at least

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Wrapping in enummap  was required to make unification across interfaces possible. If we don't use enummap, how can we connect the parts of the argument list in the correct number and order? After all, for each operation there are parts of the argument list that are different in composition and order.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I mean the new ArrayList<>() call first of all

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I realize that calling new ArrayList<>() creates intermediate collections. But it seems to me that the same collection is created before, which is later referenced by the "final" argument list:

List<?> arguments = Arrays.asList(spaceName, indexQuery.getKeyValues(), requestOptions.asMap());
return new DeleteProxyOperation<>(
this.client, this.functionName, arguments, this.argumentsMapper, this.resultMapper);
}
}
}

Either I don't have enough experience to understand the difference between the two cases:
Master case:
List<?> arguments = Arrays.asList(spaceName, indexQuery.getKeyValues(), requestOptions.asMap());
return new DeleteProxyOperation<>(
this.client, this.functionName, arguments, this.argumentsMapper, this.resultMapper);
}
}
}

Commit case:
return new DeleteProxyOperation<>(
this.client, this.functionName, new ArrayList<>(arguments.values()), this.argumentsMapper,
this.resultMapper);
}
}
}

*
* @author <a href="https://github.com/nickkkccc">Belonogov Nikolay</a>
*/
package io.tarantool.driver.core.proxy.contracts;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Do we really need that complex package structure? I haven't seen "contracts" packages in other libraries.

Copy link
Copy Markdown
Contributor

@ArtDu ArtDu left a comment

Choose a reason for hiding this comment

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

Good job on improvement our complex API. I wrote some comments. It will be the best if you also create tickets about my notions in java doc

@nickkkccc nickkkccc requested a review from akudiyar September 19, 2023 13:39
- Fix `API changes` description.
- Fix mistype and typo in `OperationWithBatchSizeOptions` interface.
- Add notions to `Options`, `ProxyOperationArgument`, `SelectOptions`.

Closes #417.
ArtDu
ArtDu previously approved these changes Sep 19, 2023
@nickkkccc
Copy link
Copy Markdown
Contributor Author

@akudiyar, we decided not to make Map immutable for now. If necessary, we will change it in the next stages.

Copy link
Copy Markdown
Collaborator

@akudiyar akudiyar left a comment

Choose a reason for hiding this comment

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

Let's not introduce new packages like interfaces and contracts since we are already in the api package that means exactly that. Also think of the amount of changes the users will have to make in their code, will these changes be meaningful?

Also be careful about creating new objects on each call, new ArrayList<> for example is not necessary

@nickkkccc nickkkccc requested a review from akudiyar September 21, 2023 07:59
Copy link
Copy Markdown
Collaborator

@akudiyar akudiyar left a comment

Choose a reason for hiding this comment

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

See my comment above - let's discuss that verbally if you wish

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.

Make CRUDOptions use interface to reduce code duplications

4 participants