소스 검색

Add docs explaining generated code and its API (#39)

Motivation:

Users should be able to understand how the generated code is structured
and how it may change over time.

Modifications:

Add two docs:
1. Explain the structure of the generate code and how to navigate it.
2. Explain how the generated code may change and hot to ensure it
doesn't cause API breakages.

Result:

Better docs
George Barnett 10 달 전
부모
커밋
d35611014e

+ 78 - 0
Sources/GRPCProtobuf/Documentation.docc/Articles/API-stability-of-generated-code.md

@@ -0,0 +1,78 @@
+# API stability of generated code
+
+Understand the impact of changes you make to your Protocol Buffers files on the
+generated Swift code.
+
+## Overview
+
+The API of the generated code depends on three factors:
+
+- The contents of the source `.proto` file.
+- The options you use when generating the code.
+- The code generator (the `protoc-gen-grpc-swift` plugin for `protoc`).
+
+While this document applies specifically to the gRPC code generated and *not*
+code for messages used as inputs and outputs of each method, the concepts still
+broadly apply.
+
+Some of the concepts used in this document are described in more detail in
+<doc:Understanding-the-generated-code>.
+
+## The source .proto file
+
+The source `.proto` file defines the API of your service. You'll likely provide
+it to users so that they can generate clients from it. In order to maintain API
+stability for your service and for clients you must adhere to the following
+rules:
+
+1. You mustn't change the `package` the service is defined in.
+2. You mustn't change or add the `swift_prefix` option.
+3. You mustn't remove or change the name of any services in your `.proto` file.
+4. You mustn't remove or change the name of any RPCs in your `.proto` file.
+5. You mustn't change the message types used by any RPCs in your `.proto` file.
+
+Failure to follow these will result in changes in the generated code which can
+result in build failures for users.
+
+Whilst this sounds restrictive you may do the following:
+
+1. You may add a new RPC to an existing service in your `.proto` file.
+2. You may add a new service to your `.proto` file (however it is recommended
+   that you define a single service per `.proto` file).
+
+## The options you use for generating code
+
+Code you generate into your Swift Package becomes part of the API of your
+package. You must therefore ensure that downstream users of your package aren't
+impacted by the options you use when generating code.
+
+By default code is generated at the `internal` access level and therefore not
+part of the public API. You must explicitly opt in to generating code at the
+`public` access level. If you do this then you must be aware that changing what
+is generated (clients, servers) affects the public API, as does the access level
+of the generated code.
+
+If you need to validate whether your API has changed you can use tools like
+Swift Package Manager's API breakage diagnostic (`swift package
+diagnose-api-breaking-changes`.) In general you should prefer providing users
+with the service's `.proto` file so that they can generate clients, or provide a
+library which wraps the client to hide the API of the generated code.
+
+## The code generator
+
+The gRPC Swift maintainers may need to evolve the generated code over time. This
+will be done in a source-compatible way.
+
+If APIs are no longer suitable then they may be deprecated in favour of new
+ones. Within a major version of the package existing API won't be removed
+and deprecated APIs will continue to function.
+
+If the generator introduces new ways to generate code which are incompatible
+with the previously generated code then they will require explicit opt-in via an
+option.
+
+As gRPC Swift is developed the generated code may need to rely on newer
+functionality from its runtime counterparts (`GRPCCore` and `GRPCProtobuf`).
+This means that you should use the versions of `protoc-gen-grpc-swift` and
+`protoc-gen-swift` resolved with your package rather than getting them from an
+out-of-band (such as `homebrew`).

+ 143 - 0
Sources/GRPCProtobuf/Documentation.docc/Articles/Understanding-the-generated-code.md

@@ -0,0 +1,143 @@
+# Understanding the generated code
+
+Understand what code is generated by `protoc-gen-grpc-swift` from a `.proto`
+file and how to use it.
+
+## Overview
+
+The gRPC Swift Protobuf package provides a plugin to the Protocol Buffers
+Compiler (`protoc`) called `protoc-gen-grpc-swift`. The plugin is responsible
+for generating the gRPC specific code for services defined in a `.proto` file.
+
+### Package namespace
+
+Most `.proto` files contain a `package` directive near the start of the file
+describing the namespace it belongs to. Here's an example:
+
+```proto
+package foo.bar.v1;
+```
+
+The package name "foo.bar.v1" is important as it is used as a prefix for
+generated types. The default behaviour is to replace periods with underscores
+and to capitalize each word and add a trailing underscore. For this package the
+prefix is "Foo\_Bar\_V1\_". If you don't declare a package then the prefix will be
+the empty string.
+
+You can override the prefix by setting the `swift_prefix` option:
+
+```proto
+option swift_prefix = "FooBarV1";
+
+package foo.bar.v1;
+```
+
+The prefix for types in this file would be "FooBarV1" instead of "Foo\_Bar\_V1\_".
+
+### Service namespace
+
+For each service declared in your `.proto` file, gRPC will generate a caseless
+`enum` which is a namespace holding the generated protocols and types. The name
+of this `enum` is `{PREFIX}{SERVICE}` where `{PREFIX}` is as described in the
+previous section and `{SERVICE}` is the name of the service as declared in the
+`.proto` file.
+
+As an example the following definition creates a service namespace `enum` called
+`Foo_Bar_V1_BazService` (the `{PREFIX}` is "Foo_Bar_V1_" and `{SERVICE}` is
+"BazService"):
+
+```proto
+package foo.bar.v1;
+
+service BazService {
+  // ...
+}
+```
+
+Code generated for each service falls into three categories:
+
+1. Service metadata,
+2. Service code, and
+3. Client code.
+
+#### Service metadata
+
+gRPC generates metadata for each service including a descriptor identifying the
+fully qualified name of the service and information about each method in the
+service. You likely won't need to interact directly with this information but
+it's available should you need to.
+
+#### Service code
+
+Within a service namespace gRPC generates three service protocols:
+
+1. `StreamingServiceProtocol`,
+2. `ServiceProtocol`, and
+3. `SimpleServiceProtocol`.
+
+The full name of each protocol includes the service namespace.
+
+> Example:
+>
+> For the `BazService` in the `foo.bar.v1` package the protocols would be:
+>
+> - `Foo_Bar_V1_BazService.StreamingServiceProtocol`,
+> - `Foo_Bar_V1_BazService.ServiceProtocol`, and
+> - `Foo_Bar_V1_BazService.SimpleServiceProtocol`.
+
+Each of these protocols mirror the `service` defined in your `.proto` file with
+one requirement per RPC. To implement your service you must implement one of
+these protocols.
+
+The protocols form a hierarchy with `StreamingServiceProtocol` at the bottom and
+`SimpleServiceProtocol` at the top. `ServiceProtocol` refines
+`StreamingServiceProtocol`, and `SimpleServiceProtocol` refines
+`ServiceProtocol` (and `StreamingServiceProtocol` in turn).
+
+The `StreamingServiceProtocol` implements each RPC as if it were a bidirectional
+streaming RPC. This gives you the most flexibility at the cost of a harder to
+implement API. It also puts the responsibility on you to ensure that each RPC
+sends and receives the correct number of messages.
+
+The `ServiceProtocol` enforces that the correct number of messages are sent and
+received via its API. It also allows you to read request metadata and send both
+initial and trailing metadata. The request and response types for these
+requirements are in terms of `ServerRequest` and `ServerResponse`.
+
+The `SimpleServiceProtocol` also enforces the correct number of messages are
+sent and received via its API. However, it isn't defined in terms of
+`ServerRequest` or `ServerResponse` so it doesn't allow you access metadata.
+This limitation allows it to have the simplest API and is preferred if you don't
+need access to metadata.
+
+| Protocol                   | Enforces number of messages | Access to metadata
+|----------------------------|-----------------------------|-------------------
+| `StreamingServiceProtocol` | ✗                           | ✓
+| `ServiceProtocol`          | ✓                           | ✓
+| `SimpleServiceProtocol`    | ✓                           | ✗
+
+#### Client code
+
+gRPC generates two types for the client within a service namespace:
+
+1. `ClientProtocol`, and
+2. `Client`.
+
+Like the service code, the full name includes the namespace.
+
+> Example:
+>
+> For the `BazService` in the `foo.bar.v1` package the client types would be:
+>
+> - `Foo_Bar_V1_BazService.ClientProtocol`, and
+> - `Foo_Bar_V1_BazService.Client`.
+
+The `ClientProtocol` defines one requirement for each RPC in terms of
+`ClientRequest` and `ClientResponse`. You don't need to implement the protocol
+as `Client` provides a concrete implementation.
+
+gRPC also generates extensions on `ClientProtocol` to provide more ergonomic
+APIs. These include versions which provide default arguments for various
+parameters (like the message serializer and deserializers; call options and
+response handler) and versions which don't use `ClientRequest` and
+`ClientResponse` directly.

+ 2 - 0
Sources/GRPCProtobuf/Documentation.docc/Documentation.md

@@ -21,6 +21,8 @@ This package provides three products:
 
 - <doc:Installing-protoc>
 - <doc:Generating-stubs>
+- <doc:API-stability-of-generated-code>
+- <doc:Understanding-the-generated-code>
 
 ### Serialization