Wednesday, December 14, 2016 Quick Facts

Quick facts on the numpy.ndarray object returned by

  • The array's shape is (height, width, 3)
  • The last shape value of 3 represents three color channels, in RGB order. This is important because OpenCV's imread function gives channels in BGR order.
  • The array has dtype=float32 with values in range 0.0-1.0. Again, this is important because OpenCV's imread function gives an array with dtype=uint8 with values in range 0-255.

I'm publishing this so I don't have to re-learn this "truth" every time I'm dealing with image loading and conversions.

Tuesday, December 6, 2016

What Code Belongs in an MVC Controller

The purpose of a controller is to act as a conduit between each user interaction and system response. Typically this involves three steps:

  • readRequest(). For a web server this means reading the inbound HTTP request, analyzing the headers, taking care of authorization.
  • doSomething(). Now that the server knows what it's being asked to do, the server can go ahead and do something useful.
  • writeResponse(). After the server has finished its job or kicked off a long-running process, it should write a response back to the user to let the user know how things went.

In a different sense, a controller's action method is just a wrapper for a function that executes actual business logic, a wrapper that translates an HTTP request into function args.

This setup makes sense to me, but what other approaches are there to writing good controllers? Please share your comments.

Wednesday, November 9, 2016

Install Anaconda 2 to /opt/anaconda2

By default, Anaconda 4.2 for Python 2 will install itself to the user's home directory on Linux. This is great for local development, but for server-side deployment and testing it's better to install to a shared location.

The install docs are pretty vague about how to set this up, saying simply, "Install Anaconda as a user unless root privileges are required." The way I've made this work easily on an Amazon EC2 running Ubuntu 16.04 LTS is as follows.

  1. Download the appropriate installer
  2. Install as a superuser with sudo bash
  3. Install to /opt/anaconda2 and prepend the install location to PATH in ~/.bashrc
  4. Change the target directory's group ownership to ubuntu and grant g+w permission for the directory and all its subdirectories

In short, something like this will work beautifully, allowing packages to still be installed simply using conda install or pip install.

Wednesday, July 27, 2016 vs. cv2.imdecode

Interesting note to self... the following code produces the same results, one using a chain of OpenCV methods and the other using a concise Caffe method.

Thursday, May 12, 2016

Mix Groovy and Java in STS 3.7.3.RELEASE

To mix Java and Groovy together in the same Spring Starter project, a few changes can be made to the project's properties and paths. By default, when a Java project is created it only looks for source files and test files in the src/main/java and src/test/java directories.

Add src/main/groovy to Java Build Path

  1. Create the src/main/groovy directory
  2. Right-click the project in Package Explorer, then click Properties
  3. Click Java Build Path in the left sidebar
  4. Click Add Folder... to add src/main/groovy

Add Groovy libraries to classpath

  1. Right-click the project in Package Explorer
  2. Expand Groovy, then click Add Groovy libraries to classpath

Only include groovy-all

At this point, trying to run the Spring Boot app will generate errors that look like this.

org.apache.catalina.core.ContainerBase : A child container failed during start
java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].StandardContext[]]

The errors can be resolved by removing the extra libraries STS automatically added in the previous step.
  1. Right-click Groovy Libraries in the project
  2. Click Properties
  3. Select "No, only include groovy-all" in the first panel that asks, "Should all jars in the groovy-eclipse lib folder be included on the classpath?"

Monday, May 9, 2016

Mix Groovy and Java in IntellJ IDEA

To mix Java and Groovy together in the same IntelliJ IDEA project, a simple change can be made to the project's .iml file. By default, when the project is created it only looks for source files and test files in the src/main/java directory.
By adding two sourceFolder elements IntellJ will automatically find and compile .groovy files in the Groovy directory.

Wednesday, May 4, 2016

Go to Assembla Ticket

Here's a simple JS code that can be converted into a bookmarklet to quickly open an Assembla ticket.

Saturday, April 30, 2016

HTTP/REST API Specifications

Now that I have the pleasure of designing new APIs to support both B2C and B2B use cases, my first thought is to standardize. In the case of APIs, I believe standards reduce the burden of maintenance and improve the ease of integration.

To that end, I sought to define guidelines for all operations. These are not new or novel, but I need these to set shared expectations with my team. And we start with a few core principles:

  1. Follow REST conventions for CRUD operations
  2. Use JSON in all request and response bodies (Content-Type: application/json)...
  3. Except where binary content is involved (Content-Type: multipart/form-data)

REST conventions

Striving to KISS:

Error response body

Success responses will contain appropriate data for the request, but all error response bodies look alike. At least structurally, having only one field.

  • Array<Error> errors - An array of any errors encountered while executing the operation. This field is always present for an error state (any non-200 HTTP status).

Each errors element has the following fields:

  • int code - "for programmatic consumption" (ref Braintree)
  • String message - "for human consumption" (ref Braintree)
  • String component - Whatever we're blaming for the error

Tuesday, February 2, 2016

Get Full DateTime Format (GMT) in Apex

To get the full DateTime format in GMT such that it's compatible with Apex methods like JSON.deserialize(),  the most accurate method is to call DateTime.formatGmt().

For comparison, below are some other alternatives for generating similar String values for a DateTime object.

Monday, January 11, 2016

6 Reasons You Got the Generic Error Page

Sometimes in Visualforce, you'll have debug logging enabled for a community or portal user, but loading a page fails with no trace of what went wrong. When you look in the debug log for an explanation, all you see is that Salesforce successfully loaded the Generic Error Page configured for the site.

Before logging a case or asking a fellow developer for help, check for the following 6 common culprits.

  • Are you missing any static resources, {!$Resource.__}?
  • Are you missing any custom labels, {!$Label.__}?
  • Are you missing any custom permissions, {!$Permission.__}?
  • Are you missing any page references, {!$Page.__}?
  • Are you missing any custom controller/extension properties bound on the page? This can be a problem when deploying packages among sandbox orgs.
  • Are you missing any custom controller/extension actions bound on the page?

What I've also discovered, interestingly enough, is that for some reason using MavensMate v6.0.0 with Sublime Text 3, saving a Visualforce page or component skips the validation for global variables used in Visualforce.