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

Stop setting methodNameStyle = Capitalize when useIdiomaticEndpoints is true #342

Merged
merged 7 commits into from Oct 9, 2020

Conversation

L-Lavigne
Copy link
Contributor

@L-Lavigne L-Lavigne commented Oct 2, 2020

This PR addresses sbt-mu-srcgen #93 along with an upcoming code-change PR for sbt-mu-srcgen and a documentation update PR for mu-scala.

The main functional change is that we no longer set methodNameStyle = Capitalize when useIdiomaticEndpoints is true. The flag gets the default value of true for clarity.

It does so by splitting the useIdiomaticEndpoints source-generation flag (created in mu-scala #599 to control service method capitalization and package prefixes), into 2 distinct flags with different defaults:

1) useIdiomaticGrpc which controls the namespace prefix and defaults to true;
2) useIdiomaticScala which controls the endpoint capitalization and defaults to false.

More formally, if useIdiomaticScala is true and if all the RPC call definitions in an input IDL are capitalized, the Scala methods in the services generated from this IDL will be de-capitalized, while the gRPC endpoints derived from those will be re-capitalized to match the original IDL. For example, a Protobuf IDL rpc GetBook definition becomes a Scala def getBook method inside a methodNameStyle = Capitalized service, which then generates a GetBook gRPC endpoint. A getBook IDL definition (for example from Avro) would remain unchanged (methodNameStyle = Unchanged, def getBook, and getBook gRPC endpoint).

The reason for the limitation that all RPC calls must be capitalized for the option to apply, is that we do not annotate individual methods, only the top-level @service annotation. Thus if we were to de-capitalize a mixed-capitalization group of calls and apply methodNameStyle = Capitalized to the service, some of the originally-lowercased methods would be incorrectly re-capitalized which is part of the issue we're addressing here (for example, getBook and GetBook would both become def getBook Scala and GetBook endpoints).

Note that the PR also updates the documentation, moves some test resources into the resource root, splits and renames tests between Schema, Protocol, and Cats laws classes, and normalizes the tests a bit between the Avro and Proto cases.

I'm happy to provide some more background on the "idiomatic" flag's history as I understand it, in case it helps in reviewing this change. Feel free to ask about this or anything else unclear.

This PR addresses [sbt-mu-srcgen #93](higherkindness/sbt-mu-srcgen#93) along with an upcoming code-change PR for `sbt-mu-srcgen` and a documentation update PR for `mu-scala`.

It does so by splitting the `useIdiomaticEndpoints` source-generation flag, created in [mu-scala #599](higherkindness/mu-scala#599) to control service method capitalization and package prefixes, into 2 distinct flags with different defaults:

1) `useIdiomaticGrpc` which controls the namespace prefix and defaults to `true`;
2) `useIdiomaticScala` which controls the endpoint capitalization and defaults to `false`.

More formally, if `useIdiomaticScala` is true and if _all_ the RPC call definitions in an input IDL are capitalized, the Scala methods in the services generated from this IDL will be _de_-capitalized, while the gRPC endpoints derived from those will be re-capitalized to match the original IDL. For example, a Protobuf IDL `rpc GetBook` definition becomes a Scala `def getBook` method inside a `methodNameStyle = Capitalized` service, which then generates a `GetBook` gRPC endpoint. A `getBook` IDL definition (for example from Avro) would remain unchanged (`methodNameStyle = Unchanged`, `def getBook`, and `getBook` gRPC endpoint).

The reason for the limitation that all RPC calls must be capitalized for the option to apply, is that we do not annotate individual methods, only the top-level `@service` annotation. Thus if we were to de-capitalize a mixed-capitalization group of calls and apply `methodNameStyle = Capitalized` to the service, some of the originally-lowercased methods would be incorrectly re-capitalized which is part of the issue we're addressing here (for example, `getBook` and `GetBook` would both become `def getBook` Scala and `GetBook` endpoints).

Note that the PR also moves some test resources into the `resource` root, and normalizes them a bit between the Avro and Proto cases.

I'm happy to provide some more background on the "idiomatic" flag's history as I understand it, in case it helps in reviewing this change. Feel free to ask about this or anything else unclear.
@L-Lavigne L-Lavigne added enhancement New feature or request documentation Improvements or additions to documentation breaking-change A breaking change that needs to be treated with consideration tests Improves or modifies tests labels Oct 2, 2020
@codecov
Copy link

codecov bot commented Oct 2, 2020

Codecov Report

Merging #342 into master will increase coverage by 0.11%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #342      +/-   ##
==========================================
+ Coverage   83.90%   84.02%   +0.11%     
==========================================
  Files          29       29              
  Lines        1908     1909       +1     
  Branches       27       26       -1     
