1,361 karma · joined June 14, 2010
Well, they're not as broadly useful as without HTTPS, but you can still always MITM yourself to get a free transparent caching layer between the client and your end server.
- GET requests are supposed to be idempotent so they can be transparently cached by caching proxies. Even if you won't be taking advantage of caching proxies, it makes it easier if you can use the same data and mechanisms (i.e., HTTP headers) for server-side caching (and makes it easier to pull it out onto a separate server later). This is important if it gets a bunch of traffic or requests are resource intensive.
- Thinking about endpoints as "resources" instead of as function calls discourages you having parameters with a large or infinite set of possible inhabitants, which would dilute your cache utilization. "mysite.com/multiplicationTable.html" is nicely cacheable; You can cache "mysite.com/mult?a=5&b=10" if you want to, but how likely is someone to request that same URL again before it falls out of cache? Any information that changes the response is technically a parameter, too (since it invalidates your cache) - that especially means things like session state and side effects. That doesn't necessarily mean "never have side-effecty/RPC endpoints", but you should minimize them if you want to be scalable, since every request to one pretty much has to put load on your server.
- PUT/DELETE requests are supposed to be idempotent so they can be re-issued in case of failure. I also find it encourages design with immutable/replace semantics, rather than partial update semantics, which puts you in a better position when you want to move toward distributed/eventual consistency systems (or even just for debugging), since the data's all there in the request, and likely easier to make it commutative with other requests. Some of these things might matter to you more than others, depending on what you're building.
- Using headers properly gets you nice features like content negotiation, and provides what's needed for caching to work (e.g., 'vary' header). Using the built-in stuff means you can probably use someone else's library instead of hacking out something buggy yourself.
- HATEOAS gets you fully dynamic API discoverability. Describing your links well enough to accomplish this is pretty involved, and I'm personally not really sure it's worth the benefits, at least for anything that isn't an API having arbitrary clients built for it, or otherwise being directly navigated by some unknown end user. Maybe if there were more standardization around hypertext formats.
- Proper error codes can be nice for debugging, and theoretically can let certain situations be handled automatically (e.g., 401s could direct a user to authenticate, 302s generally redirect transparently) They also communicate some intent to e.g., search engines ("pass on my SEO link juice to this new URL"). They're a bit of a harder sell for internal APIs, since they're not really as descriptive as they should be. Probably the best practical benefit would be the ability to use client- and server-side libraries with them, or to be able to categorize your errors easily to simplify your handling, without having to dig into the response body. Also nice that you can look them up on Wikipedia - you don't have to maintain documentation for your own error format.
TL;DR: sticking to HTTP as intended helps to save you from rolling your own cache invalidation and coming up with your own new names for things, which are well known to be the two hard things in Computer Science.
With tuples (A,B), you're listing As uniquely paired with Bs
With functions (A -> B), you're listnig unique sets of (As non-uniquely paired with Bs), so each A can go to any value of B, with replacement.
I also listen to music in whatever language I'm learning - I used to use it to switch my brain between languages on the way from one language class to another. For memorization, the best way really is to just write it and repeat it a dozen times, so putting a song on repeat is really useful for refreshing your memory on commonly used words, practicing pronunciation, and even occasionally picking up new words by looking up lyrics, etc. Nothing beats immersion, though, just because, on top of practice (inherently prioritized by common usage), it gives you all the extra context to infer or reinforce meaning - memorizing words or working from a textbook means you have no extra information to go off of but what's written there. If you want to get those benefits of immersion without actual immersion, find things that mimic those qualities (extra context, prioritized by common usage, repetition), like music, kids TV shows, comic books, conversation, etc.
It turns out this style of recipe-building, when you get down to the minimal stuff you need for it, is really useful for any sort of computation-in-a-context (for a recipe, the result of running the recipe is the value "in" the context - you can "modify" it by adding to the recipe, same as you can "modify" a function's return value by composing it with another function). Basically, the interface says that "return" lets you put something in a context, "join" describes how you can compose contexts, and kleisli-compose says that if you have two functions that return results in a context ( a -> ctx(b) and b -> ctx(c) ), you can compose those functions by composing the resulting contexts with "join". The end result is that if you have some context, like a recipe, you can apply changes to it ("bind"). In fact, if you have no context (the Identity monad) kleisli-compose reduces to just normal function composition, and bind reduces to application.
TL;DR: separation of concerns is a really nice side-effect of what's just a really broadly applicable interface for "more complicated but still composable stuff".
> Bottom is a member of any type, even the trivial type () [...] If it were not, the compiler could solve the halting problem and statically determine whether any computation terminated
You can imagine function composition and identity don't work too well on things that never complete.
Glancing at the text available, it doesn't seem to make any references to other programming languages, and takes an approach of "let's build this up from the things you learned in Math class". Seems like it might be a good fit for someone with more math than programming background, or someone with enough programming experience that they want to get to the heart of what functional programming is, but a bit jaded by the usual language tutorial format.
Edit: To be clear, I don't really feel too strongly about it. It's still leagues ahead of many other languages - I just think that particular choice of keyword is likely to confuse things a bit.
Don't get me wrong, that's still somewhat useful - it tells me "this function doesn't do anything too crazy", but it doesn't tell me "it should be safe to refactor this without having to read the function bodies of the entire call graph below this point", which makes calling it "pure" seem a bit disingenuous.
The key word, though, is 'potential' - as the author mentions, one of the issues you run into with disassembly is that you sometimes run into code that jumps into garbage (dynamic jumps with insufficiently constrained inputs, or code that should've been unreachable), and sometimes you just hit an infinite loop waiting for an interrupt. It really needs some input/interactivity to determine likely entry points and dead ends/unreachable code.
One nice thing you can do while you have the call graph, though, is propagate constraints (basically type inference/data flow analysis) to get an idea of where dynamic jumps may go, which ones might be under-constrained, and which branch targets are likely dead ends. Haven't gotten as far as implementing it yet, but there's a paper on it here: http://www.cs.rhul.ac.uk/home/kinder/papers/phdthesis.pdf
> This is almost identical to the original Mario Bros, except you can't knock enemies upside down by hitting the platform they're standing on. The only way to defeat them is by hitting the POW block or throwing the Punch Ball which Mario and Luigi carry around.
There's keep-alive, but that still means that if you want to get a parent and its children, you have to wait for the parent request round-trip.
To add - this is a major issue we've been working through at Slant.co - we've combined child objects into the requests for the parent objects (sometimes even two levels down), but it's significantly complicated caching efforts - we're in the process of building some namespacing into our server-side request cache, so we can transparently make cached Question and Option pages stale whenever, e.g., the title of a Pro/Con gets changed. If HTTP allowed multiple responses, we could treat everything transparently server-side as individual requests, and get much higher hit-rates for proxy and client-side caches.
You could actually go a step further - if you're using "Hypertext as the engine of application state" (HATEOAS), URIs for the locations of direct subentities need to be there, if the client is expected to be able to make those state transitions, for the API to be "fully RESTful". (Though, I'd personally agree with the article that features like discoverability and content negotiation are secondary to those you get from idempotence/properly using HTTP methods, and feel they should be considered bonus features, rather than strict requirements)
I'd been thinking about modifying an emulator to do automatic speedrun splits based on changes in memory. Many of the people who'd most appreciate that kind of thing prefer to speedrun on original hardware, though, and a lot of them would be happy to pay for modifications like this - as many have, e.g., paid to have their 3DS modded with HDMI output.
Of course, it's all relative - this community does have a good number of early language adopters and people involved in programming language research. At the other end of the spectrum, just a few years ago, I met a Java developer who, at the time, hadn't even heard of C# - I'd imagine he'd've been quite shocked by the languages talked about here.