REST Services for my Model Framework

Fri Jun 06 09:55:01 EDT 2014

Tags: framework

Recently, I've been refactoring out my framework code from XPages Scaffolding into an OSGi plugin. Part of this is just to help with code reuse and versioning: having a whole bunch of framework classes in each NSF is a drag, both from a perspective of having a bunch of extra stuff in the NSF and for having to worry about keeping them up to date (a template would work, but eh...). But another part is that it lets me work on some new features I've been itching to try.

One of those is adding REST services for model objects. Having access to your data via REST+JSON is pretty important, whether you're using Angular.JS, iOS, or miscellaneous. The Data service in the ExtLib does a great job of exposing document and view data directly, but it runs into the same problem that the standard data sources in XPages do: it doesn't have any provisions for your specific domain models. On the XPage side, I've solved this for myself by making a model framework that has done a fine job so far of covering my needs for accessing and collecting data in a pretty friendly way, and now I'm working on building REST APIs "for free".

Using the DAS as an inspiration (both in a vague sense and in a "using the code" sense), I'm working on Wink services to provide access to the model objects defined in each DB in a way that uses all of the same getters/setters with almost no changes to the code. The only change required (at least so far) is an optional annotation to define which fields should be included when accessing the object via REST. I'm aiming to match the data formats used by DAS as much as makes sense, since they're well-thought-out for representing Domino-friendly data, though the URLs will be pretty different due to the nature of my model manager objects.

This has been going well so far, and I'm looking forward to having it fully fleshed out. It should allow me to continue defining my model objects the same way I have been for use in XPages/Java, but then also be able to access the data just as well from other front-end technologies - potentially having NSFs that contain just a set of model definitions to act as a headless API app for use with other clients. And hey, if I get around to adding non-Domino backends to the model framework, the NSF would turn into a platform-agnostic gateway for data access.

Be a Better Programmer, Part 3

Thu Jun 05 11:06:03 EDT 2014

Tags: performance
  1. Be a Better Programmer, Part 1
  2. Be a Better Programmer, Part 2
  3. Be a Better Programmer, Part 3
  4. Be a Better Programmer, Part 4
  5. Be a Better Programmer, Part 5

After a break last week, this week's entry returns a bit to practical concepts. Specifically:

Develop a Working Knowledge of Relative Speeds

Performance of an app depends on almost-countless factors, but I've found that you mostly just need to know a few general ideas and rules of thumb to avoid the real pitfalls.

Big O Notation

The first thing to have a general working knowledge of is the naively-named Big O notation. This is one of the core concepts in a Computer Science curriculum and is often one of the more "mathy" subjects when you learn it. However, for the level of programming we do, it mostly serves as a warning to not loop too much. Specifically, avoid this sort of thing when possible:

for(int i = 0; i < someLength; i++) {
	for(int j = 0; j < someLength; j++) {
		// some stuff here
	}
}

That's O(n²): the amount of times that the inner loop runs grows quadratically with the size of "someLength", and it's among the worst things you can do. I recommend looking around for some basic introductions to the concept, such as this article. One thing to remember with Big O notation is that it's a general guide, not a hard-and-fast rule: an O(n²) algorithm may be faster than an O(1) if what the latter is actually doing is really slow in some other way.

I/O Overhead

Another key thing to keep in mind is that the difference between "levels" of activity - in-memory, DB access, etc. - is often so great that it completely dwarfs any other complexity. For example, it's usually going to be significantly faster to sort/search/mangle a data structure in memory many times over than to access a database even once. As with Big O, this is sort of a fuzzy rule, but I tend to keep a couple order-of-magnitude levels in mind:

  1. In-memory structure access
  2. Efficient database access (open connection, in-memory)
  3. Filesystem access
  4. Remote database/service access (e.g. web services)

#2 and #3 probably go back and forth in performance in different contexts, but any filesystem use is "dirty" enough conceptually that I downgrade it just for that.

This is why caching and minimizing database access is so important. The Domino programming environment makes it feel like the database is there "for free", but it has all the same pitfalls. Say you have a basic List of Maps in Java and the same data stored in a view in Domino, and you want to do what amounts to a keyed lookup. Even though the algorithm for doing a lookup by key in Domino is (presumably) very efficient from a Big O perspective, even a linear search through the List in memory is going to run laps around it.

