A realpolitik view of tech only holds under the assumption that any new technology is good technology. It allows nothing to balance or sustainability, and I believe the trajectory of the Web is unsustainable and therefore fundamentally doomed despite its near-term wonders.
The SV camp has said nothing to convince me otherwise.
Or to put it in other words: browser technology is asked to do so much that they had to go invent a new language to keep up. So that they could serve ads.
For us ordinary folks trying to write good applications that can be maintained by one person and scale reasonably well, there's justifiable reason to jump off this rollercoaster and work in a more humble environment with modest perf/safety tradeoffs and native code executables(e.g. Go, Basic, Pascal).
Dynamic types, OO with some extension for functional style, inherited Algol syntax with some homegrown innovations, batteries-included design. Where they differ, it's largely in whether they bend towards consistent style(Python) or more late-binding power(Ruby).
Get yourself into a classroom again. It doesn't have to be an ambitious course. It's a familiar structure and you've been out of it long enough that it'll seem refreshing. While you do that go hit the gym if you aren't, yet. (Or if you want to do it on a budget, get a set of resistance bands.) Set lots of simple goals with structure and regularity. Journal your progress. This will get you back into the thick of things without the nasty obligations of the workplace - by the holidays you might have a good plan together.
Or in other descriptive terms, Forth could be called "point-free" or "tacit". There is no structure given by the code's context, no named arguments to describe what is in scope - all you have is what is on the stack at the moment of execution, and global variables that the program might access by convention.
Point-free can be a very concise and flexible strategy but also error-prone since (in Forth) it allows the stack to leak and consume/return an unbalanced quantity of arguments. This class of error is eliminated within the syntax of Algol style languages languages but can be reproduced easily if you build your own stack machine.
I've cottoned on to the idea of focusing on feedback loops instead of "practices" lately as a way to deal with the kinds of evolutionary changes projects tend to go through.
Practices tend to emerge within a specific project situation as a pragmatic way of addressing concerns. When the practices are communicated across projects a game of telephone is played, the nuances lost, and the meaning is eventually replaced with dogma.
Consider which would be more useful: a workout log that suggests how much additional difficulty you should add each week, or a fixed plan found in a magazine that says that you should be performing an exact workout in each week?
This is the struggle I think programmers really face, because the codebase at any moment in time needs an appropriate "workout plan" to successfully reach the next stage. Sometimes a form of cheat can be used to accelerate it towards a goal, but the concrete progress is reliant on a similar formula to progressive overload cycles.
This focus on feedback also guides healthy cutoffs between prototyping and production solutions: the production solution only makes sense once prototype learning has been done, and the prototype likewise stops making sense when it conflicts with the demands of feedback.
1. I left in the hands of other people
2. I failed to keep it accessible to myself
It's easy to lean too far in one or the other direction by leaving stuff on a commercial service or forgotten on a single device without backups. For most folks, paper wallet and safebox is the appropriate mix since it follows traditional physical security patterns and ensures some protection from theft or damage. A strong secondary option is to be online but obscure and not advertise where your valuable data rests - perhaps your keys exist on a backup service, but they're tucked away such that an attacker has to think to look for them, and to do some forensics to track down their location. This buys time to hear the alarm bells of "your password was reset" and rotate anything valuable out of the compromised accounts.
Under no circumstances would I keep the money within any of these dedicated services: even though I use Coinbase and exchanges, it's too easy to employ social engineering and privilege escalation to get in and take everything, so any value stored in them has be considered "hot", and I only keep the amounts I want to trade on them(which at this moment is $0).
I believe the main size optimization here comes from having only teletype and batch processing interfaces. When you do that, the surface area of the UI, and hence the amount of supporting code, drops tremendously. These early tools also skimped on error messages and checks, so the user experience was generally one of confusion and catastrophic error, despite being small and simple. You really needed the documentation to have any hope of understanding an old system.
Now we have operating systems that go out of their way to automate away everything and present it in real-time with multitasking and custom graphical elements everywhere, while also supporting many more protocols and hardware interfaces - wireless networking, GPU APIs, etc. The biggest growing pains seem to be past - things went from simple and stable to complex and unstable in the 1990's and then to complex and stable but insecure now. There's a lot of room to mature all of these features, but there aren't as many novel ones.
I keep a minimal form of journal for all life events. I briefly describe a thing I did or a thing that happened, and how much energy it took me to go through it on a 0 to 4 scale, where 0 is breathing and 4 is major life crisis. If I think there was a lesson I write the lesson too.
This creates a feedback loop for stress reduction where I aim to mitigate both the likelihood of having a crisis and train a calm response by learning how to deal with smaller stuff so that the day is full of 1's. I chuck it all in a text file once a day, and return to it because my todo is also in there so I always have a backlog. I don't distinguish between work and hone tasks although I might if I were going in to an office.
Long form diaries I don't really engage with because they'd sap relatively more time - I would get caught in trying to make it a storytelling experience.
That is to say, there are probably hundreds of things, off the top of your head, that bother you and probably bother others. To the best of your ability choose one that you have a clear "thread to pull on" - as in, there is an action here you could take that might not be elegant, might not scale, be politically heated, or put you in a position beyond your understanding, ultimately require a team or need financing. But you could do it NOW and not just dream about it, consequences be damned. When the potential is scary like that, that means you actually hold a lot of leverage to unleash new forces, just by starting on it and not stopping.
Most of software isn't like that: it's predictable in its design, it automates a thing that was done slower or less effectively before. It fits into the system and stays within the lines. So you also won't find many examples for the particular thread you're pulling on, and that's expected.
If you do this and it's something you personally care about and will pour heart and soul into, you're doing about as much as anyone could hope for. You won't and can't get all of it right - but what people need isn't perfection, so much as a vehicle that will last well enough for the journey.
Just wanted to say that I admired GalaXynth when it came out. I still have the demo and mean to give it another go sometime. As you're probably well aware the justifications to buy a synth are hard to pin down and if you made a second run at the concept with a focus on fleshing out "traditional" features I bet there would be some breakthroughs.
For clients, JS runtimes offer a more polished experience on average than Java. That's not because of anything really intrinsic to the languages or platforms - it's just worked out that there is a lot of Java server code and a lot of JS client code, and consequently more catering to either of those extremes.
My number one piece of programming advice is that you can always find a simpler way - and if you have R&D time to sink into simplifying your problem, doing so is a good idea - but actually simplifying is a very hard task and there is no blogpost tip or design pattern that will do it: it requires knowing your problem very deeply and being willing to shave a few yaks and reinvent a few wheels and generally grind away at something that was already solved, but in a way you find dissatisfying.
If the problem is genuinely original to you, your best bet is to find the biggest leveraging factors(language, tools, libraries, etc.) and consistently lean on those to arrive at a solution fast, then pay down the resulting debt in dependencies, performance and gaps in UX later. This can actually aid in an R&D effort because reaching a clunky solution quickly will lend a certain maturity to the codebase and the problem you're addressing. But it means being willing to read and reuse code that you are personally uncomfortable with and know does not really solve the specified problem exactly. This is a revision-heavy process and it's antithetical to what many programmers are inclined to do - which is to get everything finalized in one shot, drawing on all the stuff they know is the "best practice" even if it's tangential to shipping.
The more you're willing to allow your code to be "knowingly wrong" in ways that are easy to call out and to return to later, the faster you can get to the stage when actually revising it has value. This is why everyone writes bad code yet some code looks better than others: the good code was bad code that solved the right problem, then revised.
I think the main point to focus on is not the relative condition of liveliness, but the mechanism of its generation - which is to have and engage with difficult life problems, struggling against them each day, even while knowing that there's some absurdity to it(because the premises are so often arbitrary).
In the popular context this always maps onto basic survival since it's very relatable and immediate: but for a person in a slightly more privileged state the problem is one of picking the thing to struggle with, because it's possible to walk away from so much of it, find a distraction and squander one more day. If walking away from everything were really the answer, suicide would be success, and we are disinclined to want to believe that. Neither does it work to try to engage with every problem you see as there are too many of those and you aren't going to be effective at all of them.
This motivates many of the conclusions of Stoic thought: the moderation, the development of awareness about one's sphere of control.
It's a tough nut to crack. Open source contributors tend to want to dive in and make the one patch they want without engaging in any design or feedback process. Installing that process means someone has to take up managerial duties. Most projects stumble along with a "one coder army" who expedites these processes by assuming anything they can't do on their lonesome is out of scope, and all feedback, patches or design ideas are strictly suggestion. Switching to a team management approach when a project gets big is a big source of friction since it's rare to have a strong solo dev who is equally capable at giving up direct control and delegating. Usage of a project is often mismatched with development energy, creating unbalanced workloads.
So the tendency ends up being that a lot of projects just stay small and go out of their way not to grow, even when they address a problem that demands more scope than they have.
My suggestion given all of that is to not give up, but focus your design energies on the inspirational: if you produce mockups and prototypes that are hugely compelling, someone will come out of the woodwork to realize some of them: you may not know which ones or when, but you're giving them footholds in approaching the problem.
What else is "scripting" but that act of making a very small automation of a business function? Is a customized spreadsheet a tool?
There's always going to be demand for tools of many kinds, so whatever you're offering has to differentiate better than "internal tool". The abstract you give is kind of like a software framework, possibly with some form of high level scripting, configurator, or wizard to guide the user.
At the end of the day always evaluate your solution against a short bash or Python script. Did your solution gain anything? If not, why?
It barely registered for me at the time that Python had changed. But using it back then, it felt quite a bit similar between late 1.x and early 2.x, just with creature comforts gradually appearing and bulking up the language:
No decorators
Old-style classes(a distinction that makes almost no difference if you are using the class as a simple container with no inherited methods).
List comprehensions appeared in 2.0 and I struggled to grasp them for a little while.
The runtime might not have supported any cyclical reference collection(or I was just unaware at that point, being a student).
No iterators (2.1) or generators (2.2)
Python 1 to 2 was a simple transition, as it didn't do much to reassess the language's basics.
Python, because it's the rare combination of "wildly popular" and "keeps you out of trouble". Ruby has always had a one-framework-town kind of feel to it, with Rails being the one thing people automatically associate with the language. Javascript has the popularity, on the other hand, but it's a minefield in so many ways. The browser is not fun to work with for anything serious, and code written in node bitrots very easily.
So, it's Python. Python has footholds in a variety of places. It's not the most expressive in some respects, but the built in types are more than sufficient to power any student code.
A possible alternate is Go. Go doubles down on keeping you out of trouble by pressing so much code into a uniform style. This may excite some students and frustrate others depending on which threads of thought they're trying to follow.
I ended up making a custom data structure and query language around this kind of notation. Not in Python(am working in Haxe) but easily generalized. The structure is either array or string map or ordered string map with a dynamic data field and optional string tags. So it maps very well onto JSON or XML style data, but comes with the benefit of a very unambiguous way to do queries, where I can mix together addressing styles(take this numbered index OR take the named key) and pull elements into an array without much difficulty. The lookup syntax is "@<key>#<index>..." and each key or index entry is parsed into an ADT. I can pass along partially constructed queries as the relevant data to be processed. It's not quite as flexible as SQL since the data has to come in tree form, but it creates a major design affordance: the same query can be passed to a custom algorithm or custom data structure, with less ambiguity than a simple string lookup.
To some extent this retreads ground covered by e.g. XPath, but the specific structure puts it closer to my day-to-day needs.
The SV camp has said nothing to convince me otherwise.