I started at working Salesforce in around this time 2014. So pretty soon I've spent about even time on two different teams over 4 years. It went very quickly.
My first couple years were heavy in Ruby using object-oriented paradigms and though I really enjoyed using Ruby and the many creature comforts that came with it, it also had a lot of drawbacks as a language. Using Ruby meant that you were choosing ease over performance. Attempts at using concurrency were pretty frustrating and complicated.
Around 2 years ago, I made my new team decision primarily based on 2 opportunities: the opportunity for learning functional programming practices and Clojure... and choosing to work with the guy I actually sat next to most of the previous couple years. Neither of these was a mistake.
During my first 2 years at Salesforce, I came to these conclusions:
- Separate concerns when using structured data: Data in storage/transport should be as flat as possible. Deeply nested data creates tight bindings to structure where they shouldn't exist. A list of hashmaps is about as deep as it should get. Restructure data into an index when it needs to be accessed quickly.
- All software is trade-offs: Rapid prototyping vs. maturity/scalability... Simplicity vs. Code Re-use... Get it working and don't over-generalize isn't a bad principle but assumes that the software will always be under active development and you will eventually get around to refactoring the code to allow it to grow into it's next phase.
- Nearly all of my achievements are marked with pride and some amount of horror. Things that seem like minor decisions end up having long term implications. Things that were expected to solve a problem in the short term continue their service longer than expected.
I also had deep concerns about the simplicity of object-oriented coding but I couldn't have said much about it. Now, after a couple years of clojure and watching Rich Hickey videos, I think I can articulate it better. In a nutshell, it's really hard to use objects without getting wrapped up in how they work internally. This is one of the reasons I liked pry, which let you interrogate any object to get at it's methods and documentation in a REPL.
After letting myself immerse in clojure land for a couple years, I have a preference for functions that do data manipulations over objects. (I still haven't gotten fully used to namespaced keys but that is coming.)
Even when I write in python these days I tend not to use classes, prefering functions such as map and filter along with simple data collections like arrays and dicts (though I much prefer clojure's idempotent handling model which assumes that no data that you have a reference to will change underneath you without it being explicitly so in the form of an atom).
Controversially, I think that:
- Object-Oriented ought not be the default model and needs to be justified for the expense it imposes. The expense it imposes is that you need to be aware of it's internals and given the choice between being handed data and being handed objects, I'd rather be handed data. We do need solutions for managing state and for code reuse.
- Implicitness and indirection also need to be justified. You need to know what you're getting in exchange and it needs to be worth it. The sacrifices are often in readability. How much shuttling do you have to do between the top of your file/function/class and where you are? It all has a cost.
These are more weakly-held observations:
- Any system that includes a repo with fragile tests will involve people trying to circumvent the repo with fragile tests or slow deploy cycles if these are not addressed quickly.
- Some people believe data shouldn't live in repos but I do... especially if it's seed data for some infrastructure-as-code project. (Since most databases don't have a good notion of history or time.)
- Minimize your deploy surface.
I think it's a good idea to look at facts and form opinions about what works and why. It's good to find out from others who are more believable than you what works for them and why.
I probably did a better job of talking about the what than the why here but my coffee is still kicking in this morning and I'm not really planning to edit this blog post. Which brings me to a final observation:
- Something better than nothing.