Pumpkin Coconut Curry with Crispy Salmon

Pumpkin Coconut Curry Picture

A couple of years ago, I was browsing Whole Foods while trying to decide what to make for dinner. I knew I had some frozen salmon at home, but I needed something to go with it — something filling, satisfying and flavorful. A package of soba noodles and a jar of prepared curry sauce later and I had one of my new go-to meals: salmon with curry noodles.

Fast forward to today: My apartment complex is doing a fall recipe contest, and I was wondering if I had something that I could submit. I knew there would be a lot of pumpkin breads and chili, so I wanted to do something unique. My boyfriend suggested my salmon curry noodles, but I wasn’t sure if it was “autumn” enough.

… but maybe it could be.

Chopped Ingredients

Squash and curry is a classic combination, so why not pumpkin? Combined with a warm, earthy curry blend like garam masala, it might just evoke the same comforting flavors as a pumpkin spice treat.

The curry sauce in this recipe borrows elements from some of my favorite curry dishes: rich coconut milk, warm flavorful spices that aren’t too hot, and a satisfying depth of flavor. The pumpkin adds a wonderful creamy texture to the sauce without having to rely on actual cream — or full-fat coconut milk. Light coconut milk works just fine! Toasting some of the spices in the oil while cooking the onion helps build that depth of flavor. The dash of fish sauce works similar to salt, except it draws out the more savory notes of the sauce. Don’t worry, your sauce won’t taste like fish! (If you need proof, just ask my boyfriend. I didn’t tell him I added fish sauce, and he didn’t make any comments about fishy sauce. Shh don’t tell him~)

Ingredients in Skillet

A garnish of pumpkin seeds helps add texture along with little pops of salty, curry goodness. Use more cayenne if you want some bite in those pops.

Continue reading

Tagged , , , , , ,

ReactJS: State, Props and Reusable Components

So here’s a thing.

As I build more components in ReactJS, I’m starting to uncover some interesting use cases. One such case that came up recently involved reusing components — a component that can be used both on its own and as part of another component. Let me explain.

A new feature on ProjectNom involves connecting your user profile to a Twitter account. To make this a more seamless experience, I decided to build a simple React component that surfaces the current state of your Twitter account.

For example, if you haven’t added your Twitter account yet:
Connect Twitter Account Example

If you want to add your Twitter account, then we have to send you to the Twitter website to authenticate, so we display the following:
Redirect to Twitter Example

And finally, if you’ve already connected your Twitter account:
Twitter Connected Example

As you can see, this component revolves heavily around manipulating a button, so I knew that would be the primary element in the render.

But thinking more generally, the second state with the busy indicator was something that jumped out as a component that I could use elsewhere on the site. So, I decided to build a “BusyButton” component which could be used both as part of this Twitter component but also on its own whenever I needed a button to display a “busy” state.

So first, let’s make a BusyButton suitable for our Twitter component. As described in my earlier post, it’s best practice to store state in the outermost parent component. Child components just use their props. So, using that philosophy, we can build our BusyButton component like so:

module.exports = React.createClass({
	render: function() {
		var buttonStyle = "btn-" + this.props.style;
				
		if (this.props.busy)
		{
			var busyLabel = this.props.busyLabel
				? React.DOM.span({style: {paddingLeft: 10}}, this.props.busyLabel)
				: "";

			return React.DOM.button({className: "btn " + buttonStyle, style: {minWidth: 75}, disabled: "disabled"},
				React.DOM.i({className: "fa fa-circle-o-notch fa-spin"}),
				busyLabel
			);
		}
		else
		{
			var icon = this.props.icon
				? React.DOM.i({className: "fa fa-" + this.props.icon, style: {paddingRight: 10}})
				: "";

			var attributes = {className: "btn " + buttonStyle, type: this.props.type, id: this.props.id, onClick: this.props.onClick};
			
			if (this.props.disabled) {
				attributes.disabled = "disabled";
			}

			return React.DOM.button(attributes,
				icon,
				this.props.label
			);
		}
	}
});

As you can see, this component is driven entirely with props. If this is a child component, then that makes sense. If the parent gets rendered again, it will pass new props to the child, and the child’s behavior will change when it renders.

So far so good.

But now we come to our second acceptance criteria. We want this button to have the same behavior on its own: a button that can be marked as busy, and have the same disabled state and indicator icon.

With our current component, we have to set everything with props. That’s fine for the component’s initial render, but if we want to change the component’s behavior after the fact, we have a problem. Props are supposed to be immutable — an initial state and nothing more. (see: Props in getInitialState Is an Anti-Pattern)

Truth be told, we could ignore this advice and use something like componentWillReceiveProps to make the component behave like we expect. The issue I have with this approach is that it ignores the fact we are fundamentally talking about changes in the component’s state. The “active” and “busy” behaviors are two different states that the button can be in. And the button can freely move between those states as necessary.

This was the conundrum: I needed the component to run from props in order to keep state isolated in one spot, but I also needed the component to maintain state so that it could be easily manipulated when used on its own. I never found a satisfactory answer to this problem, so I welcome any suggestions or best practices for others who may have encountered this scenario.

In the meantime, I’ve done something of a compromise:

module.exports = React.createClass({
	getInitialState: function() {
		return {
			busy: this.props.initialBusy,
			disabled: this.props.initialDisabled
		};
	},

	busy: function() {
		this.setState({busy: true});
	},
	
	activate: function() {
		this.setState({busy: false});
	},
	
	disable: function() {
		this.setState({disabled: true});
	},
	
	enable: function() {
		this.setState({disabled: false});
	},

	render: function() {
		var buttonStyle = "btn-" + this.props.style;
				
		if (this.state.busy)
		{
			var busyLabel = this.props.busyLabel
				? React.DOM.span({style: {paddingLeft: 10}}, this.props.busyLabel)
				: "";

			return React.DOM.button({className: "btn " + buttonStyle, style: {minWidth: 75}, disabled: "disabled"},
				React.DOM.i({className: "fa fa-circle-o-notch fa-spin"}),
				busyLabel
			);
		}
		else
		{
			var icon = this.props.icon
				? React.DOM.i({className: "fa fa-" + this.props.icon, style: {paddingRight: 10}})
				: "";

			var attributes = {className: "btn " + buttonStyle, type: this.props.type, id: this.props.id, onClick: this.props.onClick};
			
			if (this.state.disabled) {
				attributes.disabled = "disabled";
			}

			return React.DOM.button(attributes,
				icon,
				this.props.label
			);
		}
	}
});

I ended up using state, since it conceptually made sense for the component. But rather than manipulate state directly, I’ve exposed some custom functions on the component that allow its user (whether it be a parent component or custom JavaScript) to control whether the button is in an active or busy state.

The disadvantage is that you have to use these functions. Passing down props from the parent no longer works, because this component now has state, and state takes precedence over props. Luckily, this is a basic component with only two primary states (active & busy), so it’s easy to manage.

But it’s clear that React doesn’t have good support for this scenario, and I’m not entirely happy with this solution. For a framework that is built entirely around the concept of reusable components, it isn’t very clear how reusability is supposed to work.

Tagged , ,

DRY, Browserify

In my last post, I discussed some of the biggest lessons I learned while building my first component in ReactJS. One of those lessons revolved around Browserify, and how it was the best way to leverage component reuse.

As I moved closer to production, I realized there was one particularly nasty side effect to Browserify. Take the following code for example:

var React = require("react");
var ReactDOM = require("react-dom");

// Custom React Component
var RecipeTabs = require("components/RecipeTabs.js");

function initPage()
{
	ReactDOM.render(
	  React.createElement(RecipeTabs),
	  document.getElementById('recipeTabs')
	);
}

Browserify lets us use CommonJS require syntax even though browsers don’t natively support it. One way it does this is by inlining the entire contents of your require‘d JavaScript into your script. So, in the example above, our 13-line script will suddenly grow to include all of React, all of ReactDOM and all of the code for RecipeTabs.

If we blindly require React in this manner inside every JavaScript file on our site, then we end up with a bunch of duplicate inlined code. Even worse, we are forcing users to download the same code over and over. The browser only sees unique file names and sizes — it isn’t smart enough to realize that inside those files are large chunks of repeated code. What we really want is one file that contains all of our common code, and reuse that file on every page. That way, the browser only downloads the code once; every other page load uses a cached copy.

Thankfully, Browserify natively provides a solution to this issue.

The trick is to create a single file that contains all JavaScript requires used site-wide. This single bundle can then be included on all of your pages.

Browserify gives us an easy way to do this. For example, using gulp:

gulp.task('browserify-global', function() {
	return browserify()
		.require(['react','react-dom'])
		.transform(envify)
		.bundle()
		.pipe(source('exports.js'))
		.pipe(gulp.dest('./js'));
});

This creates an exports.js file which is a bundle of React and ReactDOM. We can now include this on every page of our site — the browser will download it once and then cache it for every subsequent page.

But we still have a problem. Browserify doesn’t know about exports.js when it processes the rest of the site’s JavaScript. It will go ahead and inline React and ReactDOM as usual wherever it’s require‘d.

The second piece to make this work is to tell Browserify to not inline certain require‘d libraries:

gulp.task('browserify-custom', function() {
    return glob('./src/**/*.js', function(err, files) {
        if(!err) {
	        var tasks = files.map(function(entry) {
	            return browserify({ entries: [entry] })
	                .external(['react','react-dom'])
	                .bundle()
	                .pipe(source(entry))
	                .pipe(gulp.dest('./js'));
	        });
		}
	});	
});

Now, whenever Browserify encounters a require for ‘react’ or ‘react-dom’, it won’t inline the script. But, as long as we include the exports.js generated in the previous step, the reference will resolve, and it will be able to execute any React or ReactDOM code.

This isn’t limited to third-party JavaScript libraries either. If you have your own code that is referenced across the entire site, then you can include it:

.require(['react','react-dom', {file: './src/pn.js', expose: 'pn'}])

The expose property specifies the name to use in your require statements. In this case, whenever I need to reference code in pn.js, I can simply require('pn').

In the second step, we can now specify pn as an external library:

.external(['react','react-dom','pn'])
Tagged , , , ,

ReactJS: What I Learned From My First Component

Today marks an important milestone — I’m blogging about a JavaScript library!

Ever since I took a deep-dive JavaScript boot camp a few months ago, I’ve been eager to start a project that would let me hone my newly-acquired skills. To that end, I’ve been refactoring ProjectNom’s (poorly-coded) JavaScript so that it conforms to best practices.

That’s low-hanging fruit though. What I really wanted to sink my teeth into was something like AngularJS — a modern JavaScript framework that takes the language to another level, opening up entirely new ways of rendering a website (e.g. SPA).

But the problem with Angular is that it’s a full MVC framework, and an opinionated one at that. To truly get the most out of it, I’d have to build ProjectNom from scratch – which I had just finished doing for other reasons, and didn’t want to do again so soon.

At work, it has been proposed that we use ReactJS for any front-end development so that components could be shared and re-used across projects. I didn’t know anything about React except the name, so when I had some free time, I decided to research it.

I started to get really excited. Not only did the philosophy of the framework sound right up my alley, but it was also designed in such a way that it could slot easily into an existing project. After a tutorial or two, I made the decision to take it for a spin on ProjectNom. What follows are my experiences and takeaways as I moved from the perfect world of tutorials to a real world use case.

To be clear, this post is not a tutorial. There are many of those already, including on React’s own website. I include a quick introduction to the theory of React in the next section, but after that I will assume you know the basics of how React works so that we can dig a little deeper.

So what is React?

Let’s imagine for a moment that standard HTML elements — div, ul, input, etc — are like LEGO bricks. They each have a function and purpose; but, on their own, they aren’t very interesting or useful.

React gives us a way to define components. A React component is like a LEGO set – it specifies the pieces and assembly instructions to create an interesting, complex object. It’s easy to define your own component, but there are also a large number of ready-made React components available. Either way, once a component is defined, all you have to do is ask React for it, and it’s ready to use on a web page.

Of course, a static collection of HTML elements is only slightly more interesting than a single HTML element. Most web pages are driven by the data that flows through it, and that’s where React’s power is fully realized. Each React component contains a state and this state defines how the component should look or behave. You can specify an initial state when you first ask React for a component, but that state can be modified at any time in response to new data. You could think of it like a LEGO set that specifies exactly which minifigs should go where, but providing the flexibility to move them around later.

If this sounds as interesting to you as it does to me, then I encourage you to check out a tutorial or two. Feel free to come back here once you understand the basics.

Continue reading

Tagged , , , , , , ,

Favorite Games of 2015

