Thursday, September 18, 2014

Atrocious API Architecture (AAA)

Summary

Use the following planning, design, implementation and testing pointers to create a terrible API.

Or do the opposite of each recommendation to create an API that rocks.

PLANNING

  • Start building your app before you clearly define your system requirements
  • Do not try to understand your problem domain
  • Do not identify constraints
  • Focus on on individual steps, rather than overall system throughput
  • Do not try to improve efficiency of your biggest constraints (see previous rule)
  • Refer only the articles listed in the References section below

INTERFACE DESIGN

  • Do not use RESTful APIs
  • Use web services and assume your integration partners will not change their APIs
  • Make your API as big as possible
  • Use SOAP or better yet, roll your own request/response protocol
  • Do not apply the Fascade Pattern (expose your implementation details via your API)
  • Do not use default args, varargs, generics or enums
  • Do not version your API (change your API at will without notifying clients)
  • Never use JSON (Use a custom message protocol or at least SOAP)
  • Do not implement rate limiting (allow a single client to hog system resources)
  • Use nonsensical API operation names
  • Use inconsistent API operation names (ex: use both AddProduct and insertClient)

REQUEST DESIGN

  • Permit non SSL access to various end points
  • Require as much data as possible from your clients to satisfy simple requests
  • Never use interface types for input parameters (use classes)
  • Require generic input parameter types
  • Always use the String type for inputs and outputs
  • Expose access to all internal data fields and methods
  • Use inconsistent parameter ordering (and lots of them!)
  • Force clients to use exceptions for flow control
  • Force client to specify data type of fields in each request
  • Use session based security for long running transactions
  • Do not provide authentication options (do everything in the clear)
  • Do not notify clients when data has been modified (force them to perform bulk reads and compare)
  • Do not filter any of the fields from your database tables
  • Do not allow clients to indicate which fields they want returned in the response
  • Do not return updated_at attribute (make the client hit your API repeatedly for the same data)
  • Do not use HTTP status codes in your response

