I know you're waiting, nay, poised, taught with anticipation, for my next rice cracker review. We have three new kinds today.
Coruscating Lucubrations
Wednesday, April 17, 2013
Sunday, April 14, 2013
Rice crackers!
I love rice crackers. I have a veritable passion for them. One of the great sadnesses in my life has been the baseless, cruel attack on MSG by the health fascists. MSG is good. MSG in rice crackers is good. Rice crackers without MSG are an abomination.
Now, I admit I can be a bit slow sometimes, and I'll admit that it took me until a week ago to realize that in the age of the Interwebz, I could go online and find the forbidden MSG-laden rice-crackers. A week later, and the goods have started to roll in, so I'm going to start a series of reviews.
Not all of these rice crackers have MSG. Some didn't list their ingredients, and I ordered them just because they looked good and came from a company which sold other things containing MSG.
In my ratings, 5 really is "average." It means edible, worth the money if nothing better is available.
JFC, Nori Maki Arare
No MSG; can be had at Wegmans. Passable, but not outstanding. They're the logs wrapped in seaweed, of which I'm fond. The sodium content is reasonable, and they're flavorful despite not having MSG; their real selling point is the nori, so if you don't have a taste for seaweed, they're not worth it. I'm going to use them as the baseline.
Pacific Mercantile CO, Hana Arare
They talk the talk, but they don't walk the walk. They look exactly like the crackers of old San Francisco Chinatown circa 1973, but I'll bet they have no MSG in them. They are missing that distinctive zing, and the flavor is flat. Not worth the carbohydrates.
Bin-Bin rice cracker
Now, I admit I can be a bit slow sometimes, and I'll admit that it took me until a week ago to realize that in the age of the Interwebz, I could go online and find the forbidden MSG-laden rice-crackers. A week later, and the goods have started to roll in, so I'm going to start a series of reviews.
Not all of these rice crackers have MSG. Some didn't list their ingredients, and I ordered them just because they looked good and came from a company which sold other things containing MSG.
In my ratings, 5 really is "average." It means edible, worth the money if nothing better is available.
JFC, Nori Maki Arare
Rating: 5
No MSG; can be had at Wegmans. Passable, but not outstanding. They're the logs wrapped in seaweed, of which I'm fond. The sodium content is reasonable, and they're flavorful despite not having MSG; their real selling point is the nori, so if you don't have a taste for seaweed, they're not worth it. I'm going to use them as the baseline.
Pacific Mercantile CO, Hana Arare
Rating: 3
They talk the talk, but they don't walk the walk. They look exactly like the crackers of old San Francisco Chinatown circa 1973, but I'll bet they have no MSG in them. They are missing that distinctive zing, and the flavor is flat. Not worth the carbohydrates.
Bin-Bin rice cracker
Rating: 6
A product of Thailand, these crackers come in individual plastic pouches and look for all the world like little cookies. The flavor on these is nice, if a bit sweet for my taste. I prefer savory, but if you like a sweet cracker, these are pretty nice, and have a good MSG flavor.
I still have about a dozen different products to go through, but I can only eat so many crackers in a sitting, so the rest will come in another post. Stay tuned for more MSG, sodium-laden goodness!
Labels:
food,
review,
rice cracker
Sunday, February 17, 2013
JavaScript, and lessons learned
For various reasons, I found myself doing a bunch of JavaScript stuff this weekend. The project was to get a decent WYSIWYG editor into Redmine. Because I don't feel like writing an essay tonight, here's the short version of what I learned:
- Redmine is actually pretty easy to write plugins for; the development model is not bad at all
- JavaScript sucks balls. It is a truly hideous language.
- The jQuery and Aloha devs are programming gods. What they've produced is incredible, considering the fetid, rancid cesspool that is JavaScript.
- jQuery is a nice toolkit
- Aloha is slick
- Aloha and Redmine documentation isn't very good. jQuery is not bad
- "Dependency hell" takes on a whole new meaning in JavaScript.
Labels:
programming,
software
Tuesday, November 13, 2012
Why I Loved Living In Europe
I have friends who are baffled as to why I love Europe so much. I can understand that; there's a lot about Europe that is easy to dislike. Germans do tend to be blunt, French (Parisians, in particular) can be politically incorrect, and the postal service -- like a lot of business -- in Italy can be positively glacial. And to be fair, Americans have their own (mostly justifiable) stereotypes in Europe. It is still a pretty reliable way to detect Americans in Paris by looking for sneakers.
But the stuff I like about Europe, the things that are missing in the US, I really like. Lately, I've been musing on the social aspects. I miss the way small businesses operate in Eurpoe. They have a different relationship to their customers than in the US; it's rare to come across businesses like this in the states. Maybe it's because Capitalism rules all here, and niceties have no short-term commercial return.
The last time I was in Paris, Brett and Marnie were still living there in the 8th Arrondissement, and one evening Brett and I walked from their apartment to a small pizza place a few blocks away. It wasn't fancy, and it certainly wasn't a typical restaurant; if you can imagine walking into a café and ordering a pizza, that's what this was like. Anyway, we got there and placed our order, and when we sat down to wait, the lady who took our order brought us out two small glasses of wine to drink while we waited. I have never, in my life, had a better time waiting for a pizza. Brett and I talked, and drank, and watched the other customers until our pizzas was ready. I'm not a Paris noob; I wasn't blinded by the glitz. That year we went to Paris three times, and once we were browsing in a cramped, busy shop where the owner was obviously complaining about the American tourists who were blocking her customers. It's not all rainbows and unicorns, but I'm capable of ignoring assholes, and the niceties more than make up for it.
Which leads me to my next example. When I was living in Munich, there was a small greek restaurant around the corner that we'd frequent. When we would get together at our apartment with friends, we'd often end up down there for food (we never cooked for guests) and drinks. They had backgammon and chess boards, and you could go and sit, and drink and smoke and play games. It was a nice place. Anyway, after we'd been there a few times, the owner started coming out when we were done with our meals with a bottle of Grappa and glasses, and he'd sit down with us and drink and talk, and crack jokes. Again, I've been a regular customer at places in the states, but I've never had anybody do that here. The closest I've come is when Jason and I were going to Rock Bottom weekly; there was a period where the wait staff was pretty stable, and one of the waiters got to know us to the point where he'd just confirm our orders rather than asking us what we wanted. Not quite the same.
At this point, you might think I'm waxing rhapsodic about getting getting free booze. It isn't that; it's what the free booze represents. It's a little indication that the owners appreciate your business; it's the personal touch. It's a little something that makes you feel like your more than just a mechanism by which your wallet gets around. It turns a transaction into a personal, social interaction, and in my opinion, it is enhanced by the fact that the French and the Germans are not insincere in their interactions: they are not falsely friendly. When you encounter a kind gesture, it's much more likely to be honest.
One final parting story. When I first arrived in Munich, my first trip to Germany, the very first day, I visited Anne at her work for lunch. I was jet lagged, alone, had almost no money, and spoke no German, but I got instructions from Max's mom, got on the S-Bahn, and made my way into town. Somehow, I found the place -- this was in 1990, before the inter-webz and smart phones -- and we went to a grocery store to buy the fixings for sandwiches. During check out, I did the tourist struggle with the currency, and during this, the cashier and Anne had some exchange which she later deciphered for me; the cashier said: "Oh, don't make such a circus out of it," to which Anne replied: "Oh, just hold on. You're not going anywhere." That was it. There was nothing intentionally rude about it, by either the cashier or Anne, and I'm glad that I learned about the Bavarians and their tendency to bluntness before I learned enough German to be offended by this sort of interaction. Anne's much better at melding into this sort of environment than I am. I never did learn to overcome my hyper-politically correct, artificially friendly tendencies. I don't like conflict. But I can respect the honesty, and find that I prefer it.
Well, so much for randomly musing about Europe. I wanted to say something about Italy, but I've only been there enough to know that I'd like to spend more time there.
But the stuff I like about Europe, the things that are missing in the US, I really like. Lately, I've been musing on the social aspects. I miss the way small businesses operate in Eurpoe. They have a different relationship to their customers than in the US; it's rare to come across businesses like this in the states. Maybe it's because Capitalism rules all here, and niceties have no short-term commercial return.
The last time I was in Paris, Brett and Marnie were still living there in the 8th Arrondissement, and one evening Brett and I walked from their apartment to a small pizza place a few blocks away. It wasn't fancy, and it certainly wasn't a typical restaurant; if you can imagine walking into a café and ordering a pizza, that's what this was like. Anyway, we got there and placed our order, and when we sat down to wait, the lady who took our order brought us out two small glasses of wine to drink while we waited. I have never, in my life, had a better time waiting for a pizza. Brett and I talked, and drank, and watched the other customers until our pizzas was ready. I'm not a Paris noob; I wasn't blinded by the glitz. That year we went to Paris three times, and once we were browsing in a cramped, busy shop where the owner was obviously complaining about the American tourists who were blocking her customers. It's not all rainbows and unicorns, but I'm capable of ignoring assholes, and the niceties more than make up for it.
Which leads me to my next example. When I was living in Munich, there was a small greek restaurant around the corner that we'd frequent. When we would get together at our apartment with friends, we'd often end up down there for food (we never cooked for guests) and drinks. They had backgammon and chess boards, and you could go and sit, and drink and smoke and play games. It was a nice place. Anyway, after we'd been there a few times, the owner started coming out when we were done with our meals with a bottle of Grappa and glasses, and he'd sit down with us and drink and talk, and crack jokes. Again, I've been a regular customer at places in the states, but I've never had anybody do that here. The closest I've come is when Jason and I were going to Rock Bottom weekly; there was a period where the wait staff was pretty stable, and one of the waiters got to know us to the point where he'd just confirm our orders rather than asking us what we wanted. Not quite the same.
At this point, you might think I'm waxing rhapsodic about getting getting free booze. It isn't that; it's what the free booze represents. It's a little indication that the owners appreciate your business; it's the personal touch. It's a little something that makes you feel like your more than just a mechanism by which your wallet gets around. It turns a transaction into a personal, social interaction, and in my opinion, it is enhanced by the fact that the French and the Germans are not insincere in their interactions: they are not falsely friendly. When you encounter a kind gesture, it's much more likely to be honest.
One final parting story. When I first arrived in Munich, my first trip to Germany, the very first day, I visited Anne at her work for lunch. I was jet lagged, alone, had almost no money, and spoke no German, but I got instructions from Max's mom, got on the S-Bahn, and made my way into town. Somehow, I found the place -- this was in 1990, before the inter-webz and smart phones -- and we went to a grocery store to buy the fixings for sandwiches. During check out, I did the tourist struggle with the currency, and during this, the cashier and Anne had some exchange which she later deciphered for me; the cashier said: "Oh, don't make such a circus out of it," to which Anne replied: "Oh, just hold on. You're not going anywhere." That was it. There was nothing intentionally rude about it, by either the cashier or Anne, and I'm glad that I learned about the Bavarians and their tendency to bluntness before I learned enough German to be offended by this sort of interaction. Anne's much better at melding into this sort of environment than I am. I never did learn to overcome my hyper-politically correct, artificially friendly tendencies. I don't like conflict. But I can respect the honesty, and find that I prefer it.
Well, so much for randomly musing about Europe. I wanted to say something about Italy, but I've only been there enough to know that I'd like to spend more time there.
Labels:
Europe
Tuesday, October 2, 2012
The power of ad-hoc interfaces
That's not a technical term; it doesn't mean anything by itself. But since Go doesn't have a term (or I'm not aware of it) for the particular flavor of type interfaces it supports, I'm calling Go's interfaces "ad-hoc interfaces."
I keep being tickled by Go's submarine features. These are things which aren't touted with any fanfare, but which I find more useful as I gain experience with the language. In this case, the feature I'm growing increasingly fond of is the fact that types are not tightly coupled to interfaces; this is in contrast to Java objects, which are tightly coupled to interfaces.
For example, in Java:
Right? In Go, this might be:
Notice that, in Go, the definition of Cupboard doesn't say anything about its relationship to Door. This is a compile time binding, a strict duck-typing mechanism. What's cool about this is that you can do this sort of post-definition ad-hoc type-to-interface binding anywhere. In a package that uses the "containers" library, you could say:
Those other libraries do not know, nor care, that you've defined an Openable interface, and (in this case) you don't care what other functions those library types expose other than Open(). In the Java version, you'd have three options:
I keep being tickled by Go's submarine features. These are things which aren't touted with any fanfare, but which I find more useful as I gain experience with the language. In this case, the feature I'm growing increasingly fond of is the fact that types are not tightly coupled to interfaces; this is in contrast to Java objects, which are tightly coupled to interfaces.
For example, in Java:
public interface Door {
public void open();
public void close();
public boolean isOpen();
}
public class Cupboard implements Door {
public void open() { ... }
...
}
Right? In Go, this might be:
type Door interface {
Open()
Close()
IsOpen() bool
}
type Cupboard struct {
}
func (c *Cupboard) Open() {
...
}
...
Notice that, in Go, the definition of Cupboard doesn't say anything about its relationship to Door. This is a compile time binding, a strict duck-typing mechanism. What's cool about this is that you can do this sort of post-definition ad-hoc type-to-interface binding anywhere. In a package that uses the "containers" library, you could say:
type Openable interface {
Open()
}
func doSomething(o Openable) {
o.Open()
}
func main() {
c := new(containers.Cupboard)
doSomething(c)
f := new(filesystem.File)
doSomething(f)
o := new(icfp.Conference)
doSomething(o)
}
Those other libraries do not know, nor care, that you've defined an Openable interface, and (in this case) you don't care what other functions those library types expose other than Open(). In the Java version, you'd have three options:
- Modify the libraries you're using and add the Openable interface to the class definitions
- Use reflection to get a handle on the open() method
- Use the visitor pattern: wrap the classes you want to use in another class that knows about each of the classes you're using and can type-switch on them
Solving this problem in traditional inheritance and is-a models is do-able, but much more tedious. This drives some unfortunate behaviors, one of them being that developers used to traditional OO (ok, I see this a lot in Java developers; I don't know if it afflicts C++ or .NET developers too) tend to over-engineer interfaces. In an attempt to avoid the pain of having go back and alter the original interface or class definitions, devs tend to try to think about all possible edge cases, and throw everything they can think of into the initial interface definition. Go drives a slightly different, and in my opinion, more natural, behavior. In Go, interfaces tend to evolve. The development tends to be more: "hey, a bunch of my classes are doing the same sort of thing; I've defined Open() for four classes already; maybe I could use an interface here and refactor some code into a common function."
Ad-hoc interfaces help developers avoid situations where functions are added to types just to ensure that the type satisfies an interface. They can help prevent eager, wasteful, function definitions. Most importantly, they allow developers to follow the rule that the interface belongs to the user, not the library. It allows developers to say "I use this functionality from this library," and if multiple libraries use similar naming conventions, then also "from these libraries."
If there is one, most important take-away from this, it is that ad-hoc interface support is a tool that can be used to reduce efferent dependencies. If the package defines, itself, the interfaces it uses, then the coupling to libraries that it uses is tenuous in the extreme, and this is a very good thing. It isn't that you can't achieve this level of abstraction in C++, or Java, or .NET; it's just that it's much harder to do in those languages because they have traditional, tightly coupled, is-a definition mechanisms.
There's a pretty good article about coupling metrics over at IBM; it's interesting to read it with ad-hoc interfaces in mind.
Labels:
golang,
programming,
software
Wednesday, June 27, 2012
Now *this* is interesting
I needed to compare some images for something at work and have been trying a few different approaches. Since I wrote the application that's using it in Go, and since this was going to be called tens of thousands of times, I was looking for a Go library rather than something I'd have to fork off a bunch. I ended up implementing a couple of libraries, and one of these was a near-line-for-line clone of the pdiff application. Anyway, this is all just backdrop; the real craziness is this:
Here's my code. Again, I've done almost nothing to this except perform the nearly trivial translation from Yee's clearly-written C code to Go. I introduced minimal Go idioms. I am using Go's standard image library rather than Yee's custom one that uses the FreeImage library.
The algorithm is effectively allocating a bunch of big-ish arrays and iterates over one of them performing a fair amount of calculations. There are a fair number of function calls, and the math is limited to logs, powers, tan, and the regular suspects +-/*. I make no claims, and a whole bunch of caveats: I didn't do rigorous benchmarking (although, the results are consistent across several runs), and I've already said I did minimal Go-ification. I did no additional optimization on my code. I didn't even break it up to take advantage of Go's awesome goroutines. I am using Go 1.0.2.
If I had to guess, I'd say there are three probable explanations:
Here's my code. Again, I've done almost nothing to this except perform the nearly trivial translation from Yee's clearly-written C code to Go. I introduced minimal Go idioms. I am using Go's standard image library rather than Yee's custom one that uses the FreeImage library.
1199)src/autocompare % time ../../bin/pdiff a.png c.pngHere's the original:
images are visually different; 49949 pixels differ
../../bin/pdiff a.png c.png 20.32s user 0.28s system 100% cpu 20.429 total
1200)src/autocompare % time ~/pdiff/perceptualdiff a.png c.pngThat's a 7.3% difference. I am surprised at how close to the C version the Go version is. My code is here, and you can compare it yourself to the original (link above).
FAIL: Images are visibly different
49948 pixels are different
~/pdiff/perceptualdiff a.png c.png 18.88s user 0.06s system 99% cpu 18.941 total
The algorithm is effectively allocating a bunch of big-ish arrays and iterates over one of them performing a fair amount of calculations. There are a fair number of function calls, and the math is limited to logs, powers, tan, and the regular suspects +-/*. I make no claims, and a whole bunch of caveats: I didn't do rigorous benchmarking (although, the results are consistent across several runs), and I've already said I did minimal Go-ification. I did no additional optimization on my code. I didn't even break it up to take advantage of Go's awesome goroutines. I am using Go 1.0.2.
If I had to guess, I'd say there are three probable explanations:
- The FreeImage library is horribly inefficient (or way less efficient than Go's standard image library)
- Despite the fact that the code looks mostly like calculations, most of the time is spent in allocating arrays and this is normalizing the times (although, I'd expect to see more time in system in that case)
- Go 1.0.2 is actually pretty close to C these days, for some tasks
Labels:
golang,
programming,
software
Monday, June 25, 2012
Programming satisfaction
The satisfaction quotient is very high with Go. This post isn't so much about Go, per se, except that I've been getting a high amount of satisfaction with my Go programs.
I moved into management last year, and I don't have much time for coding any more. I work more managing than I did programming; most of my week is spent in meetings, which means that to get any of my tasks done, I have to put in more hours than the standard 40. This is a temporary situation; right now I just have very few options for delegation -- my team is large, but is mostly offshore, and I had been having difficulty finding good people to hire for the open positions on the team. However, I've always heard that long hours is a side-effect of lower-middle management, so it's not unexpected.
A couple of weeks ago, one of the problems we had with my project became a critical path issue; there was a technical solution and I thought I knew what the problem was, but none of my team had the bandwidth to address it... so I promised the person who was having the problem that I'd fix an application for him to address the issue. It was a week later than I had hoped, but I finished it this weekend (the only time I could find to write it), and I have to admit: there is a visceral satisfaction to finishing a piece of code.
Unlike management, in writing software you can complete a job. The best you can get in management is to finish tasks, and somehow they never seem to be truly finished. You always have to follow up, double-check, cross Ts, and dot Is. Most of my job is recurring activities, and while I automate as much as I can, it's still a never ending struggle to drive the project forward. While I enjoy doing it, it lacks the joy of completion.
Granted, most software development also lacks the joy of completion, especially in maintaining legacy systems. Most of the time you're fixing bugs or implementing minor feature enhancements, or refactoring old bad or mutated code; the types of projects where you can stamp the software as "done," even for broad definitions of "done," are few and far between. That's why I was happy to get into management; all of my jobs for the past decade had lacked that primary satisfaction I derived from programming, and nothing kills love quite so completely than having it become a chore.
For whatever reason, I have yet to run into aspects of Go that annoy me. I have hints of where I might encounter such annoyances in the future, and I'm sure they exist; to deny them would be to assert that Go is perfect, and I'm not that foolish. However, I can churn out decent code that works correctly with minimal post-compilation debugging, and that's a pretty rare thing. Ruby satisfied the "churn out" part, but failed miserably on the post-deployment debugging aspect. Haskell was highly effective at facilitating applications which, once they compiled, ran with minimal need for debugging, but just getting the application written was a chore. Go has a nice balance, and very little boiler-plate, and I'm always amazed at how much I can write with so few 3rd-party dependencies.
It is a rare pleasure to write a piece of software that does a job, and does it right. That's the beauty of small systems; it's the elegance of the Unix philosophy. It's intensely gratifying.
I moved into management last year, and I don't have much time for coding any more. I work more managing than I did programming; most of my week is spent in meetings, which means that to get any of my tasks done, I have to put in more hours than the standard 40. This is a temporary situation; right now I just have very few options for delegation -- my team is large, but is mostly offshore, and I had been having difficulty finding good people to hire for the open positions on the team. However, I've always heard that long hours is a side-effect of lower-middle management, so it's not unexpected.
A couple of weeks ago, one of the problems we had with my project became a critical path issue; there was a technical solution and I thought I knew what the problem was, but none of my team had the bandwidth to address it... so I promised the person who was having the problem that I'd fix an application for him to address the issue. It was a week later than I had hoped, but I finished it this weekend (the only time I could find to write it), and I have to admit: there is a visceral satisfaction to finishing a piece of code.
Unlike management, in writing software you can complete a job. The best you can get in management is to finish tasks, and somehow they never seem to be truly finished. You always have to follow up, double-check, cross Ts, and dot Is. Most of my job is recurring activities, and while I automate as much as I can, it's still a never ending struggle to drive the project forward. While I enjoy doing it, it lacks the joy of completion.
Granted, most software development also lacks the joy of completion, especially in maintaining legacy systems. Most of the time you're fixing bugs or implementing minor feature enhancements, or refactoring old bad or mutated code; the types of projects where you can stamp the software as "done," even for broad definitions of "done," are few and far between. That's why I was happy to get into management; all of my jobs for the past decade had lacked that primary satisfaction I derived from programming, and nothing kills love quite so completely than having it become a chore.
For whatever reason, I have yet to run into aspects of Go that annoy me. I have hints of where I might encounter such annoyances in the future, and I'm sure they exist; to deny them would be to assert that Go is perfect, and I'm not that foolish. However, I can churn out decent code that works correctly with minimal post-compilation debugging, and that's a pretty rare thing. Ruby satisfied the "churn out" part, but failed miserably on the post-deployment debugging aspect. Haskell was highly effective at facilitating applications which, once they compiled, ran with minimal need for debugging, but just getting the application written was a chore. Go has a nice balance, and very little boiler-plate, and I'm always amazed at how much I can write with so few 3rd-party dependencies.
It is a rare pleasure to write a piece of software that does a job, and does it right. That's the beauty of small systems; it's the elegance of the Unix philosophy. It's intensely gratifying.
Labels:
golang,
processes,
programming,
software
Subscribe to:
Posts (Atom)