Translating Code Through Context

I’ve had a love of books for most of my life. This love first came about on a day I decided to hide from bullies in the school library, back in elementary school. Once inside I wasn’t sure what to do. I looked around and my eyes fell on a book displayed on the side of a row of bookshelves. The person on the front reminded me of myself, surrounded by darkness, seeming sad and abused. I was drawn to that book and to books in general. I started reading abundantly from that point, and writing my own stories too. I fell deeply in love with prose. I would read all manner of things, dictionaries, encyclopedias, instructions, you name it.

Then I hit a wall. I could read Edgar Allen Poe works easily, but struggled with The Iliad and Beowulf. I struggled with some of William Shakespeare’s work too. Then I had a teacher help me by guiding me in using context to understand the meaning of ancient words. He taught me to not just look up the words but gauge how to interpret them based on the situation of occurrence.

I took this guidance to heart and applied it to much more than books. It’s what allows me to translate other code languages and to write in code I haven’t learned before. Through investigation and some guess work I can often figure out what your code is doing. If you understand the meaning, you can repurpose the syntax.

Let’s take a look at Beowulf, the epic poem

Hrothgar, king of the Danes, or Scyldings, builds a great mead-hall, or palace, in which he hopes to feast his liegemen and to give them presents. The joy of king and retainers is, however, of short duration. Grendel, the monster, is seized with hateful jealousy. He cannot brook the sounds of joyance that reach him down in his fen-dwelling near the hall. Oft and anon he goes to the joyous building, bent on direful mischief. Thane after thane is ruthlessly carried off and devoured, while no one is found strong enough and bold enough to cope with the monster. For twelve years he persecutes Hrothgar and his vassals. https://www.gutenberg.org/files/16328/16328-h/16328-h.htm

This is the opening, the preface. Focusing in on the first sentence, we have a king who builds a mead-hall, or palace. I didn’t know what mead was so I looked it up.

Mead (/miːd/), also called hydromel, particularly when low in alcohol content, is an alcoholic beverage made by fermenting honey mixed with water, and sometimes with added ingredients such as fruits, spices, grains, or hops - Wikipedia

So I can assume a mead hall is a place designed for drinking mead. Feast is also mentioned so I imagined a large rustic dining hall with alcohol fermenting in barrels. Who is feasting here? Liegemen of the king. I don’t know this word either but I have heard servants in vampire tales say “My liege” when referring to their master, especially when being called to take orders. With that context and the context of “liegemen” in this opening. I can guess these are loyal servants of the king. They must be very loyal to get a grand feast along with presents. I’ll also assume retainer has a similar connotation as liegemen.

“Brook” is another word I’m unfamiliar with but given the context

Grendel, the monster, is seized with hateful jealousy. He cannot brook the sounds of joyance that reach him down in his fen-dwelling near the hall.

I could replace it with “stand” or “bear”. He cannot “stand” the sounds of joy. Joyance looks like joy and I’m sure the feast is very joyful. I look up fen-dwelling since I have no reference for it. I decide that, based on the definition “an area of low, flat, marshy land; swamp; bog”, that Grendel lives in an overgrown, smelly swamp and that contributes to its misery.

The more I contextualize words the less I have to look up. When I get to the last part of this passage I can guess the meaning though the circumstances alone.

Oft and anon he goes to the joyous building, bent on direful mischief. Thane after thane is ruthlessly carried off and devoured, while no one is found strong enough and bold enough to cope with the monster. For twelve years he persecutes Hrothgar and his vassals.

“Oft and anon” probably means “off and on”. “Direful” reminds me of dire, which is a serious/dangerous situation. “Direful mischief” would mean serious/dangerous mischief. “Thane after thane” is carried off and eaten. Grendel is kidnapping and eating people, which adds validity to my assumption that direful means serious/dangerous. Rounding out the passage, I assume vassal is another name for a servant of the king. Likely the Thanes and vassals have high rank, probably noblemen. Thus explaining why the king would have a feast for them. It’s like a political leader holding a celebration for their backers. Also, though it sounds cold, I think people would be more concerned about Grendel eating noblemen rather than servants of humble standing.

Of course you can look up each word you don’t know, but sometimes words have different meanings. English is notorious for this. It also interrupts the flow of reading and can leave you needing to reread so that you get a clearer picture. During the reading of that passage I only needed to look up 2 words instead of 11. I’d say this is a large improvement.

We can apply this concept to code as well. My goals today will be:

  • Showing how to read code in your main language that was written by another developer.
  • Showing how to read a programming language different from your main language.
  • Showing how to translate code from your main language into a different language.

I’m primarily a Ruby on Rails developer, so I will treat that as my native language as we proceed forward.