There are, naturally, limits: some database operations are particularly fast and some in-memory algorithms are particularly slow.

Platform Knowledge

And in addition to the rules of thumb, sometimes it's best to just know a lot about the platform you're working with. Sometimes this comes with a knowledge of the general type of platform (e.g. key/value lookup in a document DB is fast, "relational" activity is not), and sometimes it just takes hands-on experience.

Fortunately, this becomes self-reinforcing as you learn it. Once you run across severe pitfalls (say, db.Search or using @Now in a view), you develop sort of a visceral revulsion to using it again except when it's the only option. Eventually, you build up enough working knowledge and callouses that it becomes second nature.


Once you have a good grasp of what is and isn't quick, it can really help you structure your programs more effectively. Not only does it help you write faster-executing code, but it also helps you understand when it does and does not matter: if you have code that will only execute once, you can intentionally forgo a faster-but-harder-to-maintain algorithm in favor of a clear-but-moderately-slower one as long as you know you're not falling off a performance cliff. That balance between writing for the computer and writing for other programmers is one of the crucial things to strive for.

Swift

Wed Jun 04 20:52:28 EDT 2014

Tags: swift

This is a topic that doesn't really fit my usual bailiwick of Domino programming, nor is it something I'm particularly qualified to comment on, since the most Objective-C programming I've ever done was some putzing around years and years ago with a weird idea for a pseudo-database that didn't even involve Cocoa, but I'm going to talk about it anyway.

I'm really excited about Swift.

In case you don't follow Apple circles, Swift was one of the fire hose of announcements at WWDC on Monday. It's a new programming language designated to replace Objective-C, billed as "Objective-C without the C", and can be thought of as Apple's Go.

So why am I so excited about it? Part of it is that I've been flirting with the notion of diving into Cocoa development proper, and this provides a perfect impetus. But beyond that, it tickles my programmer brain in a great many ways.

Low level + dynamic

The primary thing that piques my interest is the way it blends the best of what in olden days were referred to as "systems" and "scripting" languages. It's not the first language to do so, but it'll be among the few to get widespread adoption. It's C without pointers (mostly); it's functional programming without the Lisp; it's Objective-C without the brackets and @s; it's Ruby/Python without the speed loss; it's ML/Haskell/etc. without the "what the hell is this?".

What this means in practice is that it doesn't shy away from syntactic sugar. It's extremely common to want to make literal arrays and maps (Dictionaries in Cocoa parlance), and so Swift has clean syntax for those. They want to really emphasize closures, so the syntax gets cleaner the simpler the task is. They want strong typing, so they use type inference to get the result without all the "oh, come on, you know what I mean!" feeling you get from writing Java.

Good for programmers and compilers

It's striking just how many of the syntactic sugar bits and the defaults of the language are geared both towards improving programmers' lives (with easier code and bug prevention) and improving compiler optimization. It seems like it's a product of the modern state of compilers: whereas C was made during the infancy of computing and is designed to allow the programmer to really turn the screws in tons of crazy ways (see: pointer arithmetic), Swift is designed to take advantage of the fact that the bounds for what makes a good program are now well-known, and by restricting "dangerous" operations, the code is not only safer but also much more predictable.

One example of this is something that most current languages have adopted: for-all loops. In languages without them, it's contingent on the programmer to write the looping logic themselves. In pre–for-all Java, for example, this meant either using array indexes or Enumerators/Iterators. Those ranged from sort of a pain and potentially inefficient (indexes) to probably fast but horrendously ugly (the others). But for-all loops fix that: not only is the syntax much easier to type and is much clearer in intent, but now the compiler can choose the most appropriate method of iteration.

Swift is full of this, from its focus on immutability to its use of the "override" keyword to its integration of functional-programming idioms.

Type inference

I mentioned this already, but it deserves its own section. I've long had a very conflicted view on type systems. On the one hand, I appreciate the values of a Java-style strict type system - the consistency, the prevention of errors, the self-documentating nature - but good lord is Java a huge PITA to actually write sometimes. I can't even count how many times I've written a line like this:

