This is largely copy paste from the Basic example pallet refactor. A lot of useful information is contained there which should really be reference documentation.
I've taken these out and put them here until we have a process for reference docs. I've tried to organize them under headings to suggest the type of reference docs each piece should live under.
// # References
//
// ## Storage
//
// pallet::storage attributes allow for type-safe usage of the Substrate storage database,
// so you can keep things around between blocks.
//
// Any storage must be one of `StorageValue`, `StorageMap` or `StorageDoubleMap`.
// The first generic holds the prefix to use and is generated by the macro.
// The query kind is either `OptionQuery` (the default) or `ValueQuery`.
// - for `type Foo<T> = StorageValue<_, u32, OptionQuery>`:
// - `Foo::put(1); Foo::get()` returns `Some(1)`;
// - `Foo::kill(); Foo::get()` returns `None`.
// - for `type Foo<T> = StorageValue<_, u32, ValueQuery>`:
// - `Foo::put(1); Foo::get()` returns `1`;
// - `Foo::kill(); Foo::get()` returns `0` (u32::default()).
//
// The getter attribute generates a function on the `Pallet` placeholder to retrieve a value in storage:
// `fn getter_name() -> Type` for basic value items or
// `fn getter_name(key: KeyType) -> ValueType` for map items.
//
// ## Pallet call types
//
// Since Calls are a dispatched function there are two extremely important things to
// remember:
//
// - MUST NOT PANIC: Under no circumstances (save, perhaps, storage getting into an
// irreparably damaged state) must this function panic.
// - NO SIDE-EFFECTS ON ERROR: This function must either complete totally (and return
// `Ok(())` or it must have no side-effects on storage and return `Err('Some reason')`.
//
// The first is relatively easy to audit for - just ensure all panickers are removed from
// logic that executes in production (which you do anyway, right?!). To ensure the second
// is followed, you should do all tests for validity at the top of your function. This
// is stuff like checking the sender (`origin`) or that state is such that the operation
// makes sense.
//
// Once you've determined that it's all good, then enact the operation and change storage.
// If you can't be certain that the operation will succeed without substantial computation
// then you have a classic blockchain attack scenario. The normal way of managing this is
// to attach a bond to the operation. As the first major alteration of storage, reserve
// some value from the sender's account (`Balances` Pallet has a `reserve` function for
// exactly this scenario). This amount should be enough to cover any costs of the
// substantial execution in case it turns out that you can't proceed with the operation.
//
// If it eventually transpires that the operation is fine and, therefore, that the
// expense of the checks should be borne by the network, then you can refund the reserved
// deposit. If, however, the operation turns out to be invalid and the computation is
// wasted, then you can burn it or repatriate elsewhere.
//
// Security bonds ensure that attackers can't game it by ensuring that anyone interacting
// with the system either progresses it or pays for the trouble of faffing around with
// no progress.
//
// If you don't respect these rules, it is likely that your chain will be attackable.
//
// ## Types of calls
//
// Anyone can have these functions execute by signing and submitting
// an extrinsic. Ensure that calls into each of these execute in a time, memory and
// using storage space proportional to any costs paid for by the caller or otherwise the
// difficulty of forcing the call to happen.
//
// Generally you'll want to split callable functions into three groups:
// - **Public calls** that are signed by an external account.
// - **Root calls** that are allowed to be made only by the governance system.
// - Unsigned calls that can be of two kinds:
// - **Inherent extrinsics** that are opinions generally held by the block authors that build
// child blocks.
// - **Unsigned Transactions** that are of intrinsic recognizable utility to the network, and are
// validated by the runtime.
//
// Information about where this dispatch initiated from is provided as the first argument
// "origin". As such functions must always look like:
//
// ```nocompile
// fn foo(origin: OriginFor<T>, bar: Bar, baz: Baz) -> DispatchResultWithPostInfo { ... }`
// ```
//
// Each call must define a `#[pallet::weight(..)]` attribute to convey a set of
// static information about its dispatch. The FRAME System and FRAME Executive pallet then use
// this information to properly execute the transaction, whilst keeping the total load of
// the chain in a moderate rate.
// The `DispatchResultWithPostInfo` is required as part of the syntax (and can be found at
// `pallet_prelude::DispatchResultWithPostInfo`).
//
// There are three entries in the `frame_system::Origin` enum that correspond
// to the above bullets: `::Signed(AccountId)`, `::Root` and `::None`. You should always match
// against them as the first thing you do in your function. There are three convenience calls
// in system that do the matching for you and return a convenient result: `ensure_signed`,
// `ensure_root` and `ensure_none`.
//
// ## Helper functions
//
// A pallet can contain additional associated functions in its implementation block.
// These fall into three broad categories:
//
// - Public interface "inspector" functions. These can be called by other pallets, for e.g. to check
// some storage value.
// - Public "operation" functions. These could be used by other pallets to perform some storage operation.
// - Private functions. These are your usual private utilities unavailable to other pallets.