Reading Code From a Different Developer

First let’s start with reading code in your main language written by a different developer. This will be an easier entry point since you already know the language. It’s very useful to learn to read the code of others because it makes code reviews easier and it can show you techniques you weren’t aware of. It also shows the code pattern being utilized when you join a project that has already been worked on, which allows you to match that pattern.

When I started working on my first client project as an apprentice, I was tasked with building out a system that would allow users to manage following legislation. The application had previously been a simple mailer and the only front end pages were for administration.

I dived into the code seeking to understand what it was currently doing so that I could utilize and/or change it. The first place I started was a case statement. I hadn’t worked with case statements before. I didn’t know what they were. I wish I had that specific code to share, but that was years ago and the code isn’t in that application anymore. So you’ll have to use your imagination. It was a large case statement and it was checking as well as changing the value of “state”. I didn’t know what “state” was either. I hadn’t worked with a PDF reader before so I looked up the one being used.

I will attempt to recreate the case statement.

The PDF looked like this (but had way more content)

North Carolina General Assembly Senate Calendar April 17th 2023

Case statement code was kind of like this:

require 'pdf/reader'

reader = PDF::Reader.new('2023/8199/Senate Calendar.pdf')
events = []
event = {}
days\_of\_week = [Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday]
part\_of\_day = [a.m., p.m.]

reader.pages.each do |page|

  lines = page.text.scan(/^.+/)

  lines.each do |line|
    case state
      when line \~= i/Committee Meeting/
        state = committee meeting
      when line \~= i/Crossover Deadline/
        state = nil
      when committee meeting
        if line \~= i/#{days\_of\_week.join(“|”)/
          unless event.blank?
            events << event
            event = {}
          end
          event[:date] = line
        elsif line \~= i/#{time\_of\_day.join(“|”)}/
          details = line.split( )
          event[:title] = details[0]
          event[:time] = details[1,2]
          event[:location] = details[3,4]
        end
       #more code for handing bills that I won’t write out for brevity sake.
     when nil
        unless event.blank?
           events << event
           event = {}
        end
     end
  end
end

This is what I knew at first glance

  • The code is parsing a pdf
  • That pdf was being broken down into pages and further down into lines
  • Regex was being used to check the value of the lines
  • The value of state would allow access to specific parts of the case statement (the “when”)
  • The value of state was changed depending on line content
  • Data was collected from the lines for events

By the end we would have a collection of events, as an array of hashes. These would be used to make events in the database.

I used put statements and went line by line, checking what was happening. Through this process I began to reason. The code was using trigger words in the PDF to decide what part of the PDF we were at. Then would store the information of what section we were in within the “state”. I still wasn’t sure what state was, but I reasoned that it was neutral at first and changed while parsing, but once a loop was done the state would go back to being neutral. It seemed like “case” was similar to “if’‘ with the addition of the value of something being passed down through the conditionals without repetition. ‘when “committee meeting”’ could be translated to ‘if state == “committee meeting”’.

Later I verified my assumptions and learned ‘state’ was an empty variable. Using state I added the ability to collect the crossover deadline as well.

Reading Code in a Different Programming Language

I was working on a project that only had one front end developer. They were busy working on designs for an upcoming feature. I wanted to help by taking on some front end tickets. I picked a simple one to start with. I need to add “Last Updated On” to a component, then display the date and time in a particular format. The front end was built using React and Typescript. I had taken a React Native class several years prior but had not worked with it since. I had never seen Typescript before. Through a text search I found the component I needed to update.

The file was over 200 lines long. I compared it with the view in the browser to locate the section where I wanted to put the date and time.

I’m going to display a simplified version of the code

import React from 'react'
import { useParams } from 'react-router-dom'
import { useQuery } from 'react-query'
import { api } from '../../../api'
import { shortDateTime } from '../../../utils/time'
import { UserVerifiedBadge } from '../../Staff/UserVerifiedBadge'

interface Props {
  actionButtons?: React.ReactNode
}

export function StaffProfile({ actionButtons }: Props) {
  const { staffId } = useParams<{ staffId: string }>()

  const { data, isLoading, isError } = useQuery<Staff>(['staff', staffId], () =>
    api.staff.getStafferById(staffId)
  )

  if (isError || isLoading || !data) return null

  const profile = data
  return (
          <div className='mt-6 min-w-0 flex-1'>
                <div className='flex items-center'>
                    <h1 className='text-2xl font-bold text-gray-900 truncate pr-3 mt-3'>
                            {profile.first_name} {profile.last_name}
                    </h1>
                    {profile.user_verified && <UserVerifiedBadge />}
                </div>
           </div>
          )
}