List<Map<String, Object>> someListOfMaps = new ArrayList<Map<String, Object>>();

Gahhhhh. Every time! Never versions of Java have improved on this (though we as Domino programmers likely won't see that for a while), but it's still a drag. Moving to a strongly-typed-but-declaration-free language like Ruby is such a breath of fresh air. Not because I specifically want to assign objects of different types to the same variable, but because I don't have to fight the compiler over nuts-and-bolts of getting the right class name down.

The kind of type inference Swift uses makes Java-style strictness palatable. You get all the benefits of strict typing, both to you and to the compiler, without having to write "Map" five hundred times per source-code file.

LLVM as .NET or the JVM

LLVM is the just-above-the-metal virtual machine that Apple uses on its devices, and this sort of marks its coming-out party as a multi-language platform in the vein of .NET or the JVM. Swift files compile down to the same object types as Objective-C, so you can mix and match them in the runtime, much as you could mix and match multiple .NET languages or Java and Scala. In practice, this means that diving into it in an existing Cocoa app is much easier than having to rewrite the whole thing, while it also means that someone like me who isn't well-versed in the framework can still make use of the decades of Objective-C knowledge online.

Conclusion

So in conclusion: I'm just real excited. This looks fun! It's like a best-of setlist from all modern languages built on top of a giant framework that lets you build apps immediately. You should give it a look too - at the very least, watch the end of the WWDC keynote, where it was introduced.

Coaxing Enums Into XPage Combo Boxes

Wed May 28 19:07:12 EDT 2014

Tags: java xpages

I've been reworking Forms 'n' Views over the last couple days to use it as a development companion for the OpenNTF Design API, and one of the minor hurdles I ran across was presenting a getter/setter pair that expects a Java Enum to an XPages control (a combo box in this case, but it would be the same with other similar controls). I had assumed at first that it would simply not work - that the runtime would entirely balk at the conversion. However, it turned out that XPages does half the job for you: for displaying existing values, it will properly coax between the string form and the Enum constant. However, it breaks when actually going to set the value.

This whetted my appetite enough that I decided to try to see if I could write a small converter to finish the job in a properly generic way, and it turns out I could. To cut to the chase, I wrote this class:

package converter;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.el.ValueBinding;

public class EnumBindingConverter implements Converter {

	@SuppressWarnings("unchecked")
	public Object getAsObject(final FacesContext facesContext, final UIComponent component, final String value) {
		ValueBinding binding = component.getValueBinding("value");
		Class<? extends Enum> enumType = binding.getType(facesContext);

		return Enum.valueOf(enumType, value);
	}

	public String getAsString(final FacesContext facesContext, final UIComponent component, final Object value) {
		return String.valueOf(value);
	}

}

The getAsString method is your standard "I don't care about this" near-passthrough, but the getAsObject portion does the work necessary. Because I'm binding to a Java bean with getters/setters expecting the appropriate Enum type (this would presumably also work with a DataObject with a thoroughly-implemented getType method), the ValueBinding class is able to look up and provide back the expected Enum class. I then use the standard Enum.valueOf method to let Java do the work of actually finding the appropriate Enum constant.

Using this, I'm able to write a control like this:

<xp:comboBox value="#{columnNode.sortOrder}">
	<xp:this.converter><xp:converter converterId="enumBindingConverter"/></xp:this.converter>
	<xp:selectItem itemLabel="None" itemValue="${javascript:org.openntf.domino.design.DesignColumn.SortOrder.NONE}" />
	<xp:selectItem itemLabel="Ascending" itemValue="${javascript:org.openntf.domino.design.DesignColumn.SortOrder.ASCENDING}"/>
	<xp:selectItem itemLabel="Descending" itemValue="${javascript:org.openntf.domino.design.DesignColumn.SortOrder.DESCENDING}"/>
</xp:comboBox>

And it works! That allows you to bind to a getter/setter pair that expects an Enum without having to write in a shim to convert it to a String value beyond the generic converter.

You probably noticed the same thing I did, though: that's ugly as sin. Not only that, but it's a lot of redundant code when what you usually want to do is provide a selection of all available constants for the given Enum. To save myself a bit of future hassle and prettify my code a bit (at the expense of UI, but who cares about that? (I kid)). I wrote this DataObject bean to accept an Enum class name and return a list suitable for use in a control:

package bean;

import java.io.Serializable;
import java.util.*;

import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;

import org.openntf.domino.utils.Strings;

import com.ibm.xsp.model.DataObject;

import frostillicus.bean.*;

@ManagedBean(name="enumItems")
@ApplicationScoped
public class EnumSelectItems implements Serializable, DataObject {
	private static final long serialVersionUID = 1L;

	public Class<?> getType(final Object key) {
		return List.class;
	}

	@SuppressWarnings("unchecked")
	public List<SelectItem> getValue(final Object key) {
		if(key == null) {
			throw new NullPointerException("key cannot be null.");
		}

		String className = String.valueOf(key);

		try {
			Class<? extends Enum> enumClass = (Class<? extends Enum>)FacesContext.getCurrentInstance().getContextClassLoader().loadClass(className);

			Enum[] vals = enumClass.getEnumConstants();
			List<SelectItem> result = new ArrayList<SelectItem>(vals.length);
			for(Enum val : vals) {
				SelectItem item = new SelectItem();
				item.setLabel(Strings.toProperCase(val.name()));
				item.setValue(val);
				result.add(item);
			}

			return result;
		} catch(Throwable t) {
			throw new RuntimeException(t);
		}
	}

	public boolean isReadOnly(final Object key) {
		return true;
	}

	public void setValue(final Object key, final Object value) { }
}

It uses the @ManagedBean implementation that I cobbled together a while back, but you could just as easily use the normal faces-config route. The way you use this is to pass in the class name of the Enum you want in a selectItems component:

<xp:comboBox value="#{columnNode.sortOrder}" onchange="fnv_mark_dirty('#{id:viewPane}')">
	<xp:this.converter><xp:converter converterId="enumBindingConverter"/></xp:this.converter>
	<xp:selectItems value="${enumItems['org.openntf.domino.design.DesignColumn$SortOrder']}"/>
</xp:comboBox>

Though it only saves a few line in this case, it'd pay off more with larger Enums. It has the down side of being pretty naive about its conversions: it just does a basic first-character proper-casing of the Enum constant name, but there's no reason you couldn't add better human-friendly-ifying to it.

I'm not sure if I'll be able to satisfy all of my Java preferences when it comes to multi-value Enums, though. Java's generic type erasure means that runtime code wouldn't have a way to inspect the getters/setters to figure out the appropriate Enum type. Perhaps I can inspect the select items attached to the control to find the appropriate class.

Code for Tim: LESS CSS for XPages

Sun May 25 16:39:10 EDT 2014

When OpenNTF announced the "Code for Tim" initiative, I browsed Tim's GitHub repository list and one stuck out to me: the "xspless" stub repository for adding LESS CSS support to XPages. I'd latently wished for this sort of feature for a while, but hadn't yet set out down the path. It seems Tim had had the same desire, and had taken at least one more step than me.

I've decided to try my hand at making this desire a reality, and it's borne some fruit so far. I've created a fork of his project to house my attempts:

https://github.com/jesse-gallagher/xspless

So far, I've made functional drafts of two tacks:

  • A servlet plugin for Domino, in the "org.openntf.xsp.less" and ".feature" projects. This servlet is available at "/xspless" within each database (behavior outside of a database is not handled) and it processes the named file (can be a Stylesheet resource, File Resource, or file in WebContent) just-in-time and delivers the result as normal CSS
  • A builder plugin for Designer, in the "org.openntf.xsp.less.builder" and ".feature" projects. This builder adds a new Eclipse Nature to Designer (activated per-project by right-clicking the app and choosing "Add/Remove LESS CSS Nature") that compiles Stylesheet resources named in the form of "foo.less.css" (Designer automatically appends the ".css") and other File or WebContent resources named in the form of "foo.less" and stores the compiled results in the NSF

My ideal goal would be the ability to write .less files in Designer without any plugins and have the server treat them as normal CSS files with pre-processing, including them in resource-aggregation chains. Since I don't currently know how to have files processed on the fly and also included in aggregation, I created the two routes, with the latter being the likely-preferred route. Though it requires installing a plugin on each developer's system, it has the distinct advantage of the resultant files working perfectly with the normal resource aggregation pipleline of the server.

In their current state, these plugins seem to do their job. If I find out a way to hook into the resource chain on the server transparently, I'll look to improve the server plugin, but for now the Designer plugin seems promising. I plan to give a shot to using it for normal development; it will likely be a refreshing change of pace to be able to use LESS to write cleaner CSS. After a bit of testing, I'll likely create a project on OpenNTF.

Be a Better Programmer, Part 2

Thu May 22 12:38:32 EDT 2014

Tags: philosophy
  1. Be a Better Programmer, Part 1
  2. Be a Better Programmer, Part 2
  3. Be a Better Programmer, Part 3
  4. Be a Better Programmer, Part 4
  5. Be a Better Programmer, Part 5

For this week's installment, I'd like to cover a more abstract topic than last time:

Develop a Philosophy of Programming

By this grandiose title I don't mean that your outlook on programming has to be an answer to life, the universe, and everything (though tell me if it is), but more that it's useful to know why you do what you do. Why are you a programmer? I'm assuming it's not because of a particular love for "delivering" "enterprise" "workflow" "solutions".

In my case, it's because I find the act of programming to immensely joyful (even when it's a pain). The best times are when I'm working on something and my brain is just saying "This is awesome" - whether the actual end product remains awesome is largely immaterial; it's more the act of creating it. Good thing, too, since another part of the joy is figuring out why the stuff I did before is awful in light of a new idea I've had.

