Prelude This is the final post in a four part series discussing the mechanics and design behind pointers, stacks, heaps, escape analysis and value/pointer semantics in Go. This post focuses on data and the design philosophies of applying value/pointer semantics in your code.
This is the final post in a four part series discussing the mechanics and design behind pointers, stacks, heaps, escape analysis and value/pointer semantics in Go. This post focuses on data and the design philosophies of applying value/pointer semantics in your code.
Index of the four part series:
“Value semantics keep values on the stack, which reduces pressure on the Garbage Collector (GC). However, value semantics require various copies of any given value to be stored, tracked and maintained. Pointer semantics place values on the heap, which can put pressure on the GC. However, pointer semantics are efficient because only one value needs to be stored, tracked and maintained.” - Bill Kennedy
A consistent use of value/pointer semantics, for a given type of data, is critical if you want to maintain integrity and readability throughout your software. Why? Because, if you are changing the semantics for a piece of data as it is passed between functions, you are making it difficult to maintain a clear and consistent mental model of the code. The larger the code base and the team becomes, the more bugs, data races and side effects will creep unseen into the code base.
I want to start with a set of design philosophies that will drive the guidelines for choosing one semantic over the other.
“Let’s imagine a project that’s going to end up with a million lines of code or more. The probability of those projects being successful in the United States these days is very low - well under 50%. That’s debatable”. - Tom Love (inventor of Objective C)
Tom has also mentioned that a box of copy paper can hold 100k lines of code. Take a second to let that sink in. For what percentage of the code in that box could you maintain a mental model of?
I believe asking a single developer to maintain a mental model of more than one ream of paper (~10k lines of code) is already asking quite a bit. But, if we go ahead assume ~10k lines of code per developer, it would take a team of 100 developers to maintain on a code base that hits a million lines of code. That is 100 people that need to be coordinated, grouped, tracked and in constant communication. Now look at your current team of 1 to 10 devs. How well are you doing with this at a much smaller scale? At 10k lines of code per developer, is the size of your code base in line with the size of the team?
“The hardest bugs are those where your mental model of the situation is just wrong, so you can’t see the problem at all” - Brian Kernighan
I don’t believe in using a debugger until you have lost your mental model of the code and are now wasting effort trying to understand the problem. Debuggers are evil when they are abused, and you know that you are abusing a debugger when it becomes the first reaction to any observable bug.
If you have a problem in production, what are you going to ask for? That’s right, the logs. If the logs are not working for you during development, they are certainly not going to work for you when that production bug hits. Logs require having a mental model of the code base, such that you can read code to find bugs.
“C is the best balance I’ve ever seen between power and expressiveness. You can do almost anything you want to do by programming fairly straightforwardly and you will have a very good mental model of what’s going to happen on the machine; you can predict reasonably well how quickly it’s going to run, you understand what’s going on ….” - Brian Kernighan
I believe this quote by Brian applies just as well to Go. Maintaining this “mental model” is everything. It drives integrity, readability and simplicity. These are the cornerstones of well-written software that allow it to be maintained and last over time. Writing code that maintains a consistent use of value/pointer semantics for a given type of data is an important way to achieve this.
“If you don’t understand the data, you don’t understand the problem. This is because all problems are unique and specific to the data you are working with. When the data is changing, your problems are changing. When your problems are changing, the algorithms (data transformations) needs to change with it.” - Bill Kennedy
Think about this. Every problem you work on is a data transformation problem. Every function you write and every program you run takes some input data and produces some output data. Your mental model of software is, from this perspective, an understanding of these data transformations (i.e., how they are organized and applied in the code base). A “less is more” attitude is critical to solving problems with fewer layers, statements, generalizations, less complexity and less effort. This makes everything easier on you and your teams, but it also makes it easier for the hardware to execute these data transformations.
“Integrity means that every allocation, every read of memory and every write of memory is accurate, consistent and efficient. The type system is critical to making sure we have this micro level of integrity.” - William Kennedy
If data drives everything you do, then the types that represent the data are critical. In my world “Type Is Life”, because type provide the compiler with the ability to ensure the integrity of the data. Type also drives and dictates the semantic rules code must respect for the data that it operates on. This is where the proper use of value/pointer semantics starts: with types.
“Methods are valid when it is practical or reasonable for a piece of data to have a capability.” - William Kennedy
The idea of value/pointer semantics doesn’t hit Go developers in the face until they have to make a decision about the receiver type for a method. It’s a question I see come up quite a bit: should I use a value receiver or pointer receiver? Once I hear this question, I know that the developer doesn’t have a good grasp of these semantics.
The purpose of methods is to give a piece of data capability. Think about that. A piece of data can have the capability to do something. I always want the focus to be on the data because it is the data that drives the functionality of your programs. Data drives the algorithms you write, the encapsulations you put in place and the performance you can achieve.
“Polymorphism means that you write a certain program and it behaves differently depending on the data that it operates on.” - Tom Kurtz (inventor of BASIC)
I love what Tom said in that quote above. A function can behave differently depending on the data it operates on. That the behavior of data is what decouples functions from the concrete data types they can accept and work with. This is one core reason for a piece of data to have a capability. It is this idea that is the cornerstone of architecting and designing systems that can adapt to change.
“Unless the developer has a really good idea of what the software is going to be used for, there’s a very high probability that the software will turn out badly. If the developers don’t know and understand the application well, then it’s crucial to get as much user input and experience as possible.” - Brian Kernighan
I want you to always focus first on understanding the concrete data and algorithms you need to get data transformations working to solve problems. Take this prototype first approach and write concrete implementations that could also be deployed in production (if it is reasonable and practical to do so). Once a concrete implementation is working and once you’ve learned what works and doesn’t work, focus on refactoring to decouple the implementation from the concrete data by giving the data capability.
Data Science and Analytics market evolves to adapt to the constantly changing economic and business environments. Our latest survey report suggests that as the overall Data Science and Analytics market evolves to adapt to the constantly changing economic and business environments, data scientists and AI practitioners should be aware of the skills and tools that the broader community is working on. A good grip in these skills will further help data science enthusiasts to get the best jobs that various industries in their data science functions are offering.
🔵 Intellipaat Data Science with Python course: https://intellipaat.com/python-for-data-science-training/In this Data Science With Python Training video, you...
The agenda of the talk included an introduction to 3D data, its applications and case studies, 3D data alignment and more.
Become a data analysis expert using the R programming language in this [data science](https://360digitmg.com/usa/data-science-using-python-and-r-programming-in-dallas "data science") certification training in Dallas, TX. You will master data...
Need a data set to practice with? Data Science Dojo has created an archive of 32 data sets for you to use to practice and improve your skills as a data scientist.