Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(26)

Unified Diff: doc.go

Issue 1247283003: Improve docs (Closed) Base URL: https://github.com/luci/gae.git@reduce_size
Patch Set: rebase Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | filter/count/count.go » ('j') | impl/dummy/doc.go » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: doc.go
diff --git a/doc.go b/doc.go
index 2704e4c15b83786e22c7f224e9696500b9e5f8b4..1508448080c91efd7b2f6ccdbed1577181fce6bd 100644
--- a/doc.go
+++ b/doc.go
@@ -6,26 +6,128 @@
// APIs. This means that it's possible to mock all of the supported appengine
// APIs for testing (or potentially implement a different backend for them).
//
+// Features
+//
// gae currently provides interfaces for:
-// * RawDatastore (a less reflection-magic version of Datastore)
-// * Memcache
-// * TaskQueue
-// * GlobalInfo (e.g. Namespace, AppID, etc.)
-//
-// A package which implements the gae is expected to provide the following:
-// * A package function `Use(c context.Context, ...) context.Context`
-// This function is expected to add any information to c which is necessary
-// for the rest of its implementations to work. This may be something like
-// an `appengine.Context` or some connection information for an external
-// server. The `...` in the function signature may be any additional data
-// needed (or it may be empty).
-//
-// * Partially-implemented interfaces should embed one of the dummy
-// implementations in the `dummy` subpackage which will panic with
-// an appropriate error for unimplemented methods.
-//
-// see "infra/gae/libs/gae/prod" for an appengine-backed implementation.
-// see "infra/gae/libs/gae/memory" for an in-memory implementation.
+// - RawDatastore (a less reflection-magic version of Datastore)
+// - Memcache
+// - TaskQueue
+// - GlobalInfo (e.g. Namespace, AppID, etc.)
+//
+// In addition, it provides a 'Datastore' service which adds all the reflection
+// magic of the original SDK's datastore package on top of RawDatastore.
+//
+// Additional features include:
+// - true service interfaces (not package-level functions)
+// - methods don't need explicit context passed to them, increasing readability.
+// - service filters allow for composition of functionality. For example:
+// - transparent memcaching of datastore access
+// - transparent transaction buffering
+// - statistics-gathering shims
+// - deterministic and probabalistic API failure simulation
+// - transparent retries
+// - truly parallel in-memory testing implementation. No more need for
+// dev_appserver.py subprocesses :).
+//
+// Package Organiaztion
estaab 2015/07/23 04:43:11 Organization
iannucci 2015/07/23 05:55:10 Done.
+//
+// The gae library is organized into several subpackages:
+// - service/* supported service definitions
+// - impl/* implementations of the services
+// - filter/* extra filter functionality for the services, agnostic to the
+// underlying implementation.
+//
+// TLDR
+//
+// In production, do:
+//
+// import (
+// "fmt"
+// "net/http"
+//
+// "github.com/luci/gae/impl/prod"
+// "github.com/luci/gae/service/rawdatastore"
+// "golang.org/x/net/context"
+// )
+//
+// func handler(w http.ResponseWriter, r *http.Request) {
+// c := prod.UseRequest(r)
+// // add production filters, etc. here
+// inner_handler(c, w)
+// }
+//
+// func inner_handler(c context.Context, w http.ResponseWriter) {
estaab 2015/07/23 04:43:11 innerHandler
iannucci 2015/07/23 05:55:10 Done.
+// rds := rawdatastore.Get(c)
+// data := rawdatastore.PropertyMap{
+// "Value": {rawdatastore.MkProperty("hello")},
+// }
+// newKey, err := rds.Put(rds.NewKey("Kind", "", 0, nil), data)
+// if err != nil {
+// http.Error(w, err.String(), http.StatusInternalServerError)
+// }
+// fmt.Fprintf(w, "I wrote: %s", newKey)
+// }
+//
+// And in your test do:
+//
+// import (
+// "testing"
+// "fmt"
+// "net/http"
+//
+// "github.com/luci/gae/impl/memory"
+// "github.com/luci/gae/service/rawdatastore"
+// "golang.org/x/net/context"
+// )
+//
+// func TestHandler(t *testing.T) {
+// t.Parallel()
+// c := memory.Use(context.Background())
+// // use rawdatastore here to monkey with the database, install
+// // testing filters like featureBreaker to test error conditions in
+// // inner_handler, etc.
+// inner_handler(c, ...)
+// }
+//
+// Service Definitions
+//
+// A service defintion lives under the `service` subfolder, and defines the
+// user-facing interface for a service. Each service has a few common types and
+// functions. Common types are:
+//
+// service.Interface - the main service interface
+// service.Testable - any additional methods that a 'testing' implementation
+// should provide. It's expected that tests will cast
+// the Interface from Get() to Testable in order to
+// access these methods.
+// service.Factory - a function returning an Interface
+// service.Filter - a function returning a new Interface based on the
+// previous filtered interface.
+//
+// And common functions are:
+// service.Get - Retrieve the current, filtered Interface
+// implementation from the context. This is the most
+// frequently used service function by far.
+// service.AddFilters - adds one or more Filters to the context.
+// service.SetFactory - adds a Factory to the context
+// service.Set - adds an implementation of Interface to the context
+// (shorthand for SetFactory, useful for testing)
+//
+// Implementations
+//
+// The impl subdirectory contains a couple different service implementations,
+// depending on your needs.
+//
+// 'prod' is the production (e.g. real appengine-backed) implementation. It
+// calls through to the original appengine SDK.
+//
+// 'memory' is a truly parallel in-memory testing implementation. It should
+// be functionally the same as the production appengine services, implementing
+// many of the real-world quirks of the actual services. It also implements
+// the services' Testable interface, for those services which define those
+// interfaces.
+//
+// Usage
//
// You will typically access one of the service interfaces in your code like:
// // This is the 'production' code
@@ -54,23 +156,26 @@
// }, nil)
// }
//
-// RawDatastore struct serialization is provided by the `helper` subpackage. All
-// supported struct types and interfaces are provided in this package, however.
-// You can operate without any struct serizialization/reflection by exclusively
-// using DSPropertyMap. A goon-style Datastore interface is also provided in the
-// `helper` subpackage.
+// RawDatastore struct serialization is provided by the `rawdatastore`
+// subpackage. All supported struct types and interfaces are provided in this
+// package, however. You can operate without any struct
+// serizialization/reflection by exclusively using PropertyMap. A goon-style
+// Datastore interface is also provided in the `datastore` service package.
+//
+// Filters
//
// Each service also supports "filters". Filters are proxy objects which have
// the same interface as the service they're filtering, and pass data through to
// the previous filter in the stack. Conceptually, a filtered version of, for
// example, the RawDatastore, could look like:
-// User
-// <mcache filter (attempts to use memcache as a cache for datastore)>
-// <count filter (keeps a conter for how many times each API is used)>
-// Memory RawDatastore (contains actual data)
+// User code
+// <count filter (counts how many times each API is called by the user)>
+// <mcache filter (attempts to use memcache as a cache for rawdatastore)>
+// <count filter (counts how many times each API is actually hit)>
+// memory RawDatastore implementation
//
-// So GetRDS would return the full stack, and GetRDSUnfiltered would only
-// return the bottom layer. In code, this would look like:
+// So rawdatastore.Get would return the full stack. In code, this would look
+// like:
// func HTTPHandler(r *http.Request) {
// c := prod.Use(appengine.NewContext(r)) // production datastore
// c, rawCount := count.FilterRDS() // add count filter
@@ -82,6 +187,6 @@
// of the count filter, it returns its state from the Filter<Service> method,
// and the state can be observed to see how many times each API was invoked.
// Since filters stack, we can compare counts from rawCount versus userCount to
-// see how many calls to the actual real datastore went through, v. how many
+// see how many calls to the actual real datastore went through, vs. how many
// went to memcache, for example.
package gae
« no previous file with comments | « no previous file | filter/count/count.go » ('j') | impl/dummy/doc.go » ('J')

Powered by Google App Engine
This is Rietveld 408576698