As I've gotten more experienced, I do less "ceremony" and more "write code that does stuff". It hasn't seem to hurt, and I end up with less code to maintain.
Explicit is not always better than implicit. If you're being explicit about obvious facts, that's pointless verbosity. Type inference is a good thing; take advantage of it. Implicit's only an issue when there's complicated or hidden rules at play. For instance with automatic conversion operators that do "magic".
(ok, you can use a fake smtp server, but it makes tests more complex, imo)
Though I was explicitly referring to the case where the code is literally rewriting static functions into objects without using any actual OO features - just adding extra noise.
This code does tend toward smaller more compact expression, but you're chasing the simplicity more than the literal absolute size.
Absolutely. A clever one-liner may make sense to you _now_, but try coming back to it after a few years when you've moved on to another language/paradigm and can't remember the subtleties of what you've written. I believe "Write Less Code" should be taken to mean "Write modular, reusable code that reduces boilerplate and emphasizes the underlying business logic". Clarity should be the key driver here. Shorter code helps, but it's only a means to an end, rather than the end itself.
So what's the distinction between simply making a passable program and working smarter, without unnecessary logic? It's hard to understand or even believe unless you've seen it happen. Even if you understand and believe, the magnitude of how powerful it is can easily be underestimated.
Take prime factors for example; how would you program it? Most people would probably expect they'll need some kind of primes against which they can factor a given number. You might create the list of primes or have a data source somewhere, and iterate over it looking for prime factors. The result could easily grow into a (small, but) considerable program.
If you practice TDD and "fake it till you make it", testing the next-dumbest case you can wind your way to very elegant algorithms through refactoring against tests. That sounds easy but in reality it often feels silly to test this one other simple edge case or to test every failure case (1..2..3..) and that makes it hard feel worth doing. It's also difficult to look at known-working code and see the other possibilities for how the same result could be accomplished for all cases with a different methodology.
If you haven't yet, check out Bob Martin's primes kata: http://butunclebob.com/ArticleS.UncleBob.ThePrimeFactorsKata (The slides have a lot to be desired but the only video I could find was on vimeo with a lengthy intro and no apparent way to fast-forward)
Chances are we'd rather maintain the simple 3-line algorithm rather than the one with the data source and unnecessary complexity. That doesn't mean shorter is always better, but in many of the problems we face everyday there are elegant solutions hiding in the details. The simpler solutions inherently have less to maintain, for better or worse.
I take pen and paper or whiteboard and spend considerable time to model the problem in pseudocode and graphs (not UML, the horror, just lines and boxes) before I start banging code.
For trivial adapter code etc. this approach is pointless but the larger and more complex the component, the more it pays off.
It can also mean to employ existing libraries where it makes sense, and to utilize code generators for tasks they are suited for (e.g. writing tests with lots of combunatorial excess or implementing interfaces on top of an FFI).
One has got to be careful with this...
Sometimes making code more concise really makes it more obscure. I suppose it's possible err on both sides, you don't want to be too verbose either. I think the point is to write readable, maintainable code.
"explicit is better than implicit"