In the vast and fast-paced field of software engineering, constant change is the only constant. New tools, technologies, and methodologies are continuously sprouting up, and every year brings an avalanche of change that could easily overwhelm even the most diligent and studious engineer. With the bewildering speed of change, it's easy to get lost in the ever-evolving labyrinth of specifics. However, to ride this tidal wave of change, one must ground themselves in the evergreen concepts of software engineering. These broad concepts, methodologies, and principles underlie the endless list of specifics, providing a solid foundation to navigate through the tumultuous sea of change.
Understanding the importance of separating the general from the specifics is akin to learning to distinguish the forest from the trees. While the trees represent the various technologies, tools, and languages you may use in software engineering, the forest represents the broad, fundamental principles underlying these elements. This article aims to elaborate on the importance of this distinction and its profound effect on long-term adaptability and growth in the field of software engineering.
Separating the General from the Specifics: An Analogy
Consider this: When learning to drive, you are taught the principles of operating any car. You learn how to steer, change gears, use the indicators, and brake. These principles remain consistent regardless of whether you're driving a sedan or an SUV, a manual transmission or an automatic. While different car models have varying features and controls, the fundamental principles of driving remain unchanged. This general knowledge is what allows you to drive virtually any car with minimal adjustments.
This is a fitting analogy for understanding the dichotomy between general concepts and specifics in software engineering. The general principles represent the fundamental, high-level concepts and principles like algorithmic thinking, problem-solving, and software design patterns. The specifics, on the other hand, represent particular tools, languages, frameworks, or libraries, much like different car models in our driving example.
The Pillars of Evergreen Software Engineering
Understanding the core, evergreen concepts in software engineering, allows you to grasp the bedrock on which effective software engineering rests. I have found that developing deep knowledge in these evergreen principles and techniques make engineering a truly fluid process. It does not matter what tool or language is in question, we can ram up and get up to speed and loiter in the deepest trenches of the most eccentric engineering techniques
Understanding and developing mental models for how systems and paradigms work. Also understanding that systems , paradigms and abstraction themselves are recursive concepts.
For example, do you know how a process tree works? How does an event loop work, how does a game loop work? how does mark and sweep work ? Why does Garbage Collection cause a pause. How does thread locking work? Also knowing how wide or deep the mental model needs to span in the context of the problem being solved is also another consideration.
Cross Pollinating Rival Paradigms
No one paradigm, concept, belief, opinion, solution or methodology is the best or the worst. Everything has an inherent duality, inequality, entropy and efficiency ratio. For example OOP is not better or worse than FP or Procedural. C++ is not better or worse than RUST. SQL is not Better or Worse than NOSQL. It is all context bound. Drawing from every paradigm and mixing it to solve problems is powerful and less practiced.
Focus and learn ever green techniques like caching, performance profiling, Here are some more examples. This is by no means an exhaustive list but just to get a general Idea through concrete examples:
Memoization: This is a specific type of caching used in computer programming where the results of expensive function calls are stored, and when the same inputs occur again, the stored result is returned instead of recalculating it.
Load Balancing: This technique helps distribute workloads across multiple computing resources, such as computers, a computer cluster, network links, central processing units, or disk drives to optimise resource usage, maximize throughput, minimise response time, and avoid overload.
Concurrency Control: Techniques like locks and semaphores help manage concurrent access to a shared resource, preventing conflicts and ensuring data consistency.
Error and Exception Handling: Implementing robust error handling in software applications ensures that the system can gracefully handle failures and continue to function or fail safely.
Lazy/Dynamic Loading: This technique delays the initialisation or loading of resources until they're needed. This can improve the efficiency of the system and the user experience, especially in applications that deal with a lot of data or resources. Dynamic loading can be done in most modern programming languages. Yes even in C.
Database Indexing: This technique is used to speed up the retrieval of data from a database. Indexes are created for specific columns in database tables, so the queries that search for certain data can find it quickly.
Sharding/Partitioning: This is a method of splitting and storing a single logical dataset in multiple databases. By doing so, the system can process data in a more manageable way, leading to increased capacity and performance.
Polling and Interrupts: In the context of software engineering, polling is a technique where the system repeatedly checks the status of external devices, while interrupts provide a way to get the attention of the processor when a task is done or a condition is met.
Message Queues: In distributed systems, message queues provide a way for applications to asynchronously communicate with each other, which can improve scalability and fault tolerance.
Profiling: This involves monitoring the behaviour of a program when it's executed to gather data about memory use, CPU utilisation, frequency, and duration of function calls. This information is then used to optimize the program and improve performance.
These techniques represent a combination of strategies and practices that, when properly used, can improve the robustness, performance, and reliability of software systems. By mastering these, we software engineers can tackle complex tasks and build high-quality software.
Algorithmic Thinking & Fishing
Understanding how to break down complex problems into smaller, more manageable parts, and designing effective algorithms is a fundamental skill in software engineering. Knowing about existence of certain algorithms so that we can fish them from the sea of recipes.
Data Structures and Language Implementation
These provide standardised ways to store and retrieve data efficiently. Mastery of data structures is crucial for effective algorithm design.
Software Design and Architecture
This involves mastering patterns and principles that guide how software components should interact with one another, promoting modularity, scalability, and maintainability.
Testing and Debugging
Understanding testing methodologies and debugging techniques helps ensure the quality and reliability of the software.
Version Control and Collaboration
Mastering tools and techniques for collaborative development and version control like Git is crucial for teamwork in software engineering.
This is the crux of any software engineering role. Developing the ability to identify, analyse, and solve problems is a critical skill in software development
Ever Green Soft Skills
In addition to the technical skills, I believe soft skills are also equally important, because Engineering is often done with people, for people and by people.
- Communication: Clear and concise communication, both written and verbal, is crucial for collaborating effectively with team members, stakeholders, and other departments.
- Collaboration: Working well with others, whether it's a small team or a larger cross-functional group, is vital. This skill includes being able to respect, listen to, and consider the ideas and opinions of others.
- Patience: Software development often involves complex tasks that require a lot of time and concentration. Patience can help software engineers to stay focused and systematically solve problems, especially when dealing with elusive bugs or challenging code.
- Time Management: The ability to organising and manage one's time effectively is crucial for meeting project deadlines, juggling multiple tasks, and maintaining a healthy work-life balance.
- Empathy: The ability to understand and share the feelings of others is important for working in a team, but it's also crucial for understanding user needs and creating user-friendly software.
- Leadership: Even if not in a management role, leadership skills like the ability to motivate, influence others, take initiative, and make decisions are highly valued and can lead to more responsibilities and career progression.
The Importance of General Concepts
Learning the general concepts provides several key benefits:
With a strong grasp of fundamental concepts, you can easily adapt to new technologies and paradigms. While learning a new programming language or tool may require an initial learning curve, the core concepts and problem-solving strategies remain the same, allowing for quicker adaptation and mastery.
General principles are transferable between different languages, tools, and methodologies. For example, understanding the concept of object-oriented programming (OOP) can be applied in multiple languages such as Java, C++, Python, and more. Concepts of Observability can be applied to any control system. Collection primitives and Futures are monadically modelled in multitude of languages, etc.
As the technology landscape evolves, certain tools and technologies may become obsolete. However, the foundational principles of software engineering largely remain constant. Focusing on these can help 'future-proof' your career, as your skills remain relevant despite changes in popular tools or languages.
The Role of Specifics
While general concepts provide the foundation, specifics are also important as they enable the practical application of these principles:
Tool Mastery: Mastery of a specific tool or language can make you highly productive and proficient in that domain. It also enables you to deeply understand and appreciate the underlying general concepts.
Employability: Many job postings require knowledge of specific languages or tools. Being proficient in these can increase your employability and competitiveness in the job market.
Innovation: Understanding the specifics can lead to innovation. As you delve deeper into a particular technology or tool, you may discover new ways to use it or even create improvements or additions to it.
The Balancing Act: General Concepts and Specifics
As in many areas of life, balance is key in software engineering. While understanding the general principles provides a solid foundation and ensures adaptability, learning the specifics allows for the application of these principles and can open specific career opportunities.
The importance lies in not becoming too anchored in the specifics and keeping an eye on the larger picture. As software engineering continues to evolve, the ability to separate the general from the specifics will ensure that the speed of change doesn't affect your ability to grow and thrive in this exciting field.
To conclude, mastering the evergreen concepts of software engineering serves as an anchor amidst the tumultuous waves of change, offering an enduring understanding that transcends the here-and-now technologies, thereby arming engineers with a timeless toolkit. Simultaneously, keeping abreast of evolving specifics provides the necessary sails to navigate these waves, marrying timeless wisdom with cutting-edge knowledge to ride the crest of technological innovation.
Thanks for Reading, Happy Engineering 🍋