The year is drawing to a close, and that usually means lots of year-end “Best Of” lists. I tend not to read these articles, let alone write them; but, I’m making somewhat of an exception this year due to how many noteworthy games were released.

I hesitate to call this “Best Of”, as there is no ranking or rating to the games I’m going to talk about. A few also weren’t actually released in 2015, so to claim a “best of 2015” list would be incorrect. Instead, these are simply games that I played this year, enjoyed thoroughly, and highly recommend.

One other note: these aren’t typical games. In fact, several of them seem to abandon traditional gameplay in favor of story or character development. If that’s not the type of game you enjoy, this list may disappoint.

Okay! Less talk more game!

Continue reading

Tagged , , , , , , , , ,

Fish & Chip Tacos

I really like Fish and Chips.

Okay, I know I shouldn’t drop bombshells like that from the get-go. I apologize if half of what you were just sipping is now a fine mist coating your computer screen.

But in all seriousness, it has been a while since I’ve had the kind of Fish and Chips that I remember from England. There are a lot of British foods I adore, but most of them are either packaged & shelf-stable (and thus, easily shipped), or have close approximations crafted by companies here in the US. Unfortunately, the same cannot be said for Fish and Chips; and, it’s still rather impossible to ship food from some random chip shop in the middle of England to another country.

So, I keep looking. One recent entry that pinged my radar was from a place called Velvet Taco. This is a Dallas-based shop, which will be opening an Austin location sometime in 2016. Their menu is filled with unique tacos, but the one that caught my eye straight away was — you guessed it — a Fish and Chip taco.

They weren’t lazy about it either. A quick search for “fish and chip taco” on Google reveals several variations, but none that really capture the imagination. (Tilapia and anemic frozen french fries? Tartar sauce? Rice Krisipes??) Instead, we’re talking beer-battered cod, malt vinegar-infused chips and curry mayo — which, while not traditional, is a more uniquely British slant on Fish and Chips than tartar sauce.

Now, I’ve never had the actual taco from Velvet Taco, and I’m not sure when I’ll get the opportunity to. But my best estimate — a nebulous “2016” — was too far away. So it was time to figure out how to recreate this compelling idea in my own kitchen.

During this experimentation phase, I decided to take the easy path on two components. The fish I decided to buy frozen from the supermarket — good quality, beer-battered cod, of course. Sure, I could make this from scratch myself, and maybe I will try that one day. But it’s a bit of a hassle, especially on a weekday. If you can find a ready-made substitute that tastes good, go for it.

(Yes yes, I know: how can I talk about frozen fish when I just used the phrase “anemic frozen french fries”? In my experience, frozen breaded/battered fish reheats better than frozen potato. Whereas the fish will get crispy on the outside and moist on the inside almost every time, the potato fries can be more unpredictable depending on brand, oven and time. So I’d rather put effort into the more temperamental component.)

The curry mayo also couldn’t be simpler: take some store-bought mayo that you like, then stir in curry powder, cayenne, and a hefty dose of lime juice. Let sit for at least an hour. Done.

That leaves the most important component (at least to me): the chips.

IMG_2278

Serious Eats has a killer recipe for chorizo and potato tacos, and it is their method for cooking the potatoes that I use for this recipe. Boiling the potatoes in vinegar helps keep the pectin intact, allowing the potatoes to keep their shape, and make it easier to crisp up into little cubes of love.

Wait, did I say vinegar?

Yes, vinegar: the preferred condiment for any British Fish and Chips. Specifically, malt vinegar. Instead of the white vinegar called for in the original recipe, I substitute malt vinegar. Convenient, no?

The result is a taco that may not resemble an order of Fish and Chips from a chip shop in England, but it’s damn good and hits all those notes I crave when I’m thinking fish and chips: crispy battered fish, fluffy chips, savory malt vinegar and a kiss of salt.

Continue reading

Tagged , ,

Solving Dinner with Blue Apron

It was really difficult to come up with a title to this post that wasn’t like one of those “We tried Blue Apron, here’s what happened” ads.

I had seen those ads scattered around the web, but never clicked on one. Soon after, I started to hear their ads on Star Talk Live, which at least make me curious — mostly because they explained the service better than clickbait. Finally, it was this The Verge article that made me seriously consider subscribing for the first time.

Blue Apron seems to market themselves towards inexperienced cooks, or those who are too busy to shop for groceries on a regular basis. I don’t really fall into either of those groups — while there are many times that I wish I had planned my meals in advance, I quite enjoy grocery shopping.

The wine pairings were enough of a nudge (along with the pre-planned meals) to finally give the service a go. Here are my thoughts.

The Service

For those who aren’t familiar with Blue Apron, it’s a fairly simple proposition: each week you are sent the ingredients for three recipes, with each recipe serving two people (there is also a family plan). You can customize which day of the week you want the delivery, and you can tailor the recipes based on your dietary preferences — for example, vegetarian or no seafood. If you don’t want a delivery for a particular week, you can cancel it a minimum of six days in advance. I worry that this long lead time might become an issue down the road, but so far it hasn’t been a problem.

Other than that, Blue Apron doesn’t require any additional input. You can just let it go, and each week you will get three recipes and the ingredients to make them. If you’re a control freak (like me), you can log in to the website and preview upcoming recipes and make slight tweaks to what you want to receive.

I say “slight tweaks”, because even though you are given the option of six recipes, there are only certain combinations you are allowed to do. My theory is that this is to keep things simple for those packing the weekly boxes (i.e., your selections have to fall into one of the pre-defined “dietary preference plans” they offer). There’s also the tendency for recipes to change slightly — for example, the Oktoberfest Pork Chops we got last week were originally supposed to be Schnitzel Pork Chops. Blue Apron says that this happens because they want to use the freshest ingredients possible; but, whatever the case, it can be disappointing.

blue-apron-combinations

The ingredients come in a surprisingly compact box; but, it’s a rather heavy box due to two large ice packs — any meat or seafood in your shipment is sandwiched between them, with everything else piled on top. It can be a little overwhelming to unload, as nothing is sorted except for little bags of “miscellaneous” ingredients for each recipe. It’s as if you went on an exuberant trip to the grocery store and didn’t remember what you got. Luckily, everything starts to make sense once you start cooking the recipes, and realize which ingredients go with which recipes.

IMG_2215

The wine is a separate service, and you have even less control over it. If you sign up for it, you choose whether you want to receive reds, whites or a mix, and what address you want to receive them. (Since an adult has to sign for the wine shipment, they recommend providing a separate business address for the wine deliveries.) At the start of each month, for an extra $65, you receive six 500mL bottles of wine (slightly less than a 750mL bottle you would find in the supermarket). You don’t have any control over the varieties, but you receive a detailed information card about each wine, explaining where the grapes were grown, who produced the wine, what flavors you can expect, and what recipes in upcoming Blue Apron shipments pair well with it. All in all, it’s a great way to expand your horizons if you’re overwhelmed by or new to wine.

IMG_2213

Verdict: If your schedule is consistent enough to support a delivery once a week, Blue Apron is reliable and easy. But, skipping and customizing meals requires advanced notice.

The Recipes

IMG_2218Packaged along with your shipment of raw ingredients are several large, glossy, full-page cards: one highlights some of the ingredients in that week’s box; the rest detail each recipe, how long it takes to make, and roughly how many calories it is per serving. The steps to make it have clear instructions and pictures — they even bold the ingredients used in that step, so you’re prepared.

Overall, the recipes are varied enough to keep things interesting, but follow a familiar theme so it’s not too jarring to move from one recipe to another. For example, in the first week, there was a salmon with a farro salad, chicken with a jasmine rice, and lamb sausage with French lentils. Each one had a protein on a bed of some sort of starch, and vegetables mixed in. Very different flavor profiles, but similar components.

IMG_2236It’s good that Blue Apron has this overlap so that new cooks can get confident with certain skills. But if their goal is to target new cooks, they need to bolster their library of tutorial videos. Instructions like “core and chop the head of cabbage” may be self-explanatory to some folks, but if you haven’t done a lot of cooking in the past, it may be rather mysterious. As of writing this, there is no video for how to core and chop a cabbage, so you’re on your own if you need an explanation. It’s also worth noting that the estimated prep and cook times are going to vary wildly if you’re not an expert in the kitchen.

That said, if you don’t mind investing some effort in learning to cook (or expanding your horizons in what you cook), then Blue Apron has a lot to offer. Each recipe highlights the elements of a successful meal — in particular, I’m impressed with how they balance sweet, salty and acidic. Most of the recipes I’ve tried so far have vinegar or lemon juice, which really help bring a recipe’s flavors to life.

