-
Notifications
You must be signed in to change notification settings - Fork 34
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
Concept API clean up, refactors, and bug fixes #163
Conversation
All sounds good to me! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed and left some comments.
@@ -1,16 +1,18 @@ | |||
# | |||
# Copyright (C) 2020 Grakn Labs | |||
# Licensed to the Apache Software Foundation (ASF) under one |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have a guard in checkstyle
, defined in graknlabs_dependencies
, that checks every .java
file and validates that the license is correct. If it is wrong (say, the following text is not present on line 2: Licensed to the Apache Software Foundation
), then the build fails.
Unfortunately, it does not run on our BUILD files. We should fix this in graknlabs_dependencies
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would be nice, yes. But I don't know how we could do that? 🤔
This comment has been minimized.
This comment has been minimized.
Also we should kill |
Yes, that's what we want.
Yes, that's what we expect. |
Yes, I agree! |
## What is the goal of this PR? Fix `WARNING: An illegal reflective access operation has occurred` warning caused by an out of date version of protobuf. ## What are the changes implemented in this PR? - Update protobuf to latest.
What is the goal of this PR?
Following the recent PR by @alexjpwalker (#157) which significantly changed the way Client Java has been implemented to work with Grakn Core 2.0, I've noticed there were lots of architectural and design issues that needed to be addressed before we proceed with completing the rest of the functionalities. However, this PR contains revision of the codebase that was not only written in the last PR. This PR revises the codebase that includes PRs from @adammitchelldev and some from @flyingsilverfin. The changes in this PR is important to take note for future reference during development.
What are the changes implemented in this PR?
Concept.asRemote(...)
should not take take inConcepts
, this is not as clear to the user as simpy expecting aTransaction
in which the user is already familiar with. We should keep the terms that the users need to work with as few as possibleConcepts
did not need to be split into interface and implementation. It's okay for the//concept
package to be depending on theGrakn.Transaction
interface as it is a the API interfaces, in which all packages necessarily depend on.implentation classes
insideinterfaces
. Additionally, and importantly, the interfaces in client-java will be extremely user facing and one of it's main purpose is ease-of-understanding and learnability of the API by the user. We don't want to pollute and overload the API for the user to understand.implementation
class rather than theinterface
, so that when an implementation class (e.g.AttributeImpl
) calls a constructor method on another implementation class (e.g.Thingimpl
) then the first class has access to the all the implementation methods of the second class.Class.getSimpleName()
and notClass.getCanonicalName()
ThingType.asEntityType()
.Local
concepts by default, and users must always explicity convert them toRemote
first before being able to do any "remote concept operations". Otherwise, the user will not be excplicitly aware that they're doing operations over the network - which is the goal of us introducingLocal
vsRemote
concepts in the first place. Thus, we also need not to provide theasRemote()
method on at superConcept
interface which covers bothLocal
andRemote
concepts. We only (and should only) need to provide theasRemote()
method onLocal
concepts.Local
concepts did not have theirequals()
andhash()
function defined.getType()
onThing.Local
concept in the previous PR (which is okay). However, we left theThingImpl.Local
constructor commented out and throws an exception. We should implementThing.Local
properly withoutgetType()
for now, and work on bringing it back properly in a subsequent PR.RoleType
was missingequals()
andhashCode()
function even though we know their identity depends on theirscopedLabel
RoleType
s were serialised in GRPC with theirlabel
andscopedLabel
, which is not the correct canonical representation of aRoleType
. We should just storelabel
andscope
, which would be the correct canonical representation. This would allow us to implement equality and hashing function forType
s a lot easier.ConceptProto
in theConcept
classes, we should at least be neat and consistent about it.Local
concepts were passing it entireConceptProto
objects, and parsing the values inside the constructor, butRemote
concepts were parsing the values in the static constructor methods. We should stick with one style.scope
orscopedLabel
inConceptMethod.Type.Req
andConceptMethod.Type.Req
which means that concept methods called fromRoleType
s would fail.RoleType.Remote
was missinggetSupertype()
and was mistakenly provided the methodsetSupertype(...)
TypeImpl.Remote
implementedgetSupertypes()
andgetSubtypes()
but notgetSupertype
and instead providedgetSupertypeInternal(constructorFn)
andsetSupertypeInternal(constructorFn)
. First, we don't needgetSupertypes()
andgetSubtypes()
atTypeImpl.Remote
. Second, we should be consistent and provide the same style API - this should have been the code smell.default
case in aswitch
should come last in the order of cases.asRemote(tx)
methods ofRemote
concepts should not simply return itself (this
) without considering the transaction argument. What if the user passes a new transaction object? If we don't expect this, then we should throw an exception, but we shouldn't simply ignore the argument. I think we should create a newremote
concept object with the new transaction.Additionally:
2.0.0
TODO (to follow up on after this PR):
ErrorMessage
instance. For example"'%s' can not be null or empty."
with codeCIN2
was used for missing IIDs, labels, and database names. The problem with this approach is that now error codes no longer uniquely identify the problem/bug that caused the exception, which was the point of our newErrorMessage
architecture utilising error codes.ThingType.Local.asThingType()
andThingType.Remote.asThingType()
should simply implemented in the implementation class, rather than implemented as adefault
method in the interface. This way we can minimise the number of methods to document on the interfaces.EntityType
: theEntityType.Remote
interface already extendsThingType.Remote
andEntityType
. Which means it does not depend onEntityType.Local
at all. When users query for a concept the first time, they always getEntityType.Local
concept, but would naturally be simply assigned toEntityType
as users won't expect to declare their variables asEntityType.Local
. And given that we want allow the user to get the "stored" / "local" fields immediately, we declare these fields at the parent interface (right now this only applies toAttribute
which providesgetValue()
. The fact thatEntityType.Remote
extendsEntityType
also allows us to retrieve any "stored"/"local" fields even from aRemote
concept. But given all the above, we can see that there's no need to have aLocal
sub interface for every concept type. We can simply treat the main interface, such asEntityType
in this case, to be the "local" concept, and when we callasRemote(tx)
it converts toEntityType.Remote
concept, which would be extendingEntityType
.Grakn.client(...)
builder method on the main interface? We already know that it's not ideal that the interface depends on the implementation (grakn.core.client.rpc.RPCClient
) to achieve this, but now we also found out that this restricts our users to have to be using Java 8 and higher. I think there's a strong case now to keep the UX to be:Grakn.Client client = new GraknClient(...)
; where the user also has toimport grakn.core.client.rpc.GraknClient
.