🤔Decision Assumptions and their long-term implications.
👷Software Architecture Series — Part 9.
🕵Case Study: Serialization in Java
🕰History: Back in 1990s, when Java Language was being developed by a team led by James Gosling, Patrick Naughton, Chris Warth, Ed Frank, and Mike Sheridan at Sun Microsystems (later acquired by Oracle Corporation), one of the primary goals was to create a platform agnostic language that could run on any device or platform without the need for recompilation. And as it happened, the output of a Java compiler is not an executable code but a bytecode, which is a highly optimized set of instructions designed to be executed by JVM. So, any system compatible with JVM will be able to run Java programs.
👉Assumption: During those days, three-tier computing was all the rage. However, moving objects over network consistently across the systems was a big headache. As capabilities of Java grew, object serialization technique was used by Java libraries to provide persistence capabilities. Designers of the Java language decided to bake the support of serialization as a core language support feature. The first official release of Java Serialization came with Java 1.1. It introduced the java.io.Serializable interface and the java.io.ObjectOutputStream and java.io.ObjectInputStream classes, which provided the mechanisms for converting Java objects into a stream of bytes (serialization) and reconstructing objects from the byte stream (deserialization).
⛓Concept: “Serialization” in Java refers to the process of converting an object into a byte stream that can be easily stored, transmitted, or reconstructed back into an object when needed. It is essentially helpful when we want to save state of an object for later use and helps in persistently store object states in storage systems like databases. During communication between different systems, objects are serialized (at source) and deserialized (at destination). Thus, serialization was key to providing cross platform compatibility. With Serialization, developers could control the versioning of serialized objects by using serialVersionUID to specify a version number. This helped in managing compatibility when changes were made to serialized classes.
🛎Reality: However, in modern distributed systems or microservices architectures, alternative methods have gained popularity over traditional Java serialization as the process of Serialization and Deserialization can be slow and resource intensive. It is quite difficult task to maintain compatibility between different versions of serialized objects, especially when new field are added to the object. Historically, Java serialization has had historical security vulnerabilities. Deserializing untrusted or externally sourced data can lead to security risks like remote code execution, making it a concern in systems where security is paramount. In distributed systems or microservices architectures, for communication between different systems or APIs, standardized data interchange formats like JSON, Protocol Buffers, or XML are more widely used due to their simplicity, readability, and widespread support across various platforms and languages.
⚠Repercussion: Now, the trend for three tier architecture has long subsided however Java still has to support the serialization feature for backward compatibility, and it is virtually used by no one. Language designers are left frustrated while adding new features as they must build support for serialization, which create no value at all, but only for the sake of compatibility.
💡Lesson: It is always advisable to follow simpler design decisions in not just software but other engineering disciplines as well, as it guards against the possible future repercussions. It has been a human nature to neglect the long-term implications of design decisions. As systems grow more complex, they also tend to become less predictable. Unforeseen interactions between components, dependencies, or changes in requirements can lead to unexpected consequences or difficulties in maintenance. Simpler designs are often easier to comprehend, maintain, and modify. When new features need to be added or when issues arise, a simpler design can facilitate quicker changes without causing unintended side effects.
📌However, here I am not making a case for sacrificing functionality or system robustness in pursuit of simpler design. But I am advocating to find a right balance between actual needs and feature implementations considering future changes. It involves an informed decision making based on trade-offs and implication of design choices. Yet, it is highly unlikely that one would be able to design a 100% perfect system, even the experienced designers at times miss a point or two, and that is acceptable, as there should always be a space left for human error 😉.
#softwarearchitect #communication #architecture #softwaredevelopment #design #business