While I haven’t encountered any new cooking techniques for myself, it has been nice to have (balanced, tasty) meals planned out.

Verdict: Blue Apron requires an investment in cooking; so, if you don’t already cook, or have no interest in improving your skills in the kitchen, then you should look elsewhere. But, if you’re willing to take the plunge, you will be rewarded.

The Ingredients

Blue Apron touts their ingredients as being fresher than the supermarket. So far, I’d say that’s only partially true.

On the one hand, Blue Apron works with several small farms and food producers, which allows them to get exactly the product they’re looking for.

On the other hand, Blue Apron is based in New York, which means most of the suppliers it sources from seem to be around the northeast. But I live in Texas. So how fresh are the ingredients by the time they get down to me?

Most of what arrives on my doorstep is at least similar to what I could get at the supermarket — the meats are high quality, the pantry items are fresh, and the hardy produce is in good shape. But more fragile produce — like fine herbs, or sensitive leafy vegetables — are often half-wilted or on the verge of reaching the Green Slime stage. I feel that Blue Apron could work harder at sourcing ingredients closer to their distribution centers — or, at the least, package their sensitive produce so it can better withstand the journey.

On a more positive note, I’ve enjoyed the opportunity to use ingredients that I haven’t cooked with before. Farro, dried hops and beets are just a few of the things that I either haven’t cooked with before, or haven’t cooked in a long time. This gets to the heart of why I wanted to try Blue Apron in the first place — an opportunity to get new recipe ideas, and work with ingredients I don’t normally consider.

I do wish that Blue Apron included more spices in their shipments. If a recipe’s core flavor profile comes from spices, then it’ll be included — for example, a curry is going to include the unique spices that form that dish. But if it’s just a protein seared in a pan, then the only instruction is to use salt and pepper. I’ve taken liberties with a couple recipes to season the protein with some additional spices that I have on hand, but a new cook might miss out on this important method of layering flavors.

Verdict: Ingredients are varied, unique, and usually fresh. Some produce items arrive on the brink of going bad, but so far that hasn’t prevented me from actually making the recipe. An improvement in sourcing ingredients would be a welcome change.

Overall

I’ll be sticking with Blue Apron for now, just because it makes planning meals during the week so much easier. And at $60/week for the two-person plan, it’s about what I would spend at the supermarket anyway. The only thing that might make me reconsider in future is if the long advanced notice for skipping a week or changing meal options becomes a hassle.

As for the wine, that’s even more of an unknown. It’s fairly expensive at an additional $60/month; while I do feel you get your money’s worth (six 500mL bottles), it’s a monthly expense that may not make sense if the quality doesn’t remain consistent.

I think the best endorsement I can give is that I’m genuinely looking forward to some of the upcoming meals; ultimately, that will be what keeps me hooked on Blue Apron.

Tagged ,

Intelligence and the Search for Meaning: Thoughts on The Talos Principle

SPOILERS! This post is full of them. Please don’t read this post if you have any interest in playing The Talos Principle. Should you have any interest? If you liked the puzzles in Portal, and wish there were more: yes. If you want your concept of humanity and perhaps even reality to be challenged: most definitely yes. SPOILERS!

The Talos Principle

What is artificial intelligence?

The simple answer to that question can be found from the likes of Google and Apple. Saying ‘Ok, Google’ or ‘Hey Siri’ into your smartphone will allow you to ask targeted questions; and, within moments, it will be understood, processed, and acted upon.

The problem is that these services are designed around very specific use cases — getting directions to a location, figuring out whether it will rain, and so on. Any variation from this built-in expectation will result in a confused or inaccurate response.

So what do we really mean when we speak of artificial intelligence? Mostly we’re looking for something that behaves like us, like a human. And because we often build artificial things in an attempt to improve efficiency, we believe it should actually rise above some qualities of human intelligence, such as processing speed or the ability to see connections in vast amounts of data.

And that’s where The Talos Principle steps in. You find yourself in a beautiful world full of ancient ruins and complex puzzles — but not as a human. It becomes clear early in the game that you are a machine. There is no trace of a biological body in yourself or in anything else you encounter.

So what are you?

Continue reading

Tagged

