I Lost Faith in the Industry, Burned Out, but the Cult of the Tool Saved Me
habr.com
habr.com
I couldn't even imagine giving up Ruby's elegant object model for the verbosity of a static typing system. So when people tell me that Ruby or Rails is magical, I'm like, yeah, in a good way. But the arcane correspondences just aren't very accessible. If I want a functional programming model, I just code one up out of the basic building blocks of ruby. If I want a type system, I can make one.
var done = false
let language = “russian”
let languages = [“english”, “french”, “german”, “russian”]
let dictionary = [1:"english", 2:"french", 3:"german", 4:"russian"]
The types are implied. The use of ‘let’ means immutable.
I believe F# goes even farther but the verbose typing of a generation ago is almost gone.
int x = 1;
BigOldClass y = new BigOldClass()
Dictionary<int, List<string>> z = new Dictionary<int, List<string>>();
int[] p = new int[] {1, 2, 3};
In modern C#, you can write cleaner code like this: var x = 1; // type is inferred
var y = new BigOldClass(); // syntactic sugar to avoid repetition
var z = new Dictionary<int, List<string>>();
var p = new [] {1, 2, 3};
Still strongly, statically typed, and obviously typed.So you can often write large chunks of code with no specified types, but everything is still statically typed. Granted this is maybe not always good, sometimes it is productive to have types in the function signatures, though the IDE can supply these automatically with codelens featuers/on hover features.
To me var is only useful for writing generic lambdas & similar - you shouldn't use for regular variables.
var i = someFunctionWithANonObviousReturnType();
Type inference may be easy when the left-hand side is a literal, but that's often not the case. And when the left-hand side isn't a literal, it definitely optimizes writing code at the expense of reading code. You can argue that IDEs should be helping us by show us the type when we mouse over or auto-completing available methods on the variable's type, but there are situations (code review, pair programming, etc) where we can't rely on tooling to help in this regard. I get why people like type inference and I use languages that have it on a daily basis, but I've also realized that I need to adapt my coding style to it or I'll end up with code that's difficult to read. In particular, I'm constantly considering whether the code I'm writing is understandable using local reasoning only and that I'm not forcing a reader of my code (who's likely to be me several months from now) to jump to some declaration somewhere else in the code.
var i:ReturnType = someFunctionWithANonObviousReturnType
I found that in practice I don't need it.
All lines however are statically typed.
Hindley-Milner type inference (like used in F#) isn't hugely more complex; it's more aggressive at using type variables to generalize the code, and applies type unification in more situations.
Worth pointing out such type inference is hardly a new idea e.g. see the ML type system: https://en.wikipedia.org/wiki/ML_(programming_language) which Wikipedia says first appeared in 1973. This actually traces its roots to the typed lambda calculus which predates electronic computers.
However I think it is fair to say that type inference systems are finally appearing in more 'mainstream' statically typed languages (for example the auto keyword in C++ and your Swift examples).
Pattern matching is another concept that’s making its way into popular programming.
https://www.bignerdranch.com/blog/pro-pattern-matching-in-sw...
https://stackoverflow.com/questions/2502354/what-is-pattern-...
C# and Java are also adding this feature.
We’re taking the long way to becoming Haskell and oCaml programmers.
I was just about ready to exit programming entirely before I discovered Elixir, just because I got tired of dealing with the...exact...same...problems...in...every...single...dang...language.
Elixir essentially forces you into a mode of operation that hits that perfect balance of productivity and concise code with a structure that inherently avoids almost every long term code base problem that I've dealt with in my career.
It got me excited about programming again, which I didn't think was possible that far into my career.
I've been through this same problem, even with Ruby. What I ultimately had to realize is that you have to just get really really familiar with Ruby before you can get a taste for its superpowers. I don't think it has all that much to do with languages / stacks, though I do think it matters to a certain extent.
I personally don't mind seeing warts in a Ruby codebase, because it means I'm at least working with Ruby. I've been violently dragged kicking and screaming away from Ruby more times than I ever want to see in my career.
I used to argue strongly against types and functional programming, but that was before I actually knew the paradigm at all. I wonder if you have tried building anything non-trivial in a Typed Functional language, or even a different paradigm like logic programming. If you have and are not convinced, that'd be a great discussion to have. If you haven't, then based on my own experience, I think you might shift your opinions after spending a year or so with it.
Matz took a unique approach when he decided to optimize for programmer happiness vs the machine and it turned out awesome.
I wonder though if you have evaluated Crystal?
I had a similar revelation with Lisp and Clojure. Writing in a language you enjoy using and are very productive in (effort->effect) is really liberating.
The great thing is even when I have to return to the old ways (Java) Clojure's java interop makes writing the Java a lot more manageable, almost fun.
I don't know whether it's the functional paradigm, the dynamic typing (I didn't have the same revelation with Ruby/JS), immutable collection by default, the minimal lisp syntax, etc.
It just feels right.
I find myself highly productive writing "mostly functional" code in C# using LINQPad. The only thing that drags me down is that it doesn't have good support for data structures that you can copy on the cheap a-la Clojure. The paradigm of "copy the world on change" is immensely powerful. Maybe I should look deeper into this. It seems that basic data structures for this wouldn't be very hard to implement on my own.
I think the ideal language for me would have functional, strongly typed capabilities for low-level operations and dynamic, late bound objects a-la Smalltalk for high-level stuff. But for this to work well it would need to have strong mechanism for versioning references, so functional parts don't get contaminated with mutability.
Oh, another thing about C#. I really wish it had an ability to concisely say "take an object, create a subclass of its class with additional properties, instantiate it, copy all values from source and then set extra properties to what I just provided".
Something x = new Something { Property = "Hello" };
var y = x.Expand(me => new { AnotherProperty = me.Property + " World" });
Assert(y is Something);
Assert(y.Property == "Hello");
Assert(y.AnotherProperty == "Hello World");
Seems like a weird piece of functionality, sort-of-union-types, but it would save me tons of code in many, many contexts.I can implement this using reflection, but it will be slow and complicated and not worth the effort. Maybe the new tuple mechanisms can do something of this sort with minimal overhead and syntax. Need to look into them.
That explains why OP got depressed, considered quitting the industry and then switched to F#. If I keep using TypeScript, I might just snap and switch to COBOL.
Maybe not this person's case, I wouldn't be too surprised if someone has another reason, but I seriously haven't heard anyone else with a strong opinion against typescript founded upon any other context. I could probably google around for other reasons.
That sounds kind of like saying, "the vast majority of people with cilantro in their burritos like cilantro."
But in general, yeah, it's kind of like that saying :)
Perhaps this leads to a different coding styles & expectations. The former end up with a preference for strong typing. Perhaps their coding style also depends on that.
The latter don't seem to find types to be a source of bugs.
Like early childhood experiences, each programmer I've discussed the subject with seems to have their own unique professional experience that has molded their opinions. It's less a religion and more a coping mechanism for bad experiences.
TypeScript gives an illusion of added productivity and safety but when you actually look at results, bug density is exactly the same as JavaScript.
As a TS developer, most of your time is spent on catering to the compiler's complaints, but doing so doesn't actually yield any benefits in terms of producing high quality software.
TS and TSLint are bandaid solutions which don't address the root problems behind what makes code bad (which 99% of the time comes down to bad design/architecture). TS simply cannot prevent bad design/architecture - It can only formalize it.
It's nice to have linted code with everything typed and statically locked into place but that means very little in terms of actual code quality.
Weak typing and dynamism just don't go well together, but other combinations are fine. Strong dynamic typing can lead to an "exploratory" approach to coding that looks a bit like what the author describes except that you can do it in such a way that your program compiles and runs the whole time you are fleshing it out, which is nice.
I find this sort of exploratory programming to be by far the most productive available in a research/prototyping mode. I do think the model falls down a bit when multiple programmers are involved, and in production. You could argue this is a feature though, as it is strong incentive to not ship the prototype ...
I mean, I started with Pascal, then C and C++, then PHP, then Ruby then C# and some Java, then Scala, then JavaScript, and now Elixir and TypeScript. Of all those, I like TypeScript the best (barring the NPM / deployment / transpilation / packaging mess, that is). I mean, I like it the best by far. It combines functional with OO much like Scala set out to do, but in a much simpler and more accessible way. I really love it, I think in its structures. All JS I write feels like TypeScript. Even a lot of the Elixir I write (for better or worse) feels like TypeScript with a funny syntax.
I now feel like structural typing is the big missed opportunity of most statically typed languages. The fact that I can define a type simply by writing, say, an object literal, continues to make my day.
let a = { name: "Pete", age: 6 };
a.nmae = 7; // type error!
a = { nmae: "Mike", age: 7 }; // type error!
or even function moo() {
return { name: "Pete", age: 6 };
}
const a = moo();
a.+---------------------+
|name string |
|age number |
+---------------------+
Stuff like this feels so normal so quickly that I feel like I'm using yesterday's tools whenever I either don't get the autocomplete/type error (hi Elixir, Ruby, Python, PHP), or I have to manually add a `type Moo = yada yada` declaration above my function (hi Haskell, Scala, C#, F#, Java, srsly all of them).I'm not claiming any of this is new. I mean truth is I haven't seen any Haskell or F# or Scala code that does this, but I bet that's just my limited exposure to functional languages. I've heard these languages are pretty powerful, so sorry if I insulted your cult there :-)
Still, I've used no other language that enables this ability to write code the way one would write dynamically typed code - head-first, straight down into the operational stuff, and finetune the data structures as we go along - while still getting type checking and all the confidence and tool support that comes with it for free.
I agree with the OP. TypeScript is my cult. <3
As compatible as it is, there is definitely a lot of friction/awkwardness around type-casting JSON objects to typed objects within a statically typed programming language; there is an impedance mismatch. It's not as awkward as trying to type cast objects designed under one type system to a different type system (e.g. SOAP APIs) but it's still really awkward.
The impedance mismatch goes away completely if you use a dynamically typed language like JavaScript. For example, JSON produced by a python program can be parsed by a JavaScript/Node.js program without any issues.
The root reason why types are bad is because they're opinionated. There is no absolute right way to type something; and because of this, it's not correct to force other projects which interface with your project to adhere to your type definitions.
Maybe I'm just annoyed by his slight on public transportation.
For me, it was Ruby. I have stopped writing Ruby code and have found other languages that I love now (yes including Typescript), but nothing will replace the enlightenment rush of Ruby.
I think all programming languages that exist today are a symbolic representation of different kind of mental models that humans have. When you find one that synchronises with your mental model, it's just magical.
https://news.ycombinator.com/newsguidelines.html
I didn't read it super closely but it seems obvious he's just using that language as a form of self-criticism. No need to pile on. (Edit: also, I think some of this is cultural differences.)
The thing about Flatland is the twist at the end, when Square asks Sphere about even higher dimensions (than three) and Sphere is unwilling to consider them.
(I guess what I'm saying is, if you like Functional Programming, try Prolog. Logical Paradigm is even more useful than Functional Paradigm.)
However, trying to get up and running on a Mac, the documentation is horrible. I looked at several of the official guides, including the Microsoft site on how to get running with VSCode, and none of them worked without having to search for the error messages.
Now that I'm up and running, none of the docs I could find would tell me how to build/run a project.
It appears you to install the .NET Core SDK, and now trying to build a project gives some ".NETFramework,Version=v4.6.1" error.
What a nightmare. I almost expected this since this is a .NET/Microsoft related project.
1. Install the dotnet core sdk 2. From a command line in an empty folder, run `dotnet new console -lang F#` 3. To build or run use `dotnet build` or `dotnet run`
I followed the VSCode instructions and using "F# new project" apparently gave me a .fsproj with the wrong TargetFramework, and after changing that, then got a "Could not load file or assembly 'FSharp.Core" error.
But there is still a lot of outdated docs out there. dotnet core has just come too fast, imo (though I'm thankful). These MS docs are accurate: https://docs.microsoft.com/en-us/dotnet/fsharp/get-started/g.... Though it does specify the use of sln, which isnt necessary for small projects.
It just makes programming so much more fun — all the tedium is gone, it feels like every character you write is actually important.
I think the lesson is: If you get burnt out, try changing your tooling for something more modern. If it ever happens to me again - I will try to have the clarity of mind to do it again.
Object-oriented programming has its drawbacks, of course.
But your monologue here is a bit grandiose. It reminds me of the narrator in Zen and the Art of Motorcycle Maintenance as he reached the pinnacle of his insight into metaphysical Quality. He was actually just going mad, of course.
Maybe you had communication difficulties with other people because you were having a severe case of burnout that verged on a nervous breakdown? In any case, I'm glad you're feeling better.
They say it takes 10 years to become an expert in anything. In my case, with OOP, I did it in 6. I would highly advise to anyone that once you become expert level in anything - don't hang around for long: make sure you've got the next meal ready for your brain as it will hate you if you haven't.
Was not intentionally grandiose. The intention was to avoid superfluous detail given the context.
Thanks
I'll take it on good faith that you are indeed an expert, and are a gifted learner. Great! I'm jealous :)
But you might want to consider the way you talk about yourself to other people. Even from a selfish perspective, becoming an expert in communication reaps many rewards - and the right level of humility is very important in communication. Both your comments come off as very egotistical, although I'm sure that wasn't your intention.
Care to provide examples of the patterns? Genuinely curious
> I was so high up on the peak of the C# mountain that recruiters could no longer understand me, employers could no longer understand me, co-workers could no longer understand me
What sort of things were you saying that led to people not understanding you? I can't imagine knowing a language so well that others can no longer understand me