The most influential thing I've read on the notion of programmer identity is Paul Graham's Hackers and Painters. His numerous other essays are also generally worth a read, but that one has stuck with me. The crucial aspect is that he aligns programmers' personalities with those of artists (over-reduced to "painters") rather than the scientists and mathematicians that Computer Science grew up with. Over the years, I've spent a lot of time thinking about where programming fits in the pantheon of professions, and I think the essay is mostly right. Certainly, programmers share a lot of traits with mathematicians (pedantry, for one), but otherwise the math/science basis of programming is something of an implementation detail. The real beating heart of programming is the joy of creating - or even just the joy of tinkering and trying, of discovering the contours of the medium.

Deciding on your philosophy of programming, whether it matches mine or takes a different path, isn't something that directly assists your day-to-day work, but I think it informs the whole. Having this sense of identity gives me a solid feeling of why I'm doing what I'm doing and an intrinsic motivation to do it properly. It helps push me to elevate my code past "the first thing that works" and into an intentionally-crafted product. Far from being a flighty academic exercise, thinking this sort of thing through has bolstered my consistent drive to improve.

For-fun Project: NSF StateManager

Tue May 20 17:25:51 EDT 2014

Earlier this year, I created a StateManager for XPages using Couchbase as a back end. Mostly, this was just to give myself an excuse to mess around with XPages internals and Couchbase. But even still, it had an interesting characteristic: by storing the state of an XPage between requests in a location available to multiple servers, the XPages became cluster-friendly - you could load an XPage on one server and make later requests to another (though it would take further work to handle other scopes).