Re-Introducing ProjectNom

ProjectNom Screencap
The original idea for ProjectNom was born about four years ago. At that time, my method of storing recipes involved a pile of printed recipes. As I picked up this pile — a pile with no organization, rhyme or reason — I wondered if there was a better way.

A better way to organize recipes, especially those found online.

A better way to cook those recipes, without having to resort to paper.

A better way to surface those recipes later when it came time to plan a meal.

The options at the time were rather limited. They were all locked to a certain platform, blissfully ignorant of the web. Importing recipes was a pain, and cooking directly from the software wasn’t a primary feature.

I built the first version of ProjectNom quickly, mostly because I wanted to get my own recipe mess under control as soon as possible. What I ended up with was a solid proof of concept, but the accelerated development time forced cracks in the infrastructure. The result was difficult to maintain and difficult to extend — classic hallmarks of such a rushed effort.

This year, I decided to finally give ProjectNom the professional treatment it deserved — or at least, the best treatment a one-person development team could deliver. Specifically, there were a few aspects I wanted to improve over the original “proof of concept”:

  • True responsive design. I used Bootstrap for the original ProjectNom, but a combination of my inexperience with modern front-end development combined with early-version Bootstrap limitations resulted in a lack of finesse, especially on smaller devices.
  • Easier importing. The first version of ProjectNom made importing recipes as easy as selecting text. While that was better than typing it in from scratch, it was still a hassle.
  • Sharing. Part of the fun of cooking is sharing the recipes you find. Having a way to do this in the same place that you store your recipes only makes sense.
  • Technical foundation. The original ProjectNom was difficult to maintain and improve upon.

This work started in January. Eight months later, I’m proud to finally reveal the complete rewrite of ProjectNom.

  • True responsive design. While I’m still not an expert in front-end development, the new ProjectNom is truly responsive across a variety of devices. If it has a relatively modern browser, it’ll look good. Some pages — namely editing a recipe — are more usable on devices with larger screens, but they’ll still render intelligently.
  • Easier importing. The new ProjectNom can quickly import recipes from known sites in one click. At launch, the following sites are supported: Food Network, Epicurious, Serious Eats, Bon Appetit & AllRecipes. The best part is that adding new sites is relatively easy, so please send along suggestions for any site not on this list! In the meantime, the traditional import functionality can be used — just select the text you want and click “import”.
  • Sharing. Invite your friends to join ProjectNom, add them to your list of friends, and then share your recipes! It’s that easy. You can even import the recipe directly into your collection for easy access.
  • Technical foundation. This could be an entire post in itself (and probably will be at some point) so I won’t go into too much detail here. But suffice it to say: the new ProjectNom is better organized for maintenance and expansion. One example: an API layer to keep the back-end concerns separate from the front-end.

There are bound to be bugs in this first version, but I’m committed to getting them ironed out. If you find anything amiss, please let me know either here in a comment, or at support@projectnom.com. I also welcome any feature ideas — I want to keep improving ProjectNom until it’s the ultimate recipe management solution across all platforms and all devices.

And on that note, I wanted to end with some musings on the state of recipe tech in general. Recipe web sites have improved greatly since I first started working on ProjectNom, but they’re still distinct silos of information. So even if a website lets you save recipes into a personal “recipe box”, you still have to remember which site has the recipe you’re looking for.

It’s also interesting to me that a lot of recipe management tools available today are locked to a particular platform. To be clear, they’re great apps — but if you’re not tied exclusively to Apple or Microsoft devices, then you suddenly lose access to your recipe collection. I certainly see the allure of staying on one platform — recipes are complex beasts, and it helps to harness the power of a specific platform to get the best experience. I certainly haven’t ruled out the possibility of creating platform-specific interfaces to ProjectNom. But the ability to access a recipe from any device at any time is a critical feature, and should never be compromised.

With ProjectNom, you can rest assured that it never will.

Now get out there and start cooking!

Tagged , , , , ,

Apple Watch First Impressions: Beyond the Obvious

Apple Watch
Much has been said about the Apple Watch already. Much of it has been obvious, especially if you’ve been following along with the technology media’s obsession with the device. In light of this, I wanted to write up a quick blog post detailing my experience with the Watch over the past week, while trying to avoid some of the common threads that you’ve likely already read.

Continue reading

Tagged , , , ,