HNHacker News
TopNewBestAskShowJobs

snprbob86

7,460 karma · joined March 13, 2008

New account: https://news.ycombinator.com/user?id=brandonbloom
submissionscomments
snprbob86··on Why you should not use Twitter for corporate customer service
"implies understanding of someone's situation on an emotional level, not just a rational level."

You've identified the difference between sympathy and empathy. OK, fine. I have plenty of sympathy, but no empathy in this situation. I deeply understand that this must suck for people who don't have a choice.

All I'm saying is that it's absolutely ridiculous to cry over the fact that somebody else's superior forced them to work late/hard one night. The original author should not feel any culpability for that. If there's any emotion I'd share here, it would be anger at those superiors, not a sense of guilt.

"It comes off as extremely douchey to tell people [...] that they can always say no."

The person I replied to was talking about a different person and suggested that person went the extra mile, hoping for some repeat business. That is absolutely optional. I have no idea if the delivery people in the original story had a choice, but I wasn't speaking about them.

snprbob86··on Why you should not use Twitter for corporate customer service
"She did it because she knew if she did that extra bit, those people would be way more likely to come back and spend money at the store. But there was never a guarantee, and almost every time was additional stress she really didn't need."

It doesn't sound like her job was at risk if she said "no", so if it wasn't worth it: she shouldn't have done it.

I'd consider myself a normal person. Hell, I think I have more sympathy, if not empathy, than the average patron. However, if you choose to do something shitty, you have no one to blame but yourself. If you're forced to do something shitty, then that's a different matter. In this case, it sounds like the people who made the delivery were either A) not all that inconvenienced B) inconvenienced by their own inability to say "no" or C) inconvenienced by an ignorant parent company who chose to chase after a social-media "WOW" story at the expense of their personel.

At most, the author of this post should have said "Oh, if I had realized it was this much trouble, I'd have waited a few extra days." Being deeply upset by something so trivial seems like unnecessarily sweating the small stuff. It's particularly silly because she had absolutely no reason to think that Home Depot couldn't find a strong day laborer on short notice.

snprbob86··on Why you should not use Twitter for corporate customer service
Maybe I'm being insensitive, but why would anyone burst in to tears for making a reasonable request that _indirectly_ causing somebody to have a crappy day at work? Furthermore, it's not even apparent that she really did ruin the day of these delivery folks. They probably got paid nicely to go through all that trouble. The fact that it took all day for the social media team to find somebody willing to go that extra mile implies to me that there were likely several people who turned down that sale/delivery.

Even if they were pressured in to that delivery by some contract or power-play, it's not her fault that she demanded quality service. Twitter et al are making companies accountable for their shortcomings. As a result, the treatment of customers is improving steadily across many industries. Like with anything, sometimes you need to break a few eggs to make an omelet.