This simplified version is something I did in my head originally. Sometimes I’ll rename the original file and make a new empty file with the name of that original one. Then I add in code to see what is the bare minimum needed to do what I need to do. But other times I do it mentally. In this case I mentally narrowed down the code to what was needed to achieve the look requested in the ticket. The above is the narrowed down version. It contains only the row that I was meant to add the date and time to.

Noticing the use of “profile” and how it seems to contain the data a staff record in our database, I check where the profile came from. Up at the start of the function I see

const { staffId } = useParams<{ staffId: string }>()

Const is a variable, I recall that it’s similar to Ruby constants. We are setting the value of the staffId variable by calling useParams. Checking the imports at the top, useParams is coming from 'react-router-dom’. If I assume its name is describing what it does, it appears to be retrieving the params sent over by the request. Specifically it’s taking the staffId from the params. Makes sense to me. Now on to what is done with the staffId.

const { data, isLoading, isError } = useQuery<Staff>(['staff', staffId], () =>
    api.staff.getStafferById(staffId)
  )

This looks to me like it is setting 3 variables. You can do something similar in Ruby on Rails. It’s setting these variables based on the results from the useQuery function. This function appears to query for the staff record and etiher return that record, an indication that it’s still searching, or that there was an error (like if the record isn’t found). I will think of the 3 variables as ‘states’, those states being data found, data search in progress and data error.

Thinking like this, data would be the staff record that was found by the useQuery function. This means that it has all of the staff record information including the updated_at

Lastly the value of profile is set

const profile = data

I decide to test out my theory by following the parttern used in the code that displays the first name and last name of the staff. I add this to the function

<p className='text-sm text-gray-900'>
     Last Updated On: {profile.updated_at}
</p>

It displays the date and time, so my assumptions were correct. However it displays them unformatted. I need to get them into the right format.

Translate Code into a Different Language

For formatting dates and times in Ruby on Rails I use strftime. However I found I didn’t have access to rails methods inside of this function. I was told there was a file with utilities for displaying dates and times. I went to that file and looked at the functions already there. In that file I saw this code

export const shortDate = (dateTime: string) => {
  return new Intl.DateTimeFormat('en-US', {
    dateStyle: 'medium',
  }).format(new Date(dateTime))
}

export const shortestDateTime = (dateTime: string) => {
  return new Intl.DateTimeFormat('en-US', {
    dateStyle: 'short',
    timeStyle: 'short',
  }).format(new Date(dateTime))
}

export const time = (dateTime: string) => {
  return new Intl.DateTimeFormat('en-US', {
    hour: 'numeric',
    minute: 'numeric',
  }).format(new Date(dateTime))
}

export const date = (dateTime: string) => {
  return new Intl.DateTimeFormat('en-US', {
    dateStyle: 'short',
  }).format(new Date(dateTime))
}

export const monthAndYearFromDate = (dateTime: Date) => {
  return new Intl.DateTimeFormat('en-US', {
    month: 'long',
    year: 'numeric',
  }).format(dateTime)
}

export const isoDate = (dateTime: Date | number | string = new Date()) => {
  const t = new Date(dateTime)
  // 2021-12-25
  const yyyy = t.getFullYear()
  let MM: string | number = t.getMonth() + 1
  const dd = t.getDate()

  if (MM.toString().length === 1) {
    MM = `0${MM}`
  }

  return `${yyyy}-${MM}-${dd}`
}

I decided to try importing different ones into the file where I needed to format the updated_at. Through trial and error I realized I wanted an edited version of shortestDateTime where the date was “medium” instead of “short”

I made a duplicate, changed the name and edited the dateStyle to be medium

export const shortDateTime = (dateTime: string) => {
  return new Intl.DateTimeFormat('en-US', {
    dateStyle: 'medium',
    timeStyle: 'short',
  }).format(new Date(dateTime))
}

I imported this into the file with the updated_at by following the syntax used for the other imports

import { shortDateTime } from '../../../utils/time'

then called it

<p className='text-sm text-gray-900'>
     Last Updated On: {shortDateTime(profile.updated_at)}
</p>

In this case I was fortunate that I had some example code already in my app. But if that wasn’t the case I would look up examples and reach out to fellow developers more experienced in the language. It is admittedly much harder to write in another language without examples with context. There is also a limitation on customization without looking up details of of the code. However this is a handly method for quick edits.

You may have noticed how using context relies on clear/understandable naming. It’s very important to name and organize things in a way that is easy for other developers to recognize and collaborate with. The same context that helps you understand will help others too. So make sure you use meaningful names, and follow code patterns. That will make code translation easier for everyone.

I hope this helps you in your future code translation endeavors.