Talks that changed the way I think about programming
opowell.com
opowell.com
"Binstock: Are you still programming?
Kay: I was never a great programmer. That's what got me into making more powerful programming languages. I do two kinds of programming. I do what you could call metaprogramming, and programming as children from the age of 9 to 13 or 14 would do. I spend a lot of time thinking about what children at those developmental levels can actually be powerful at, and what's the tradeoff between…Education is a double-edged sword. You have to start where people are, but if you stay there, you're not educating.
Extracting patterns from today's programming practices ennobles them in a way they don't deserve The most disastrous thing about programming — to pick one of the 10 most disastrous things about programming — there's a very popular movement based on pattern languages. When Christopher Alexander first did that in architecture, he was looking at 2,000 years of ways that humans have made themselves comfortable. So there was actually something to it, because he was dealing with a genome that hasn't changed that much. I think he got a few hundred valuable patterns out of it. But the bug in trying to do that in computing is the assumption that we know anything at all about programming. So extracting patterns from today's programming practices ennobles them in a way they don't deserve. It actually gives them more cachet.
The best teacher I had in graduate school spent the whole semester destroying any beliefs we had about computing. He was a real iconoclast. He happened to be a genius, so we took it. At the end of the course, we were free because we didn't believe in anything. We had to learn everything, but then he destroyed it. He wanted us to understand what had been done, but he didn't want us to believe in it.
Binstock: Who was that?
Kay: That was Bob Barton, who was the designer of the Burroughs B5000. He's at the top of my list of people who should have received a Turing Award but didn't. The award is given by the Association for Computing Machinery (ACM), so that is ridiculous, but it represents the academic bias and software bias that the ACM has developed. It wasn't always that way. Barton was probably the number-one person who was alive who deserved it. He died last year, so it's not going to happen unless they go to posthumous awards.
It's like the problem Christian religions have with how to get Socrates into heaven, right? You can't go to heaven unless you're baptized. If anyone deserves to go to heaven, it's Socrates, so this is a huge problem. Binstock: I don't think they do that.
Kay: They should. It's like the problem Christian religions have with how to get Socrates into heaven, right? You can't go to heaven unless you're baptized. If anyone deserves to go to heaven, it's Socrates, so this is a huge problem. But only the Mormons have solved this — and they did it. They proxy-baptized Socrates.
Binstock: I didn't realize that. One can only imagine how thankful Socrates must be.
Kay: I thought it was pretty clever. It solves a thorny problem that the other churches haven't touched in 2,000 years."
[0] http://www.drdobbs.com/cpp/interview-with-alan-kay/240003442
I wonder how Kay would score on sites like HackerRank, and how many companies today would pass him over because of that.
Every time I design software, I'm think back to Gary Bernhardt's "Boundaries" talk¹ and his practical, concrete suggestions for writing testable code. But I've never met anybody else who seemed as impressed as I was by the idea.
Mike Monteiro: "F* you, pay me" - https://www.youtube.com/watch?v=jVkLVRt6c1U
Since this has become such a nice thread some additions I'd add:
* Sandi Metz going through the Gilded Rose or "All the small things"
https://www.youtube.com/watch?v=8bZh5LMaSmE
I already subscribed to her programming style and the general Ruby TDD/BDD movement, but this talk captures all the important values in a single example. I think it made my programming style no longer based on vague things like experience or intuition, but just on concrete merit shown in this talk.
* Matthew Brecknell demonstrating Hole Driven Development
https://www.youtube.com/watch?v=52VsgyexS8Q
The programming style demonstrated in this video is a real mind bender. I think most Haskell programmers use a weaker version of this, Matthew takes it to the extreme. I didn't adapt this style, I don't think it's practical, but it's the sort of thing that some person someday will incorporate in some more comfortable way in a new language or platform as a revolutionary feature.
The Idris REPL itself can do hole-based programming too, which can then be dumped out to a file (:m to list holes, :p to prove a hole, :a to write proofs to disk) http://docs.idris-lang.org/en/latest/reference/repl.html
As mentioned below, this can be used in languages like Agda and Idris; they also give you proof search, which tries to automatically fill in the holes from available definitions. This works well for 'proof objects' (the name given to values which only exist to satisfy the type checker), but requires caution for values with 'computational content' (those values which can effect the resulting computation).
Pretty much all Haskell code (except the really wacky astronautical stuff) has computational content, so there are fewer "obvious" obligations to fill in than would appear in a proof (in fact, due to laziness and lack of totality, we can safely use 'undefined' for all proof objects, since they'll never be pattern-matched!).
For example, if our function needs to return a list (e.g. if we're writing a function like map, filter, iterate, replicate, cycle, etc.), a proof search will immediately give us the empty list '[]', which is correctly typed but probably wrong.
For Haskell, tools like djinn can get you a little hole-filling automation, and I think that Emacs modes like ghc-mod and intero support calling out to djinn (I can't test this, as I can't get either to work on NixOS :( ).
For a little more work, you could write properties for QuickCheck (/SmallCheck/LazySmallCheck/etc.) to constrain the behaviour, which would allow trivial solutions like the empty list to be ruled out automatically. If you're a TDD disciple, then you already wrote these properties, so this part would actually be free (as long as the automation tooling exists).
At that point you're basically doing inductive functional programming, so tools like IGOR2 or MagicHaskeller might be useful to plug in as well.
I get the chance to interact with a pretty wide range of software engineers, the thing that constantly blows people's minds is how caches work and the fact that there's 10-50x performance waiting for you if know about it(and have the time to exploit it).
It's almost like they don't teach it in school or something, I agree there's a lot of gamedev/perf stuff but that lines up with my experience of things that change the way people approach programming.
Could you point to some sources?
https://www.akkadia.org/drepper/cpumemory.pdf
Note that I wouldn't really recommend it unless you're really going to do low level programming for high performance. It's super long, explains all the details, if you've got a basic CS college education you should know most of it already anyway.
If you're just a web developer this won't actually help you as most of this improvements have already been done in the parts that matter (i.e. your database, your operating system, your interpreter and perhaps your application server).
https://www.youtube.com/watch?v=QVpSIdWE0do&list=PLEMXAbCVnm...
Again, it's game dev oriented, but there are good general advice as well, here and there.
Mike Acton is on there too. Jonathan Blow, Ron Gilbert, etc.
In general, I think more programmers should be concerned with learning how things work at a deeper level than the API for whatever web framework they are using. Web applications are god-awfully slow, it's like the programmers behind them just don't give a shit about performance, at all. It's not that much better on the desktop side either.
You might also be interested in:
https://hackage.haskell.org/package/djinn
Djinn writes the code for you. Cut out the middle-man. (Don't show your boss.)
* Growing a Language, by Guy Steele
I especially loved the moment when I finally understood the point he's trying to make is applied to the writing of the very talk he's giving.
"C++ is evil because it makes dumb people think they are clever."
Replace C++ with any "intelligent" framework or language.
Among other things, how and why to making things more implicit:
http://youtube.com/watch?v=wf-BqAjZb8M (Beyond PEP8 by Raymond Hettinger)
When implicit goes too far:
https://www.destroyallsoftware.com/talks/wat (wat by Gary Bernhardt)
However, I am not sure if what the author wrote ("Your most powerful problem solver is your subconscious mind.") is a spot-on articulation of what Rich means by hammock driven development. Here's my summary of what Rich means: immersive, focused thinking followed by unstructured, relaxed, open-ended thinking. It is the combination of the two that is so powerful.
It would be interesting with some more analysis from the OP, namely what was learned that changed their thinking, and how their thinking was changed.
Code should be designed around a model of the world
but I didn't hear any reason why not to? The Key/Value pair being the only reason, but besides that being a optimization / preoptimization in high performance applications, is there any reason to not design code around a model of the world?
Seems to me it makes things easier to think about.
Basically: When you try too hard to fit the real world into code, you end with OOP.
It has one great advantage: it is easy to translate real world into "computer".
but one great big distvantage: a computer is a computer, not real world, OOP translates to complexity (think "Architecture Astronauts", and spaghetti of pointers/references/virtual/inheritance) and things done in a way that harms performance (not a problem for smaller problems, but if your problem is not small...)
His idea is that you should instead fit the world into your DATA, not your code, think about what data your program needs from the real world (do you really need all tiny details for example?), what is your inputs and outputs, and THEN you code to make that work, you code around your data structures, file formats, etc... not the other way around.
I think Wizards and Warriors by Eric Lippert is a perfect illustration of how our initial assumptions and models aren't often the right ones (although it's not so much about data in this case) https://ericlippert.com/2015/04/27/wizards-and-warriors-part...
See data-oriented programming (not to be confused with data-driven). In the end code just processes data.
Event Sourcing - Greg Young
https://www.youtube.com/watch?v=JHGkaShoyNs
•: Not that I really expected it to be I guess.
Anything can be ^H^H^H^Hmessed up.
This does not seem to be true, based on widespread industry and scientific use of Python generating, managing, and analyzing data.
Perhaps you meant in some specific way, like "Python does not enforce objects' data schema" or some such?
There are a few talks like this, but there is one in particular where he goes into a lot of detail about it. I can't for the life of me find it again.
Firstly, maybe lastly, the conclusion of this video is real powerful stuff. I cannot pinpoint it's philosophical anchoring or origin. The same message was at the end of the iconic documentary about Jodorowskis Dune.
But
I have been trying to mentally operationalize the advice and ideas here, but found it really dificult and abstract.
Obviously an incredible lecture that deserves its own category.
* Responsive design, by Kent Beck https://www.infoq.com/presentations/responsive-design
* The Grand Unified Theory, by Jim Weirich https://vimeo.com/10837903
Another fun fact is staggering array accesses is faster then linear acesses.
I for one always get confused which index is the row and which is the column when coding. Every damn time I've done a 2D iteration in the last 15+ years. Is it [col][row] or [row][col] ...
I imagine it depends.
Not exactly what you asked, but if you look at most subroutines in linear algebra libraries like LAPACK, they tend to have extra arguments so you can tell if your inputs are already transposed and/or conjugate in order to have more efficient memory access.
* You have no inter dependancy of information across the lines
* All your data is in the cache
* You don't have instructions generated between the two lines that will require some sort of operand forwarding
Basically, if you already have the stuff in the cache, the calculation is invarent to the last calculation, and you have a processor capable of it you'll see a large speed improvement.There is a great talk about this [0] (for the exact moment go to [1]). If you're interested further I'd very much recommend finding some sort of GOOD computer architecture class. Luckily now we have a fantastic resource to locate these such courses [2]. This seems like dark magic and many programmers refuse to come to terms with it's existence. Check out `dreta`'s comment to see an example.
Now I do agree with dreta, this is VERY much architecture dependant but most architectures would benifit from this sort of optimization. Pretty much all modern Intel and AMD CPU's caches are large enough, they support a big enough cache, and they also all have pipelines under the hood. Intel started this in the pentium series with a 5-stage-pipeline (which I find very funny due to the GHz wars that came from that time period desipte the pipeline being probably the pargest performance boon in most cases that you would want to brag about).
[0] - https://www.youtube.com/watch?v=e08kOj2kISU
[1] - https://youtu.be/e08kOj2kISU?t=26m50s
[2] - https://github.com/Developer-Y/cs-video-courses#computer-org...
Wish I could link a few examples, sorry.
It might be not much news when you consider only the title statement, but it's the reasoning that talks are watched for, right?
Inlining functionality to very large procedures has the advantage that it makes obvious that there are no moving parts. You look at a few lines and know exactly the execution context. This improves readability a lot.
Maybe just try it before calling it a nightmare. Most things in life have pros and cons, the difficulty is to decide what to do in which situations. Don't take anything too seriously or idealistically. Try to understand from the perspective of an honest presenter and apply your own judgement.
I spent the first ~5 years of my career writing code in this fashion. I actually agreed with most of the talk, but this section was a big sticking point with me.
Inlining functionality to large procedures has the disadvantage that you need to understand the entire procedure to know what the function does. It also has the disadvantage that you need to test the permutation of every branch within that function in order to fully test the function. That's an order of magnitude more work. Don't even get me started on his stance on TDD (and how correlating it to the failure of OOP makes no sense at all).
And, yes, I understand that there can be pros. I've made my stance on the cons very clear, and I strongly feel as though they outweigh the pros. Does it make the moving parts more obvious? Probably sometimes. If you can't come up with good names, and your functions are small enough to begin with, probably. Better naming -- which the presenter addresses -- IMO does a much better job solving this though. His solution is to stop trying to name things, mine is to spend more time coming up with better names.
Personally I'm not much invested in testing (most of my programming is recreational) but I fail to see how a big function should be harder to test than two smaller ones that when combined can do the same things. The two small ones have obviously more possible code paths since the smaller, driven function is not hidden in the driver function anymore, so can be called in ways that don't actually matter to the purpose of the program. (That's the authors point - he calls it "surface area").
It's understandable how you wouldn't see this without testing experience. Wrote a quick gist to try to explain it as best as I could. https://gist.github.com/lojack/5a8526e88c759acac3f4f46036a37...
That's a trivial example using pseudocode. But, basically, you'll see that in the longer function example you need 10 test cases to cover all grounds, while in the method thats split apart you need 8. Realistically, I could have further split parseArguments up to simplify those test cases. It seems like a small change, but if you were to add an additional branch to the first method (an if statement) then you'd double the number of tests required. For the longer method thats 10 additional test cases, for the shorter method thats 2.
The two branches of the big function don't interact in any way (they could also be paralleized), so 100% branch coverage has no benefit here.
In fact you need less tests with the big function if you don't know the context in which the functionality is used, since the surface area is smaller.
Another way to look at it is that 100% branch coverage only means all the branches in one isolated function are tested. However, the multiple-functions version calls other functions and the possible branches there are ignored. In other words the interaction with called functions is not tested.
He got some good points in his analysis with respect to fine granular OO design. The reasoning around the need to break encapsulation was illustrative. If objects are too small they will have a lot of surface area and their interconnection is hard to reason about. In OO programs control flow is not easily graspable from reading code. If the object graph is a tangled mess then the team will have an exciting time.
Pulling out the program flow into a large procedural piece of code can look attractive. In my experience such pieces of code incidentally are found in ..Service ..Manager classes the speaker is not so fond of. At times this may be a clearer and more effective approach than managing the object graph and distributing logic to messages. But going to procedures of several hundred lines is imho going to far.
When I think about it then software needs to be testable. If the objects are too trivial and a lot of logic is in their interconnection graph then the risk increases that the important bits are not tested - after all we got close to 100% coverage. But it is still possible to build the graph and test it in a meaningful way. Being OO I can instrument it too with test frameworks. That seems less the case with a longer piece of linear code.
Object-Oriented Programming is Embarrassing: 4 Short Examples[0]
Object-Oriented Programming is Garbage: 3800 SLOC example[1]
[0]: https://www.youtube.com/watch?v=IRTfhkiAqPw [1]: https://www.youtube.com/watch?v=V6VP-2aIcSc
http://www.cc.com/video-clips/cw4el2/the-colbert-report-yahw...
tl;dr Some Mormon leaders say it's incompatible with scripture, though the LDS church hasn't never said anything official.
"Latter-day Saints should strive to use both science and religion to extend knowledge and to build faith." "Is there any conflict between science and religion? There is no conflict in the mind of God, but often there is conflict in the minds of men." http://en.fairmormon.org/Mormonism_and_science/Are_they_comp...
More Sources: http://en.fairmormon.org/Mormonism_and_science/Evolution/Off... http://en.fairmormon.org/Mormon_view_of_the_creation
Although I'm not a member, I lived in a 90% Mormon city for a few years and was made to feel very welcome and accepted.
This necessitates a lot of other background beliefs - immortal soul, individual will, and significant ordinances, to name a few.