==========================================
+ Hits         1601     1604       +3     
+ Misses        307      305       -2     
Impacted Files Coverage Δ
...n/scala/higherkindness/skeuomorph/mu/codegen.scala 89.01% <100.00%> (+0.12%) ⬆️
.../scala/higherkindness/skeuomorph/mu/protocol.scala 97.14% <100.00%> (ø)
.../scala/higherkindness/skeuomorph/avro/schema.scala 57.62% <0.00%> (+1.69%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update dcdc26b...07e25fa. Read the comment docs.

package higherkindness.skeuomorph

object StringUtils {
def decapitalize(s: String): String = if (s.isEmpty) s else s"${s.head.toLower}${s.tail}"
Copy link
Member

Choose a reason for hiding this comment

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

Could we use s.capitalize?

@@ -29,7 +29,7 @@ import org.apache.avro.Schema
import org.apache.avro.Schema.Type
import higherkindness.droste.{Algebra, Coalgebra}

import scala.collection.JavaConverters._
import scala.jdk.CollectionConverters._
Copy link
Member

Choose a reason for hiding this comment

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

I'm invoking @dmarticus here, as he has been experiencing some issues lately. I'm not sure if this causing binary issues in the sbt plugin side.

Copy link
Contributor

Choose a reason for hiding this comment

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

What up! I've been invoked!

Anyway, JP is right in that making this change will cause binary compat issues on the sbt plugin (specifically the sbt-mu-srcgen plugin) side, which is super obnoxious but unfortunately is something we'll have to live with until Davis finishes the work migrating away from avrohugger. Chris sums it the reasons why we have bincompat issues excellently in this comment, but a quick TL;DR is that avrohugger defines its own scala.jdk.CollectionConverters object, which means the object with the same name provided by scala-collection-compat is invisible.

In the short term, this means that we can't get rid of these 2.13 warnings until we migrate off avrohugger, but since both Lawrence and I have tried in different PRs to skeuomorph, I'm gonna write a quick issue explaining this problem and then tie that issue to the completion of the avrohugger migration task so we can make sure that we address this obnoxious warning as soon as we can.

Copy link
Contributor

Choose a reason for hiding this comment

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

issue: #343

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks @dmarticus for the explanation. Not sure why AvroHugger decided to clash that namespace, but in any case I've reverted the Converters change for now.

Copy link
Contributor

Choose a reason for hiding this comment

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

This might still be blocked after my task is done. I'm still planning on using avrohugger to generate the org.apache.avro.Protocol objects while then piping the resulting Protocols into skeuomorph. The reason for this is because avrohugger does stuff to strip out imported protocols from the final Protocol, something the native org.apach.avro.idl.Idl parser does not do which results in a giant protocol containing all imported definitions.

Copy link
Contributor

Choose a reason for hiding this comment

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

I've found that adding avrohugger as a test dependency to skeuomorph is actually causing bin incompat issues in the tests... so back to the drawing board 😩

@cb372
Copy link
Member

cb372 commented Oct 2, 2020

Maybe a silly question, but do we really need these flags?

I don't see any reason to ever disable useIdiomaticGrpc. As I understand it, including the namespace in the service name is not just "idiomatic", it's de-facto standard. I'd say the fact that Mu didn't do this originally was probably a bug.

if useIdiomaticScala is true and if all the RPC call definitions in an input IDL are capitalized, the Scala methods in the services generated from this IDL will be de-capitalized, while the gRPC endpoints derived from those will be re-capitalized to match the original IDL

This seems like an awful lot of work just to avoid a capital letter at the start of a method name. Do we have any evidence that our users actually care about this?

Maybe we can reduce complexity by being a bit more opinionated and less configurable?

@L-Lavigne
Copy link
Contributor Author

L-Lavigne commented Oct 5, 2020

Maybe a silly question, but do we really need these flags?

@cb372 After some reflection I agree about both flags. For useIdiomaticGrpc, keeping it around could help legacy services that may have grown dependent on the non-standard gRPC endpoints when calling them from outside Mu, but that should be a rare case and anyway we decided to allow a breaking change here.

As for useIdiomaticScala and the methodNameStyle flag it controls, they're mostly holdovers from when we had an IDL-generation-from-source feature and we often had idiomatic Scala methods as a source and idiomatic Protobuf as a destination. (See mu-scala #599.) It's a bit more awkward to implement in reverse as we're seeing, and perhaps a user insisting on idiomatic method names could just add a layer of indirection to the calls.

If we do get rid of that flag we may as well get rid of the methodNameStyle annotation parameter as well since there's no longer a use case where it would have a value of Capitalize. Edit: actually it might still be useful when starting from an idiomatic, non-IDL-generated Scala service, and wishing to expose capitalized gRPC endpoints to clients outside Mu. That wouldn't really make the endpoints "idiomatic" though (unlike the package-prefix addition) because capitalized methods is a Protobuf IDL convention and not strictly a gRPC one AFAIK.

Thoughts?

@cb372
Copy link
Member

cb372 commented Oct 6, 2020

So to summarise,

  • keep useIdiomaticGrpc, only for the sake of legacy users who might need it
  • lose useIdiomaticScala
  • but keep the underlying methodNameStyle flag in Mu, for people who use Mu but don't use sbt-mu-srcgen and might want the method names capitalised in gRPC

Sounds good to me, assuming my understanding is correct.

@L-Lavigne
Copy link
Contributor Author

@cb372 I removed useIdiomaticScala and kept the name useIdiomaticEndpoints for the gRPC package prefixes for maximum compatibility, and made it true by default for clarity. Please let me know if that makes sense.

@L-Lavigne L-Lavigne changed the title Split useIdiomaticEndpoints into useIdiomaticGrpc and useIdiomaticScala Stop setting methodNameStyle = Capitalize when useIdiomaticEndpoints is true Oct 9, 2020
Copy link
Member

@cb372 cb372 left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks for all the miscellaneous cleanup as well.

@L-Lavigne L-Lavigne merged commit 7e4498b into master Oct 9, 2020
@L-Lavigne L-Lavigne deleted the sbt-mu-srcgen-#93 branch October 9, 2020 22:27
L-Lavigne added a commit to higherkindness/sbt-mu-srcgen that referenced this pull request Oct 9, 2020
Depends on higherkindness/skeuomorph#342.

Also cleans up the Model by removing unused classes, and updates the tests and documentation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking-change A breaking change that needs to be treated with consideration documentation Improvements or additions to documentation enhancement New feature or request tests Improves or modifies tests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants