More Tech-related Rambling:
Programming languages
I am a big fan of the rapid prototyping and ergonomics of scripting languages like Python, Ruby, and Javascript - but also of the safety, legibility, and self-documenting nature of static typing. Modern languages like C# and TypeScript with extensive type inference and minimal boilerplate strike a nice balance here.
I like the immutability, elegance, succinctness, lazy evaluation, map/reduce/list constructs, sound type systems, and so on of many functional programming languages and the overall functional programming paradigm. Lisp(s) and Haskell, for example, have cool approaches. I have enjoyed seeing many of these insights picked up and adapted into both scripting languages and contemporary C#, Java, etc.
Rust's approach to achieving systems-programming-level performance, along with memory safety from the borrow checker/lifetimes, and lots of other safety constructs like Option<> types and no nulls, exhaustive pattern matching, and an overall elegant type system is another recent interest of mine.
Organizational
Good code is not just a matter of programming languages, frameworks, tools, or even individual intelligence and discipline - it is also a function of readability, best practices, interpersonal relationships, processes, and institutions. No codebase, and no section of code, will remain unchanged, or be read and maintained by the same person or group of people in perpetuity, so good software development is as much about managing change and uncertainty as it is about writing code.
Readability, documentation, knowledge sharing/transfer
Because code is read many more times than it is written, readability is paramount. Someone other than us - or a future version of us, now a different person! - will read our code in the future, and the more quickly and easily they can parse what is going on, they more likely they are modify or use it in ways that make sense and will not cause bugs.
Readability and "self-documenting" code go a long way to ensuring our teammates and successors understand the code and the product, but don't go far enough. There will always be a certain amount of institutional knowledge about the codebase and product that are required to effectively work on it, even if it is implicit, or the "institution" is a single individual. If it is implicit, and passed on as "tribal knowledge", then when new people join the team or existing people leave, there will be unnecessary confusion and lots of wasted time and trial and error needed to transmit or recover that knowledge, or worse, it will be lost entirely and the code/product maintained with an incomplete or incorrect understanding that is likely to cause bugs and feature attrition as code is used or altered in unintended ways and features or functionality known to the original authors of the code are forgotten, broken, and lost by new maintainers.
A certain amount of documentation, and conscious knowledge-sharing and knowledge transfer, are therefore essential to fight against these natural processes of degradation. An important concept is that of the "bus test": is there anyone on your team who, if they were hit by a bus tomorrow, would cripple the team? What knowledge or experience would be irreversibly lost? At any given time, any important knowledge or experience with a particular area or aspect of the product/code should be shared by at least two, or ideally three or more, people to prevent this kind of problem. Having people on a team with long-term experience and commitment is great and very valuable, but we have to confront the reality that we are in a high-turnover industry where we cannot assume or control how long any of our teammates will be with us.
Change, decay, and testing
Because code will change, or the codebase around it, or the inputs and context of the software and real world around it will change, or the people maintaining it will change, it has to be resilient to that change. One important aspect of that is the readability, documentation, and knowledge-sharing mentioned above, but that is not sufficient. No matter how good our code is, there will be bugs, existing or introduced.
One important way we can avoid feature decay is with automated testing, which functions as a kind of self-enforcing documentation. Ideally, whenever we add a feature or fix a bug, we write a test to ensure it continues working. Then, when we make changes in the future, we will know immediately when we break something, and what the intended behavior is that we need to restore. Unfortunately, in the real world this is in my experience rare, due to time and resource pressure. But we can reach towards this aspirational goal, and focus on writing tests for the most important or newest functionality, and the most important, time-consuming, or recurrent bugs, to avoid them breaking.
This slows the process of decay considerably and saves lots of developer effort and time - and thus money! The less time is wasted on finding, reproducing, and fixing bugs that could have simply been avoided in the first place, the more time is available for building out new features and responding to customer demands, the more customer value is created. This means less money spent paying developers, and happier customers who will pay more and spread the word, bringing in new customers, which means more revenue. So while spending a lot time and effort paying testers or developers to write and maintain tests for features and bugs might seem to slow feature output and increase costs in the short term, it speeds feature output, reduces costs, and increases revenues and profits in the medium and long term, especially as a product matures and ages and the original developers move on or the team grows.
Planning, Agile, Team Process
On paper, it would seem that there is only approach to planning and process in software development today - Agile. In practice, "Agile" implemented differently in every company, and frequently devolves from how it is supposed to work in one or both of two ways. Not that we should be dogmatic and treat the Agile Manifesto as a sort of immutable holy text - far from it! It seems clear that this sort of attitude to processes and "best practices" is precisely what Agile was, in large part, created to avoid. Nevertheless, I do in fact think that Agile is a Good Idea and which is rarely implemented correctly, and the spirit of which is often lost.
The first of the two main ways Agile tends to decay is precisely through this sort of cargo-cult mentality where the processes and forms are carefully observed and dutifully run through, but in such a way that they are more form than substance, a sort of set of ritual behaviors intended to appeal to the gods of software development and call forth productivity, code quality, and correctness from the heavens. Every possible meeting considered part of agile or scrum process is called, and meets for as much time as possible. All matters are discussed, and all actions taken in Jira accordingly. Everyone ticks each box and signs and dates on the appropriate lines. However the result is an excess of time spent in meetings and processes, detracting from devlopment time and developer focus, and something which often comes to resemble Waterfall done repeatedly and on a smaller scale and faster timeline. Rigidity and bureaucracy reign.
The other main way Agile devolves is into an excuse for lack of planning. Planning meetings are skipped, or involve only product management, excluding on-the-ground devs and testers, and leading to siloing and lack of real ground-level context. Reviews and retrospectives are cut back, watered down, or eliminated, leading to loss of the feedback loop between customers and the dev team, and between the dev team and its own output. Without ongoing evaluation of results, critique of our own work and processes, and tweaking things to try to live up to our own goals and those of the customer and management, quality, engagement, and output decline. Without recording and considering metrics, however crude, we don't know how much we are getting done, how productive we are, if our productivity is declining, if we have more or fewer bugs than before, what our code coverage is, or if the performance of the product is worsening or improving.
If we don't spend adequate time planning, or involve developers in planning, or consult product owners in planning, developers are confronted with poorly defined, under-specified tickets. This leads to time wasted trying to figure out what the intended feature or described bug is even supposed to be, or getting to work and producing something that isn't what the product owner or customer intended, and then having to go back and redo much of the work, perhaps multiple times. If work is not estimated, or poorly estimated - perhaps because it was not succiently planned or thought out - deadlines will be missed, or team members will run out of work and be stuck waiting for something else to be done or have to pick up whatever work they can find, which may not be the top priority the team should be focused on. Repeated missed deadlines, an excess of hotfix releases reacting to poorly executed work, and an overall envionment of constant time crunch will result. The team will constantly be on the back foot, reacting to events and putting out fires, rather than proactively addressing problems before they arise or delivering features before customers realize they need or want them. Wild west, shoot-from-the-hip attitudes prevail, work is shoddy, morale is low, and management and customers are consistently dissapointed with results.
Communication, collaboration, and culture
Communication is another practice and skill that is lauded more than it is practiced. Frequent and effective communication and collaboration is essential to a smoothly-running team and quality product. Lack of communication leads to all the same problems as lack of planning or documentation - time wasted reinventing the wheel, implementing things incorrectly due to lack of understanding, lack of coordination that results in one person being stuck having to wait for someone or something else, spending lots of time figuring out something that someone else could have shown or told you in just a few minutes.
Communication is also a function not just of individual effort or inclination, but also of culture and process. When members of a team are comfortable with one other, like each other, are used to communicating regularly with one another, and have frequent recurring meetings or events that that provide a set-aside opportunity for communication or force a certain amount of it, more communication will happen organically and when it is actually needed or useful. When people frequently communicate with people in other roles/functions, and teams are cross-functional, there is less siloing and decisions in all areas are made with more context and coordination. Ultimately, it is all about reducing the barriers to communication , and culture and process are some of the most important ways of doing this.
None of this is to say that everyone on a team needs to be best friends or that there is no such thing as an excess of communication. We don"t need to be friends , per se, to be cordial, professional, and communicative with one another, and work effectively together. And too much mixing of work and personal life can cause problems with both - it can lead to unprofessional behavior in the workplace, or exclusion of those who might prefer to keep their work life separate from their personal life, or who have different backgrounds or interests than other members of the team or company. "Culture fit" should not become an excuse for a workplace where only people with the same hobbies, interests, and demographic backgrounds or welcome or present, or be allowed to accidentally create such an environment. And an excess of communication can create too many interruptions and distractions for the sustained focus and flow needed for coding, debugging, and problem-solving.
Ideally, team culture should encourage communication and cameraderie to ensure information flows effectively and wasted effort is minimized, without creating an overly informal or unprofessional atmosphere. Questions and critiques should be freely given and taken without affront or assuming ill intent, so that every member of the team and the team itself can catch mistakes and continuously improve. At the same time, derogatory or unprofessional comments should of course be discouraged. In other words, obey the Robustness Principle: be conservative in what you do, and liberal in what you accept from others.