From The Challenges - DNS Resolver
Exploring the software engineering lessons we can learn from the solutions I've seen.
Hi this is John with this week’s Coding Challenge.
🙏 Thank you for being one of the 84,011 software developers who have subscribed, I’m honoured to have you as a reader. 🎉
If there is a Coding Challenge you’d like to see, please let me know by replying to this email📧
Welcome To Coding Challenges - From The Challenges!
In this Coding Challenges “from the challenges” newsletter I’m sharing some of the common mistakes I see software engineers make when tackling the Coding Challenges.
I’m sharing both the mistakes people make and some thoughts on how you can you avoid making the same mistakes when taking on the coding challenges or when writing software professionally. Sometimes we have to make mistakes to learn from them, somethings we can learn from other people’s mistakes, then make our own new ones! 😀
🚨Starting Soon! Learn Go By Building Coding Challenges! 🚨
I’m running the Coding Challenges Learn Go By Building Live Course starting Monday June 2nd!
It is a live course that runs for three working weeks from June the 2nd to the June the 20th. During the course I’ll introduce you to ever aspect of Go that you need to build the following five real-world projects (based off five of my coding challenges):
🏗️ cat - By building cat you learn how to build and run command line programs in Go.
🏗️ sort - By building sort you learn how to use Go's data structures and control flow to implement sort.
🏗️ curl - By building curl you learn how to write network clients in Go.
🏗️ wc - By building wc you learn how to process text data and handle locales with Go.
🏗️ Memcached (Capstone Project) - By building a Memcached server clone you learn how to build efficient network servers in Go.
Having built these five real-world applications you will be well equipped to take on new projects in Go!
If you are a paid subscriber you can get 20% off - please visit the paid subscriber benefits page for the code.
If you are ready to learn Go with me, you can sign up to Coding Challenges Learn Go By Building Live Course here.
Recapping The DNS Resolver Coding Challenge
In the build your own DNS resolver coding challenge the goal was to write a DNS resolver.
A DNS resolver handles domain name resolution; turning the hostname that your client (i.e. a browser) has into an IP address. That IP address can then be used to open a connection to the target server.
If You Enjoy Coding Challenges Here Are Three Ways You Can Help Support It
Refer a friend or colleague to the newsletter. 🙏
Sign up for a paid subscription - think of it as buying me a coffee ☕️, with the bonus that you also get 20% off any of my courses.
Buy one of my courses that walk you through a Coding Challenge.
Five Common Mistakes Software Engineers Make Solving The DNS Resolver Coding Challenge
I’ve pulled together this list of common mistakes from the hundreds of submissions I’ve been sent privately and the many shared in the Coding Challenges Shared Solutions GitHub Repo.
Shoutout To Tiger For A Great Writeup of His Learnings From This Coding Challenge!
included a great write up of some of the challenges and learnings he faced doing the project. It’s a great way to share your learnings, check out out here.Mistake 1 - Building The Message With Strings
Network protocols are usually either text based, like SMTP or binary like DNS. If they’re text based by all means parse and build the messages as text strings.
When they are binary, build the correct types and structures to pack and unpack binary data. Not doing so deprives you of some of the key learning to be had in this project - creating structures for binary data, aligning them correctly in memory and packing or unpacking them.
Which brings us to…
Mistake 2 - Ignoring Endianness / Network Byte Order
Some CPUs are big-endian and some are little-endian. If you’re not familiar with endianness, a big-endian system stores the most significant byte of a word at the smallest memory address and the least significant byte at the largest. A little-endian system, in contrast, stores the least-significant byte at the smallest address.
When you write code that handles network protocols this can lead to subtle bugs when your CPU is little-endian and the network protocols expect data to be big-endian (aka, in network terms: network byte-order). To avoid this and to make any network client or server that you write portable, always leverage the facilities of your programming language to ensure correct byte ordering.
That usually means translating from host to network byte order when sending network messages and from network to host byte order when receiving it. Most socket libraries provide functions to do this, for example most provide the C functions:
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
Which support converting host-to-network and network-to-host byte ordering. On platforms where the host and network are the same these functions are no-ops and optimised away (i.e. often macros in C that do nothing). Other programming languages usually build on these.
Mistake 3 - Hardcoding Settings And Parts Of The Message
I saw a few solutions that hard coded a chunk of the message header, either as a string or an array of bytes. It’s depriving yourself of the learning to do that and it makes the code unusable for other DNS queries where the headers would be set differently.
Beyond that when we’re looking up DNS we don’t always want to use the same server - what if it’s down?
Rather than hard code the example root DNS server, consider providing a config file with the list in it. It doesn’t make sense to require a rebuild of the code to change a config detail.
Mistake 4 - Using a DNS Package For Your Programming Language
This is similar to mistake 1. The lesson from this coding challenge is all about packing and unpacking binary network protocols. If you use a library to do that bit then you miss out on 90% of the learning from this programming project.
Mistake 5 - Binary and IDE Settings Files In Repos
This is a recurring issue across many of the submissions I see for Coding Challenges!
Source code repos are for source code. Binaries do not belong in them. It should be possible to re-create the binary from the source code so there is no need for the binary. Equally it’s not obvious from a binary if the current binary is built from the current version of the code or an earlier one. Or even if the binary has been compromised.
Equally IDE config files are user specific. Avoid storing them in a repo. There’s a couple of reasons:
When you’re on a team other people probably won’t use the same settings as you.
You might not use the same settings by the time you next use the project.
It adds noise to the repo. It’s minor but a distraction for someone not familiar with it.
Request for Feedback
I’m writing these coding challenges and this new from the challenges series to help you develop your skills as a software engineer based on how I’ve approached my own personal learning and development.
What works for me, might not be the best way for you - so if you have suggestions for how I can make these challenges more useful to you and others, please get in touch and let me know. All feedback greatly appreciated.
You can reach me on Bluesky, LinkedIn or through SubStack
Thanks and happy coding!
John
P.S. If You Enjoy Coding Challenges Here Are Four Ways You Can Help Support It
Refer a friend or colleague to the newsletter. 🙏
Sign up for a paid subscription - think of it as buying me a coffee ☕️ twice a month, with the bonus that you also get 20% off any of my courses.
Buy one of my courses that walk you through a Coding Challenge.
Subscribe to the Coding Challenges YouTube channel!