I thought the same for a long time and it really discouraged me. My natural pitch recognition is pretty bad.
What helped was starting with very simple melodies and songs, so I could get familiar with the most common movements. That made it easier to figure out progressions, because I learned how to narrow down the options.
I’m still not great at it, but I keep improving. That’s why I think it’s trainable.
Every time I write another DTO → domain → DB mapping layer in Kotlin/TypeScript, I think about Clojure. I’m pretty grateful I learned it. It really changed how I think about software. Still, it’s a trade: less ceremony, more responsibility.
> but it gets in the way when you're rapidly prototyping and exploring.
If you prototype a new features for an existing system, a test let you execute only the code you actually need. This will shorten your feedback loop and allow you to iterate faster. Refactoring a test is fine. Writing a BS test just to explore a solution is fine.
In my experience following a test lead practice will help you build a simpler system which will be easier to maintain.
I'm really greatful for clojure to exist. It exposed me to a lot of concepts and gave me a new perspective to think about problems, which in turn helped me to grow tremendously as a developer.
The emphasis to work directly with the data is quite unique to clojure (as I'm aware of, please proof me wrong on this) which allows me to just dive in and think about the problem I want to solve instead of fighting my language or framework.
The interactivity of the environment paired with immutability results in an instant feedback loop which let me get into mental flow really fast, which is a joy.
You're absolutely right. I guess I mentioned pattern matching in particular because of the cited sentence from OP "I'm still waiting for pattern matching + algebraic data types".
> The same is true for the rest of the things you've mentioned: none are specific to static typing!
Sure, I could be wrong here. I frequently am. But could you point out why do you think that?
For what its worth: People don't use dynamic language because they don't know better or never used a static language. To better understand what dynamic languages bring to the table, here are some disadvantages of static types to consider:
Static types are awesome for local reasoning, but they are not that helpful in the context of the larger system (this already starts at the database, see idempotency mismatch).
Code with static types is sometimes larger and more complex than the problem its trying to solve
They tightly couple data to a type system, which (can) introduce incidental complexity
>(I'm still waiting for pattern matching + algebraic data types)
This is a good example, if you pattern match to a specific structure (e.g. position of fields in your algebraic data type), you tightly coupled your program to this particular structure. If the structure change, you may have to change all the code which pattern matches this structure.