I was prompted today by a discussion on the possibilities of this sort of thing to go back to that code and adapt it to storing the data in Domino. The initial work was pretty straightforward: using the baked-in Database#getDocumentByKey and MIMEBean capabilities of the OpenNTF Domino API, the same key-value concepts I used for the Couchbase version transferred neatly. At that point, I had the same cool cluster/failover-friendliness as before, but now using NSF for storage.

But then Nathan egged me on further: he pointed out that there's no reason to stop at just storing the last state; I could store every revision. Suddenly, a world of possibilities are open: an audit trail of page state, the ability to view this trail from externally (tied to context information like DB path and username), and the ability for the user to step back through the tree. I set to implementing that last one immediately:

(Download)

If you'll forgive the off-by-one problem in the history display and the sparse layout, you can see it in action: the user is able to revert the view to a previous state, with the entire viewScope coming along for the ride. Additionally, I realized I could store this traversal history as a tree (I told you they come in handy) to visualize the act of a user stepping back in state and creating a new branch from there:

Domino State Viewer

Currently, this is largely of nerdy-interest concern, but there are a lot of ways this could be built up into a real useful tool. Users could have a built-in "undo" tool (assuming you're undoing actions without external side effects), an admin could see the specific actions taken and buttons clicked by a user using a page, the app could peer into the state of all users using a given page to present a collaborative UI, and so forth.

I created a "Miscellany" project on GitHub intended to house pie-in-the-sky one-offs/test projects like this, and so the curious can find the code there:

https://github.com/jesse-gallagher/Miscellany

The DSAPI Login Filter I Wrote Years Ago

Mon May 19 15:02:18 EDT 2014

Tags: dsapi c

In one of the conversations I had at the meetup yesterday, I was reminded of the DSAPI filter I use on my server for authentication, and remembered I'd yet to properly blog about it.

Years ago, I had a problem: I was setting up an XPages-based forum site for my WoW guild, and I wanted sticky logins. Since my guildies are actual humans and not corporate drones subject to the whims of an IT department, I couldn't expect them to put up with having to log in every browser session, nor did I want to deal with SSO tokens expiring seemingly randomly during normal use. My first swing at the problem was to grossly extend the length of Domino's web sessions and tweak the auth cookie on the server to make it persist between browser launches, but that still broke whenever I restarted the server or HTTP task.

What I wanted instead was a way to have the user authenticate in a way that was separate from the normal Domino login routine, but would still grant them normal rights as a Domino user, reader fields and all. Because my sense of work:reward ratios is terribly flawed, I wrote a DSAPI filter in C. Now, I hadn't written a line of C since a course or two in college, and I hadn't the foggiest notion of how the Domino C API works (for the record, I consider myself as now having exactly the foggiest notion), and the result is a mess. However, it contains the kernel of some interesting concepts. So here's the file, warts, unncessary comments, probable memory leaks or buffer overflows, and all:

raidomaticlogin.c

The gist of the way my login works is that, when you log in to the forum app, a bit of code (in an SSJS library, because I was young and foolish) finds the appropriate ShortName, does a basic XOR semi-encryption on it, BASE64s the result, and stores it in a cookie. The job of this DSAPI filter, then, is to look for the presence of the cookie, de-BASE64 it, re-XOR it back to shape, and pass the username back to Domino.

Now, the thing that's interesting to me is that, because you've hooked directly into Domino's authentication stack, the server trusts the filter's result implicitly. It doesn't have to check the password and - interestingly - the user doesn't actually have to exist in any known Directory. So you can make up any old thing:

CN=James T. Kirk/OU=Starfleet/O=UFP

Though I do not, in fact, maintain a Directory for the Federation, Domino is perfectly happy to take this name and run with it, generating a full-fledged names list:

Names List: CN=James T. Kirk/OU=Starfleet/O=UFP, *, */OU=Starfleet/O=UFP, */O=UFP

It gets better: you can use any of these names, globs included, in Directory groups or DB-level ACLs and they're included transparently. So I set up a couple groups in the main Directory containing either the full username or "*/OU=Starfleet/O=UFP" and also granted "*/O=UFP" Editor access and an Admin role in the DB itself. Lo and behold:

Names List: CN=James T. Kirk/OU=Starfleet/O=UFP, *, */OU=Starfleet/O=UFP, */O=UFP, Starfleet Captains, Guys Who Aren't As Good As Picard, [Admin]
Access Level: Editor

Now we're somewhere interesting! Though I didn't use it for this purpose (all my users actually exist in a normal Directory), you could presumably use this to do per-app user pools while still maintaining the benefits of Domino-level authentication (reader fields, ACLs, user tracking). With a lot of coordination, you could write your C filter to look for appropriate views in the database matching the incoming HTTP request and only pass through the username when the cookie credentials match a document in the requested app. Really, only the requirements of high performance and the relentless difficulty of writing non-server-crashing C stand in between you and doing some really clever things with web authentication.

 

Be a Better Programmer, Part 1

Thu May 15 18:31:54 EDT 2014

Tags: programming
  1. Be a Better Programmer, Part 1
  2. Be a Better Programmer, Part 2
  3. Be a Better Programmer, Part 3
  4. Be a Better Programmer, Part 4
  5. Be a Better Programmer, Part 5

For over a year now, I've had notes on this blog-post series sitting on my desktop, staring at me and asking why I haven't actually started it. Well, I'm going to start it now.

The title and core concept are stolen from the illustrious Day[9], though I expect any mentions of video games will be incidental at best. What I want to do is encourage everyone, myself included, to be a better programmer, and I aim to do this by sharing overall concepts and strategies that I have found to help me. Some of these (like the quick one today) will be about generic concepts with more-or-less direct applicability to daily programming, while others will fall more to the sides of either "here's a neat trick" or more of an overall outlook on life and the profession.

To start off easily, I'm going to bang a drum I've banged before:

Data Structures

In Java, the most applicable form of knowing about data structures is the Collections framework, but they pay dividends even if you never write a line of Java (or work with a Java framework like XPages) in your life. I learned about data structures in college, but I recognize that "having been a CS major" isn't a viable option for non-time-travelers. The Wikipedia article does a decent job going over the basics of the types, though actually following the links to them runs the high risk of stumbling into the mathematical foundations and arcane pseudocode, which are of interest primarily to CS professors.

The good news is that I forgot the vast majority of the actual details of the structures yet still derive tremendous benefit. The best example of that is when it comes to Trees. In my mind, Trees have a couple primary points of note:

  • They consist of a root node that has zero or more children, each of which also has zero or more children.
  • There are two main categories of Trees to know about: binary and non-binary. What this just means is whether the count of children is limited to two or not. The primary purpose of this limit is for searching: left is "less than" and right is "greater than".
  • Binary trees are great for keeping and traversing sorted sets of data (thus Java's TreeSet), while non-binary trees are great for representing hierarchies (such as an XPage or an org chart).
  • If you're dealing with trees, you're probably going to do some recursion.

Once you know a bit about Trees, they start popping up everywhere: the ExtLib is rife with "leafNodes" and the like, JSON and XML data can be safely thought of as a Tree, and database indexes (like Views) fit the bill as well.

Unless you're actually implementing a low-level library, you don't really need to know more than the broad strokes. I learned tons of stuff about representing Trees as an array, algorithms for traversing them, and various specialized types (like Red-black Trees), but I've forgotten basically all of that.

I've found having a working knowledge of the various types to be a tremendous benefit in visualizing the structure of a program, in figuring out why something works the way it does, and in coming up with good solutions to a variety of problems. I recommend finding some tutorials online (maybe this guy, though I haven't watched them) and familiarizing yourself with the basics. You will likely find that it will be a stepping stone to greater understanding of basically everything you do as a programmer.

So it goes.

Mon May 12 20:55:43 EDT 2014

Tags: tim

Having only briefly met Tim Tripcony in person and lacking the writing skill for the task, I feel like it's not entirely proper for me to comment on his death, but I'm doing to do so anyway.

Years ago, when I was finding out about the Lotus community and starting my journey learning XPages, Tim immediately stood out as one of The People to pay attention to. His knowledge of the platform and willingness to share made his blog an excellent resource, but it was more than that. In a way that is extraordinarily rare in the world, Tim wrote code that wasn't just good or useful, but Right. Just looking at the way he approached and solved a problem, you could tell immediately that it was correct, that it was the product of a mind filled not just with knowledge and trivia, but with a desire to come up with the best, most beautiful solution.

That's a skill and a way of going about programming that I strive to reach, and I was glad to ride Tim's coattails in that direction when I could. When I read a blog post of his, I knew immediately it was advice to take to heart. When I saw that his approach differed from mine, I knew that mine was wrong. He was the type of programmer I want to be.

And though I didn't know him very well personally, it was clear that his joy in sharing and sense of humor shone through. Talking to him and reading his work, you could tell he relished the opportunity to engage with others and mutually improve. His generosity and evenhandedness are further traits I aspire to.

I admired him immensely, and I have a hollow feeling in my gut knowing that I won't have an opportunity to know him better.