PROJECT MANAGEMENT

  • No Agile development (that's a given!)
  • Do not use project management software like Jira, Pivotal Tracker, Rational Team Concert
  • Hold hour-long meetings hourly
  • Micro manage your developers
  • Never allow time for research or prototyping
  • Assume everybody will get everything right the first time and plan accordingly

IMPLEMENTATION

  • Do not use feature branches
  • Merge all code into the single, master branch
  • Do not tag your commits with a ticket/reference number
  • Do not make your API pluggable
  • Provide the same level of service regardless of business requirements
  • Design such that small specific changes will require lots of system upgrades
  • Always copy and paste code (no code reuse!)
  • Avoid writing modular code
  • Create only mutable objects (avoid stateless design)
  • Avoid functional programming
  • Do not fail early (process as much of the request as possible before you return an error)
  • Use Java (always overload your methods and use subclassing as much as possible)
  • Fail silently when possible
  • Use only global variables
  • Use floating points for monetary values

TESTING

  • If you do test, do not try to test individual components (which would be nearly impossible, given your needlessly complicated API)
  • Do not write unit tests
  • Do not provide an API test framework for your clients to use
  • Ensure that your tests take so long to run that it is impossible for developers to test their new code before they merge it into the master branch
  • Do not document (and if you do add non-valuable comments like: // This is a loop)

References



This work is licensed under the Creative Commons Attribution 3.0 Unported License.

Thursday, September 11, 2014

Fix Go SDK Version for go-lang-idea-plugin

Problem

Go works fine from the command window, but within IntelliJ you get a message about incorrect SDK version.

Assumption

You installed Go using homebrew.

Go Environment

Here, we see that Go 1.3.1 is the current installed version:

$ go env
GOARCH="amd64"
GOBIN=""
GOCHAR="6"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/lex/dev/go/samples"
GORACE=""
GOROOT="/usr/local/Cellar/go/1.3.1/libexec"
GOTOOLDIR="/usr/local/Cellar/go/1.3.1/libexec/pkg/tool/darwin_amd64"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fno-common"
CXX="clang++"
CGO_ENABLED="1"


Fix IntelliJ Problem

The go-lang-idea-plugin reported that it expected Go version 1.3, but got 1.3.1. So, just remove 1.3 (assuming that you don't need it) and create a symlink fro 1.3 to 1.3.1:

$ cd /usr/local/Cellar/go
  /usr/local/Cellar/go $ tdml
.
├── 1.2.2 -> /usr/local/Cellar/go/1.3/
├── 1.3
│   ├── bin
│   ├── etc
│   ├── libexec
│   └── share
└── 1.3.1
    ├── bin
    ├── etc
    ├── libexec
    └── share

11 directories
  /usr/local/Cellar/go $ rm -rf 1.3
  /usr/local/Cellar/go $ ln -s /usr/local/Cellar/go/1.
1.2.2  1.3.1/
  /usr/local/Cellar/go $ ln -s /usr/local/Cellar/go/1.3.1 /usr/local/Cellar/go/1.3


Discussion

This feels like such a hack, but I could not find a way to configure the version of the Go SDK for the go-lang-idea-plugin.

If anybody finds a better solution, please let us know. Thanks!

References

http://lexsheehan.blogspot.com/2014/08/install-godoc-command.html
https://github.com/go-lang-plugin-org/go-lang-idea-plugin/blob/master/Missing%20ENV.md
https://github.com/go-lang-plugin-org/go-lang-idea-plugin/issues/696
http://brew.sh/

This work is licensed under the Creative Commons Attribution 3.0 Unported License.

Thursday, September 4, 2014

Jasmine Now Supports Pending Status

Summary

Jasmine is a BDD-style testing framework for automated testing of your web UI using headless browsers.

By default, it is configured to test Chrome and Firefox browsers.

History

Until recently, Jasmine did not allow you to indicate that any of your tests are in a pending state.

As of version 2.0, that is now possible.

Install Jasmine 2.0

You may run into issues updating your Jasmine installation.

Below, are the commands that worked for me:

$ rm -rf node_modules/karma
~/dev/angularjs/test $ npm cache clean
~/dev/angularjs/test $ npm install karma-jasmine@2_0 --save-dev
npm WARN package.json todomvc-angular-tests@1.0.0 No repository field.
npm WARN package.json karma-chrome-launcher@0.1.4 No README data
npm WARN package.json karma-phantomjs-launcher@0.1.4 No README data

> fsevents@0.2.1 install ~/dev/angularjs/test/node_modules/karma/node_modules/chokidar/node_modules/fsevents
> node-gyp rebuild

  CXX(target) Release/obj.target/fse/fsevents.o
  SOLINK_MODULE(target) Release/fse.node
  SOLINK_MODULE(target) Release/fse.node: Finished

> ws@0.4.32 install ~/dev/angularjs/test/node_modules/karma/node_modules/socket.io/node_modules/socket.io-client/node_modules/ws
> (node-gyp rebuild 2> builderror.log) || (exit 0)

  CXX(target) Release/obj.target/bufferutil/src/bufferutil.o
  SOLINK_MODULE(target) Release/bufferutil.node
  SOLINK_MODULE(target) Release/bufferutil.node: Finished
  CXX(target) Release/obj.target/validation/src/validation.o
  SOLINK_MODULE(target) Release/validation.node
  SOLINK_MODULE(target) Release/validation.node: Finished
karma@0.12.23 node_modules/karma
├── di@0.0.1
├── graceful-fs@2.0.3
├── rimraf@2.2.8
├── colors@0.6.2
├── mime@1.2.11
├── q@0.9.7
├── minimatch@0.2.14 (sigmund@1.0.0, lru-cache@2.5.0)
├── optimist@0.6.1 (wordwrap@0.0.2, minimist@0.0.10)
├── glob@3.2.11 (inherits@2.0.1, minimatch@0.3.0)
├── source-map@0.1.38 (amdefine@0.1.0)
├── lodash@2.4.1
├── useragent@2.0.9 (lru-cache@2.2.4)
├── log4js@0.6.20 (semver@1.1.4, async@0.1.15, readable-stream@1.0.31)
├── http-proxy@0.10.4 (pkginfo@0.3.0, utile@0.2.1)
├── chokidar@0.8.4 (recursive-readdir@0.0.2, fsevents@0.2.1)
├── connect@2.12.0 (uid2@0.0.3, methods@0.1.0, cookie-signature@1.0.1, debug@0.8.1, pause@0.0.1, fresh@0.2.0, qs@0.6.6, bytes@0.2.1, buffer-crc32@0.2.1, raw-body@1.1.2, batch@0.5.0, cookie@0.1.0, negotiator@0.3.0, send@0.1.4, multiparty@2.2.0)
└── socket.io@0.9.17 (base64id@0.1.0, policyfile@0.0.4, redis@0.7.3, socket.io-client@0.9.16)

karma-jasmine@0.2.2 node_modules/karma-jasmine


Test Code

Here's how to indicate that you have a Pending test:

Continuous TDD - Console Output


Notes

Instead of saying PENDING: 1 in an intuitive yellow color the console output says, "Skipped 1".

Mocha/Chai is another alternative that also works well and has a more flexible plugin architecture.

References

https://jasmine.github.io/2.0/introduction.html#section-Pending_Specs
http://lostechies.com/derickbailey/2012/08/18/jasmine-async-making-asynchronous-testing-with-jasmine-suck-less/
http://www.yearofmoo.com/2013/01/full-spectrum-testing-with-angularjs-and-karma.html
https://github.com/karma-runner/karma-jasmine
https://www.npmjs.org/package/npm-check-updates

This work is licensed under the Creative Commons Attribution 3.0 Unported License.

Thursday, August 28, 2014

Rietveld and Other Code Review Tools

Rietveld

Rietveld is a web application that manages the process of code reviews for software projects with large developer communities.

Rietveld is used today by developers of the standard distribution of the following:
  • Go (Golang)
  • Python
  • Chromium browser

Follow Golang Development

If you want to follow Go development on Rietveld, go to: golang-dev



In this example, I clicked the first issue, Issue 13454043: os/user: group lookup functions

Description


os/user: group lookup functions

Adding group lookup functions analogous to the user lookup ones to the
os/user package.
Updates issue 4589049.


Comments for src/pkg/os/user/lookup.go

Below, we see two comments:

bradfitz 2014/01/16 18:43:36
In reports whether ...



bradfitz 2014/01/16 18:43:36
let's leave this one out for now.  We can add it later if needed.  Also, the
return type is weird ([]string) ... why not []*User?

Otherwise this should clarify that it returns userids, not users.


Code and Comments for "group lookup functions" Issue


Summary

Rietveld is an effective code review tool for a large development community and it's great for groking Golang code and learning from code review comments.

However, when it comes to a typical development team, Github is good enough Typicial Github Workflow:
  1. Developer pushes changes to Github
  2. Developer creates pull request (PR) to team (sometimes needs to nudge reviewers)
  3. Reviewer accepts changes in PR and merges code from PR

Github Code Review Alternatives

Other code review alternatives include:

References

https://codereview.appspot.com/user/golang-dev
https://www.codereviewhub.com
https://code.google.com/p/gerrit

This work is licensed under the Creative Commons Attribution 3.0 Unported License.

Wednesday, August 27, 2014

Install godoc command

Installation


$ go get code.google.com/p/go.tools/cmd/godoc


Verify Installation


$ godoc fmt Println
func Println(a ...interface{}) (n int, err error)
    Println formats using the default formats for its operands and writes to
    standard output. Spaces are always added between operands and a newline
    is appended. It returns the number of bytes written and any write error
    encountered.


Alternative

A previous post, Install godoc showed you how to install the godoc package with the go instal command. This example shows you how to install the godoc command.

View Source

Add the -src flag and see the source code:

$ godoc -src fmt Println
// Println formats using the default formats for its operands and writes to standard output.
// Spaces are always added between operands and a newline is appended.
// It returns the number of bytes written and any write error encountered.
func Println(a ...interface{}) (n int, err error) {
    return Fprintln(os.Stdout, a...)
}



References

http://lexsheehan.blogspot.com/2014/07/install-godoc.htm

This work is licensed under the Creative Commons Attribution 3.0 Unported License.

Saturday, July 19, 2014

Markdown Highlighter Languages

Languagehighlight codeLanguagehighlight code
ABAPabapActionScriptas
ActionScript 3as3Adaada
ANTLRantlrANTLR With ActionScript Targetantlr-as
ANTLR With C# Targetantlr-csharpANTLR With CPP Targetantlr-cpp
ANTLR With Java Targetantlr-javaANTLR With ObjectiveC Targetantlr-objc
ANTLR With Perl Targetantlr-perlANTLR With Python Targetantlr-python
ANTLR With Ruby Targetantlr-rubyApacheConfapacheconf
AppleScriptapplescriptaspx-csaspx-cs
aspx-vbaspx-vbAsymptoteasy
BashbashBash Sessionconsole
BatchfilebatBBCodebbcode
BefungebefungeBooboo
BrainfuckbrainfuckCc
C#csharpC++cpp
c-objdumpc-objdumpcfstatementcfs
CheetahcheetahClojureclojure
CMakecmakeCoffeeScriptcoffee-script
Coldufsion HTMLcfmCommon Lispcommon-lisp
cpp-objdumpcpp-objdumpCSScss
CSS+Django/Jinjacss+djangoCSS+Genshi Textcss+genshitext
CSS+Makocss+makoCSS+Myghtycss+myghty
CSS+PHPcss+phpCSS+Rubycss+erb
CSS+Smartycss+smartyCythoncython
Ddd-objdumpd-objdump
Darcs PatchdpatchDebian Control filecontrol
Debian SourcelistsourceslistDelphidelphi
DiffdiffDjango/Jinjadjango
DylandylanEmbedded Ragelragel-em
ERBerbErlangerlang
Erlang erl sessionerlEvoqueevoque
FelixfelixFortranfortran
GASgasGenshigenshi
Genshi TextgenshitextGettext Catalogpot
GherkinCucumberGLSLglsl
GnuplotgnuplotGogo
GroffgroffHamlhaml
HaskellhaskellhaXehx
HTMLhtmlHTML+Cheetahhtml+cheetah
HTML+Django/Jinjahtml+djangoHTML+Evoquehtml+evoque
HTML+Genshihtml+genshiHTML+Makohtml+mako
HTML+Myghtyhtml+myghtyHTML+PHPhtml+php
HTML+Smartyhtml+smartyINIini
IoioIRC logsirc
JavajavaJava Server Pagejsp
JavaScriptjsJavaScript+Cheetahjs+cheetah
JavaScript+Django/Jinjajs+djangoJavaScript+Genshi Textjs+genshitext
JavaScript+Makojs+makoJavaScript+Myghtyjs+myghty
JavaScript+PHPjs+phpJavaScript+Rubyjs+erb
JavaScript+Smartyjs+smartyLighttpd configuration filelighty
Literate HaskelllhsLLVMllvm
LogtalklogtalkLualua
MakefilemakeMakefile (basemake)basemake
MakomakoMatlabmatlab
MiniDminidModelicamodelica
Modula-2modula2MoinMoin/Trac Wiki markuptrac-wiki
MOOCodemoocodeMuPADmupad
MXMLmxmlMyghtymyghty
MySQLmysqlNASMnasm
NewspeaknewspeakNginx configuration filenginx
NumPynumpyobjdumpobjdump
Objective-Cobjective-cObjective-Jobjective-j
OCamlocamlOocooc
PerlperlPHPphp
POVRaypovPrologprolog
PythonpythonPython 3python3
Python 3.0 Tracebackpy3tbPython console sessionpycon
Python TracebackpytbRaw token dataraw
RConsolerconsoleREBOLrebol
RedcoderedcodereStructuredTextrst
RHTMLrhtmlRubyrb
Ruby irb sessionrbconSsplus
SasssassScalascala
SchemeschemeSmalltalksmalltalk
SmartysmartySQLsql
sqlite3consqlite3SquidConfsquidconf
TcltclTcshtcsh
TeXtexText onlytext
ValavalaVB.netvb.net
VimLvimXMLxml
XML+Cheetahxml+cheetahXML+Django/Jinjaxml+django
XML+Evoquexml+evoqueXML+Makoxml+mako
XML+Myghtyxml+myghtyXML+PHPxml+php
XML+Rubyxml+erbXML+Smartyxml+smarty
XSLTxsltYAMLyaml

Tuesday, July 15, 2014

Custom OO Golang Error Handling

This golang code sample demonstrates the following go language features:
  • switch statement
  • classes (struct + methods)
  • variadic function
  • include timestamp in error message
  • custom error type
  • inherit behavior from base class using embedded struct

This example shows how to create a base class *** that provides consistency in error logging.

(***) Go uses structs and associated methods which provides the same functionality as a classical "class" with it's internal methods in Object Oriented (OO) programing.

You can then create error subclasses that have custom behaviors, e.g., emailing admins or sending a text message to a manager.

Having consistent error logging patterns become valuable when you use log analysis tools like Splunk.

Code Example


package main

import (
 "fmt"
 "time"
)

type Err struct {
 errNo int
 when time.Time
 msg string
}

func (e *Err) Error() string {
 return fmt.Sprintf("%v [%d] %s", e.when, e.errNo, e.msg)
}
func (err Err) errorNumber() int {
 return err.errNo
}

type ErrWidget_A struct {
 Err       // Err is an embedded struct - ErrWidget_A inherits it's data and behavior
}
// a behavior only available for the ErrWidget_A
func (e ErrWidget_A) Error() string {
 fmt.Println("do special ErrWidget_A thing...")
 return fmt.Sprintf("%s [%d] %s", e.when, e.errNo, e.msg)
}
// a behavior only available for the ErrWidget_A
func (e ErrWidget_A) optionalErrHandlingOperation() {
 fmt.Println("Email the admins...\n")
}

type ErrWidget_B struct {
 Err      // Err is an embedded struct - ErrWidget_B inherits it's data and behavior
}
// a behavior only available for the Widget_B
func (e ErrWidget_B) Error() string {
 fmt.Println("do special Widget_B thing...")
 return fmt.Sprintf("%s [%d] %s", e.when, e.errNo, e.msg)
}
// a behavior only available for the Widget_B
func (e ErrWidget_B) optionalErrHandlingOperation() {
 fmt.Println("SMS operations manager...\n")
}

func run() error {
 return &Err{
  8001,
  time.Now(),
  "generic error occurred\n",
 }
}

func run2() *ErrWidget_B {
 errB := new(ErrWidget_B)
 errB.errNo = 6001
 errB.when = time.Now()
 errB.msg = "Widget_B error occurred"
 return errB
}

func RunWidget(modelNo int) (string, error) {
 // Run valid widgets
 switch modelNo {
 case 1:
  return fmt.Sprintf("run widget model %d", modelNo), nil
 case 2:
  return fmt.Sprintf("run widget model %d", modelNo), nil
 default:
  // Error condition - unknown widget model number
  errA := new(ErrWidget_A)
  errA.errNo = 5002
  errA.when = time.Now()
  errA.msg = "Widget_A error occurred"
  return fmt.Sprintf("unable to run unknown model %d", modelNo), errA
 }
}

// Split multiple (variadic) return values into a slice of values
// in this case, where [0] = value and [1] = the error message
func split(args ...interface{}) []interface{} {
 return args
}

func main() {

 // Execute RunWidget function and handle error if necessary
 msg := ""
 // RunWidget(1) succeeds
 x := split(RunWidget(1))
 msg = "\n\n"; if x[1] != nil {msg = fmt.Sprintf(", err(%v)\n\n", x[1])}
 fmt.Printf("RunWidget(1) => result(%s)" + msg, x[0])

 // RunWidget(2) succeeds
 x = split(RunWidget(2))
 msg = "\n\n"; if x[1] != nil {msg = fmt.Sprintf(", err(%v)\n\n", x[1])}
 fmt.Printf("RunWidget(2) => result(%s)" + msg, x[0])

 // RunWidget(666) fails -
 x = split(RunWidget(666))
 msg = "\n\n"; if x[1] != nil {msg = fmt.Sprintf(", err(%v)\n\n", x[1])}
 fmt.Printf("RunWidget(666) => result(%s)" + msg, x[0])


 // Throw generic custom error type and handle it
 if err := run(); err != nil { fmt.Println(err) }

 // Throw ErrWidget_B error and handle it by printing and running optional custom behavior
 widget_B_error := run2(); if widget_B_error.errNo != 0 {
  fmt.Println(widget_B_error)
 }
 fmt.Println("")


 timeNow := time.Now()
 // Create and print ErrWidget_A, then call custom behavior
 a := ErrWidget_A {Err{5001, timeNow, "test"}}
 fmt.Println(a)  // fmt will execute Error() method that can have special behavior
 fmt.Println("A ErrWidget_A has this error number: ", a.errorNumber())
 a.optionalErrHandlingOperation()  // Widget_A emails admins

 // Create ErrWidget_B, then call custom behavior
 b := ErrWidget_B {Err{6001, timeNow, "test"}}
 fmt.Println("A ErrWidget_B has this error number: ", b.errorNumber())
 b.optionalErrHandlingOperation()  // Widget_B sends SMS message to managers
 // Since b was not printed by fmt, the special ErrWidget_B behavior is not triggered
}


Output


RunWidget(1) => result(run widget model 1)

RunWidget(2) => result(run widget model 2)

do special ErrWidget_A thing...
RunWidget(666) => result(unable to run unknown model 666), err(2014-07-15 23:58:29.852925228 -0400 EDT [5002] Widget_A error occurred)

2014-07-15 23:58:29.853084372 -0400 EDT [8001] generic error occurred

do special Widget_B thing...
2014-07-15 23:58:29.853095357 -0400 EDT [6001] Widget_B error occurred

do special ErrWidget_A thing...
2014-07-15 23:58:29.853106552 -0400 EDT [5001] test
A ErrWidget_A has this error number:  5001
Email the admins...

A ErrWidget_B has this error number:  6001
SMS operations manager...


Process finished with exit code 0


Notes

In Go, an error is something that implements an Error() function that returns a string. Here's the predefined, built-in interface type error:

type error interface {
    Error() string
}


The fmt package functions automatically call the Error() function when asked to print an error.


References

http://www.golangbootcamp.com/book/interfaces#sec-errors
https://gobyexample.com/errors
http://tour.golang.org/#58

This work is licensed under the Creative Commons Attribution 3.0 Unported License.