snprbob86··on A concatenative programming library in 5 lines of Clojure
I whether or not there is a stack is similar to the complementary nature of foldL vs parallel fold (ie Clojure's core/reduce vs reducers). Left-to-right concatenative languages make use of a stack and are appropriate for side effects and stream processing. However, there are pure concatenative languages that operate in parallel via term rewriting, which has a computational model akin to that of a DNA computer.
snprbob86··on A concatenative programming library in 5 lines of Clojure
Fogus linked to my project, Factjor:

https://github.com/brandonbloom/factjor

Factjor supports quotations, currying, composition, and has most of the primary combinators: dip, keep, cleave, spread, application, etc. It's only about 100 lines.

snprbob86··on A Million First Dates
OK Cupid has (had?) both ads and an ad-free A-list subscription package. However, I doubt either of those were their primary sources of income. OKC has an extremely robust survey platform baked into their question and answer system. I suspect that the demographic and market analysis data is extremely valuable and that selling it to advertisers, consumer packaged goods companies, etc. would be very lucrative.
snprbob86··on AngularStrap - Bootstrap directives for AngularJS
You're being down voted because this is a discussion about Angular, not an opportunity for you to stand on your soap box about Knockout. However, I should point out that it's probably unwise to dismiss Angular outright over something as trivial as IE6&7 support. Angular's approach is well worth studying, even if you never use it. In short, I feel that the hierarchical view models (called "scopes") powered by data-driven "directives" and the preference for dirty checking over dependency graph management, yields a much cleaner internal design for the framework, and applications that both perform faster and are easier to maintain.
snprbob86··on A Million First Dates
OK Cupid's OK Trends blog had an article titled "Why You Should Never Pay For Online Dating", but they removed it after they were acquired by match.com, a paid dating site. You can Google around and find a few copies of the article.
snprbob86··on List Comprehensions in Eight Lines of Clojure
Your blog post should probably at least mention clojure.core/for, so that new Clojurists can use that in real projects, after they are done learning.
snprbob86··on Fay: a subset of Haskell that compiles to JavaScript
ClojureScript is not yet self-hosting. That is, the compiler does not run in the browser, although quite a few people want it to, so it's being worked on a bit.

That said, I haven't found it to have any serious impact on my development experience. There is no compile-debug-refresh cycle because I can evaluate forms against the browser REPL remotely. Compilation occurs server side and the JavaScript code is eval-ed on the client.

More details here: http://blog.fogus.me/tag/clj-compilation/

snprbob86··on SQL is Agile
Paraphrasing: "Isn't the logical type, in fact, `:if`?"

Yes.

Clojure's types are, generally, of the solution domains. The primary solution domain being: computation. That's the domain that all of Clojure built in types belong to.

The nature of Clojure and its community discourages the use of platform types for modeling the problem domain. Sometimes using platform types is desirable for optimizations like protocol dispatch and well-known structured fields. However, even when you're doing that, you're still operating in the solution domain. You're making an explicit decision about representation and evaluation: data structures and algorithms.

However, any substantial application is going to need some custom code for inspecting and debugging values. You'll wind up designing some schema and writing some custom validation. There can be tools to help you with this: consider XML's (very ugly) XSD schema system. Or consider W3C validators for HTML and CSS. For an example in the OOP world, look at AstValidator.java in the Google Closure code base. You simply can't escape it. A rich, strong type system can give you a leg up and get you 70% of the way there, but it will actively fight you when you want to go the last mile.

When and if you need it, you can basically make your own type system, tailored to your application.

snprbob86··on SQL is Agile
> If your language has classes, you should probably be using them for your entities and domain models.

Two years ago, I would have agreed with you. Now after some heavy, realistic usage of Clojure, I don't think I'll ever go back to modeling my domains with classes.

Maps are just so much more flexible! Granted, you frequently have a "type" like key. In the ClojureScript compiler, for example, AST nodes look like {:op :if :test ... :then ...} You can say that the :op :if is a "type", but in reality, the type of that object is a Map.

I'm working on a system now where there wasn't an obvious discriminated union or hierarchy of types. I fought the urge to introduce a type-like key in my map; the result has been quite pleasant.

snprbob86··on Show HN: CSS3 animation
Film is the high bar: The very best we can do with virtually infinite time and resources.

You're totally ignoring the fact that we've got near film-quality, interactive 3D animations, running at 30 to 30 frames per second on 10 year old hardware collecting dust in people's living rooms.

Meanwhile, this simple animation isn't quite getting the minimum 24 frames per second when run full screened on my 30 inch monitor powered by a brand new MacBook Pro.

snprbob86··on Show HN: CSS3 animation
Whenever I see these fancy "HTML5" multimedia demos, I get a little sad that others are impressed by the fact that they were made with web technologies. I know that, practically speaking, we're stuck with the current web tech for a while, but they are, quite frankly, shit for the types of tasks that we demand from them. After decades of studying & practicing computer animation in film and games, we're barely scratching the surface on the web.
snprbob86··on Never Have the “What Would It Take to Keep You Here?” Conversation
Unlimited vacation policies are a bad idea even on the small scale. Even on our team of 5, some of us sucked at taking time off. Those of us who didn't suck at taking time off sucked at not feeling guilty about it!

I'm still thinking about the side effects of a "Paid Paid Vacation" policy. That is, instead of getting N weeks of paid time off, you get $X per week of vacation used, up to some limit.

snprbob86··on Receiveee.com - disposable email address
mailinator does not require signup
snprbob86··on The four year vesting schedule doesn't make sense
Why would I want to treat new-grads better than experienced folks? And why would I want to incentivize somebody who doesn't like it after 3 months to stay for 4 months?

The 1 year cliff prevents disinterested parties from holding equity in my company and helps me retain people who have become important over time during that first year.

You're proposing improving my retention of lesser experienced people with lower bus factors in my organization. That seems backwards...

snprbob86··on Node.js error handling
I don't think that this style is fantastic. This means that the pair of success/error callbacks is not reified, so there isn't a single object to pass around or manipulate. The result is that composition is harder. In order to create higher order asynchronous operations, like those in Async.js [1], you need to either pass two arguments or use an array or object to pair the error handlers together. This is particularly important if you want to return a pair of handlers from a function.

In the two-callback model, the most common way to reify the handler pair is with a {success:...,error:...} object. This is much better than function(x,y,z,success,error), but still has the problem that you now need to override two handlers if you want to wrap some completion logic, regardless of success/failure. For example, if you want to close a file handle, win or lose, you need to provide two new functions.

Composition greatly benefits from a singular object. The Node.js approach is the (err,data) callback. It's an extremely simple and successful approach. The other approach are promises/futures, which internally can be implemented with one or more callbacks, but provide a nice clean interface for composition. You could get that with success/error objects, but you're exposing the internals rather than an interface, like you should be doing. A good promise interface would let you choose an implementation without tying you to any particular callback model.

[1] https://github.com/caolan/async

snprbob86··on Whose bug is this anyway?
My primary experience with C++ involves game development, so my perspective is a bit skewed. The cheaper chipsets in consoles tend to have weaker branch prediction, so any branching can be a big hit in aggregate. And everything is in aggregate because all your code is running in a tight frame loop at 30 or 60hz.

That said, the typical large C++ codebase is probably losing a lot more performance to bad algorithms than it is to problems that generally are only measurable in micro-benchmarks. There's just something about C++ that makes a lot of people obsess over performance to a degree that doesn't even affect the mindset of most C hackers. And because your brain is so preoccupied with performance in the small, you often miss opportunities for performance in the large.

Unless, of course, you're a AAA game, in which case you're fine tuning at the individual instruction and cache line levels for your most inner loops. I'm sure there are other, similar use cases for C++, but desktop software probably isn't on that list outside of a key component or two.

snprbob86··on Apple said to be talking to Foursquare for maps data
I'm grateful for the competition, even if Google didn't really need it to drive the state of the art forward thus far.
snprbob86··on Hazel for hackers

    $ git clean
    fatal: clean.requireForce defaults to true and neither -n nor -f given; refusing to clean
snprbob86··on Clojure eXchange 2012: David Nolen on The Refined Clojurist [video]
I'm not letting Vimeo off the hook either: I wanted to see the videos bigger, but not full screen. Clicking their logo said "sorry there was a problem loading this video". So I clicked "Watch later" and both videos were added to my Vimeo profile with title, screencap, etc. Clicking either video there tells me that I don't have permission to watch the private videos. Argh.

EDIT: Now I can't even watch the videos on the Skills Matter page. I get this message: "You have been temporarily blocked from Vimeo - The connection you are using has been automatically prevented from communicating with Vimeo's servers. This ban will be lifted automatically after an appropriate period of time." WTF?

snprbob86··on 24-bit color sucks
> Modern GPUs actually allow 16 bits per channel of precision when rendering, but it comes at a significant cost - various features no longer function, memory bandwidth is devoured, etc.

I'm not sure that this is true. It's extremely common for games to render lighting texture maps with HDR render targets. 16 bit-per-channel render targets are often used to accumulate excess light. The excess light gets processed by successful full screen pixel shader passes. These passes generally include blurring and flattening into a normal 8-bit-per-channel texture on the swap chain.

Furthermore, multiple render targets have been common since before the release of the Xbox 360. Deferred shading engines come into and out of popularity on what seems like a biyearly basis depending on what visual style is popular in games currently.

It seems to me that modern hardware is quite capable of greater color range, but the most demanding applications, games, would rather use that extra video RAM and fill rate for storing and processing surface normals, lighting scalars, material properties, etc. Desktop applications always lag behind games dramatically. Hell, browsers are just now starting to see some of the benefits of modern GPUs.

snprbob86··on Apple's Shares Swallow Biggest Loss in Four Years
PDFs are easily saved by selecting "open in iBooks". Or, you can bookmark a PDF by URL.
snprbob86··on Tidying up after Pull Requests
I second this. We really enjoyed the one fork per user model. Each fork's owner was responsible for their own branches, which was much more manageable.
snprbob86··on Notch trying jsFiddle
The first set of three nested loops is procedurally generating texmap, which is a multidimensional Array(16 * 16 * 3 * 16). 16x16 pixel textures, one for each the top, sides, and bottom, and then 16 of those. The inner loop tests against i, which is the current block "type" and performs customizations to the procedurally generated textures.

The next set of three nested loops is generating a random "world" with a tunnel cut out of it.

The renderMinecraft function is performing a minimal perspective projection http://en.wikipedia.org/wiki/3D_projection for a single ray cast into the world. Each pixel is cast and then, for each object hit by the ray cast, the closest is found, and a texture mapped pixel is calculated and written into the frame buffer.

snprbob86··on Show HN: Responsive Email Templates
Also useful, automatic CSS inlining: http://premailer.dialect.ca/ & https://github.com/alexdunae/premailer/
snprbob86··on Github service outage
I realize that reliability is important; GitHub should improve here.

However, my experience was that avoiding dependencies on an external server was the natural way of working with Git-based deploys. Our deploy scripts pushed the current branch from the local repository to the servers directly. This meant that the version tested locally, whether a hotfix on a developers box or the last synced/tested version on the CI server, was the exact version deployed. Granted, the scripts could have specified the exact revision to fetch from an external server, but since the deploy source and target were already communicating, why not just `git push` and a commit hook rather than various `ssh git ...` steps? It won't scale to hundreds of boxes, but by that point you surely have a local dist source for much more than just Git repositories.

snprbob86··on Mathematica 9 Is Released Today
Wolfram seems to have a penchant for hyperbole. However, at the time, that was likely true. My understanding is that v1 of Mathematica really was just a rewrite of Macsyma in C.
snprbob86··on Mathematica 9 Is Released Today
Despite the overwhelming sense of ego that pervades every word Wolfram and his organization ever writes, you owe it to yourself to try Mathematica.

When I had first encountered Mathematica in college, I thought "this is neat", used it for a few calculations, and forgot about it. Fast forward to a few months ago and I decided to install a demo just to learn about term rewriting and pattern matching.

What I discovered blew my mind: It's just a lisp! Every expression has a "head", which is just a namespaced symbol. FullForm[x+y+z] is really just Plus[x,y,z] and Head[Plus[x,y,z]] is simply Plus. Squint, and it looks like (+ x y z) to me... The really interesting part is that the entire computational library is built around term rewriting. While there is mutable state, it exists almost primarily at the symbol definition level. Everything else is pretty much pattern matching on trees of symbols. Even the rendered output is just a drawn representation of a box-oriented markup built out of Mathematica forms. It's quite amazing.

← PreviousPage 5 of 34Next →