Business rhetorical writing

I never thought there are writing techniques. Using those techniques, I have become a much better writer. I learned those rhetorical techniques by taking expository writing classes such as EXPO-15, and primarily EXPO-34. I am planning to take other EXPO classes as well. In EXPO-34, which is Business Rhetorics, I learned many things, among which is how we should divide the writing process into three stages following the Can Do Writing technique:

  1. Analysis stage (first stage) -> select the right facts, organize points into sentence outline
  2. Composing (2nd stage) -> learn the formats for introductions, summaries, and abstracts
  3. Editing (3rd stage) -> mechanical stage ensuring the our document has purpose, is logical, well organized, clear, concise and easy to read

This post is heavily influenced by the Can Do Writing book, but the EXPO-34 class I took with Prof. Randy Rosenthal is more than just that. I am glad I took his class.

A 6th-grader eloquent answer to nil vs false

On the 7th test today, I received the following answer, verbatim, to a question asking them what is the difference between a null and a false in the Gara programming language:

Beda kelas dan makna, kalau salah memiliki makna tidak benar/tidak betul, salah berada di kelas boolean, sedangkan nil adalah suatu objek yang menunjukkan tidak adanya objek, nil berada di kelas nirdefinisi

Or in English:

They are of different classes. The false signifies untruthy condition, and is of the Boolean class, whereby nil is an object signifying an absence of an object, and is of class Nulldefinition .

The programming language being used here used the term salah for false, and nil for null, and the class of nil is Nirdefinisi which means without definition in Indonesian.

This is such an eloquently written answer from a student who has not written any code ever before. We can notice how they really understood the concept of objects and how, in this case, they were able to point some subtle differences between a false against a falsey object. Those are concepts that some undergraduate students here in Indonesia may struggle with.

Even as these kinds of classes were very new to them, we can see that there is some potential here. This class is by no means easy for them. Many of whom don’t even have PCs at home. No student scored an A–yet. Regardless, this signifies that computer science education, when taught with the right tools and syllabus, can be understood by a 6th-grader. I will run the same kind of research and experiment with 5th-graders this year.

There are more than can be achieved.

Students at the computer science class in an elementary school in East Java Indonesia

Students at the computer science class in an elementary school in East Java, Indonesia


On the design of efficient, fast and predictable memory allocator

We are building our own Operating System in C for our Principles of Operating System class. At one time, we are required to create a memory allocation system. Given a whole heap of memory, we should be able to reserve some space within the memory and free that space. In this post, I would like to write down the approach that I took.

Our system allocates in a way that double-word boundary is respected; all address and size is thus a factor of 8. If the system is initialized with a main memory of which size is not a factor of 8, less space will be taken to make it align properly. When a block of memory is requested, we use first-fit to find the earliest block that can satisfy the request. Such a block must be at least of the same size, or bigger than requested. Since it is possible that the returned block is much larger than what is requested, we employ buddy allocator technique to divide the block. We call this division technique “chunking up.” As we later demonstrates, our chunking up technique is similar to budy allocator but is different in a way.

When the memory is setup for the first time, which is when the kernel is being initialized, the memory would be in the following configuration:

1
2
POS           ADDRESS    PID      FREE           SIZE
  0    0x7f2c171e0018      0       yes      134217720

The POS indicates an absolute position counted from 0, whereby the ADDRESS is the memory address usable by the user. While the POS does account the overhead struct, the ADDRESS does not. In other words, the ADDRESS is the address of the addressable allocated memory which can be read, write, checked and freed. Now, FREE indicates whether the block is, at the time of reporting, being reserved or not. The SIZE reports how large the allocated memory is sans any overhead struct. If we were to aggregate and sum the SIZE, the number would be smaller than the total free memory space when the memory is at its kernel-fresh state since we must account for overhead structs created for each memory block.

Now, when our system is fully initialized, the memory map would be akin to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
     POS           ADDRESS    PID      FREE           SIZE
       0    0x7fd464e5d018      0        no              8
      16    0x7fd464e5d028      0       yes              8
      32    0x7fd464e5d038      0        no              8
      48    0x7fd464e5d048      0       yes             72
     128    0x7fd464e5d098      0       yes            120
     256    0x7fd464e5d118      0       yes            248
     512    0x7fd464e5d218      0       yes            504
    1024    0x7fd464e5d418      0       yes           1016
    2048    0x7fd464e5d818      0       yes           2040
    4096    0x7fd464e5e018      0       yes           4088
    8192    0x7fd464e5f018      0       yes           8184
   16384    0x7fd464e61018      0       yes          16376
   32768    0x7fd464e65018      0       yes          32760
   65536    0x7fd464e6d018      0       yes          65528
  131072    0x7fd464e7d018      0       yes         131064
  262144    0x7fd464e9d018      0       yes         262136
  524288    0x7fd464edd018      0       yes         524280
 1048576    0x7fd464f5d018      0       yes        1048568
 2097152    0x7fd46505d018      0       yes        2097144
 4194304    0x7fd46525d018      0       yes        4194296
 8388608    0x7fd46565d018      0       yes        8388600
16777216    0x7fd465e5d018      0       yes       16777208
33554432    0x7fd466e5d018      0       yes       33554424
67108864    0x7fd468e5d018      0       yes       67108856

As must be noticeable, the memory is divided in such a way that the right hand side, that is ones at addresses that are growing larger, tended to be of a greater size. This indeed is done deliberately with careful design. Put in another way, we believe that blocks at the left-hand side is extremely short-lived or volatile in nature–they are used and freed quickly. For that, we want a system that does not scan further to be able to give those blocks at a time of need. This can be observed by how block at 0x7f5465a75028 of 8 bytes is free. This block must be used by the shell program in some way and then freed before the memory mapper could take a look at it when it was still being used. For a fuller picture, the first block stored the PCB (Process Control Block) metadata which is allocated by the system’s kernel as soon as the OS is running–and will remain there as long as the OS is running.

This technique helped make our first-fit algorithm to have virtually identical benefits to best-fit without compromising speed. But, unlike buddy allocator in general, however, we always make sure that the division would cause the right block to be of a slightly bigger size than its left-hand cousin. That is, the division is not done so evenly. For example, let’s study these blocks:

1
2
3
POS           ADDRESS    PID      FREE           SIZE
2048    0x7fd464e5d818      0       yes           2040
4096    0x7fd464e5e018      0       yes           4088

If the division is fully fair and equal, block at POS 4096 would be of size 4080 bytes but instead, it is of 8 bytes larger. Indeed, this is how our chunking up is a little bit different from the standard buddy allocator as we ensure that the right-hand blocks are always at slightly larger size than its right hand-side cousin. This is done with the hope that the left-hand side will be much smaller and more readily suitable for the requested size.

The generally large-spaced blocks on the right also allow for the next request to ask for a bigger size, which, should that very block can accommodate it, they can be returned right away without splitting a new bigger one. Seen from a different perspective, we may say that the block on the left will tend to be much short-living as the algorithm is indeed a little carefully designed so that blocks of smaller size are concentrated on the left-hand side which is very near to the iteration when we need to find a suitable block.

But, we do not stop at first-fit and best-buddy allocation when it comes to allocating memory. Otherwise, we can run into the possibility of wasting so much space. That is so because there can be a point where we would no longer be able to chunk up a block as doing so would either created buddies of effectively 0-byte large (if not even less) such as in the case of a block with 16 bytes. When a 16 bytes block is chunked, it should end up as two blocks of 8 bytes each. But, since we will need to create a bookkeeping struct for the new block on the right, the right buddy can end up with 0 byte addressable space. The left buddy does not have to create a bookkeeping struct since it can use the same bookkeeping struct the block is originally attached with.

Instead of chunking, in this case we ended up with a process so-called space-fitting. For example, if we have a memory in this layout:

1
2
3
4
5
6
POS           ADDRESS    PID      FREE           SIZE
  0    0x7f5465a75018      0        no              8
 16    0x7f5465a75028      0       yes             80
104    0x7f5465a75080      0        no             16
128    0x7f5465a75098      0        no             16
152    0x7f5465a750b0      0        no             16

If we issue: malloc 8 to reserve an 8-bytes addressable memory space, we will end up with a new block at ADDRESS 0x7f5465a75038 of exactly 8 bytes:

1
2
3
4
5
6
POS           ADDRESS    PID      FREE           SIZE
  0    0x7f5465a75018      0        no              8
 16    0x7f5465a75028      0       yes              8
 32    0x7f5465a75038      0        no              8
 48    0x7f5465a75048      0       yes             64
120    0x7f5465a75090      0        no             16

Without space-fitting, this new region would likely be bigger than 8 bytes, although will be less than 80-bytes wide.

The space-fitting works in this manner: first, the first-fit and best-budy will perform their works to give us the best possible block as soon as possible. Now, if the block is larger and the right hand side is free, we will transfer extra bytes there. This is almost always possible because of how our memory allocator is designed to work, that is, seen from another angle, to make the right hand side almost always free. In the rare case the right is not free but the left is, the extra bytes will be transferred there. In the even rarer case that neither side is free, the block will “divide” itself when possible even if the division is hardly equal and fair–as long as none of the block will end up with 0 byte. If none of the above can be done, the block will be left as-is.

This overall design has benefited us tremendously. Our iteration does not have to iterate further. If we ever need to chunk up we will still have a block big enough to be chunked up again. And that, nearly every block that is reserved shouldn’t have that much extra, unnecessary bytes.

Now, we should see what will happen if we allocate 128 bytes of memory. First, take a look at the snapshot of our memory map before making such an allocation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POS           ADDRESS    PID      FREE           SIZE
   0    0x7f5465a75018      0        no              8
  16    0x7f5465a75028      0       yes              8
  32    0x7f5465a75038      0        no              8
  48    0x7f5465a75048      0       yes             16
  72    0x7f5465a75060      0        no             32
 112    0x7f5465a75088      0       yes             40
 160    0x7f5465a750b8      0        no             16
 184    0x7f5465a750d0      0        no             16
 208    0x7f5465a750e8      0       yes             96
 312    0x7f5465a75150      0       yes             96
 416    0x7f5465a751b8      0       yes             88
 512    0x7f5465a75218      0       yes            504
1024    0x7f5465a75418      0       yes           1016
2048    0x7f5465a75818      0       yes           2040
 
(truncated for brevity)

Now, after performing memory allocation, our memory map is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POS           ADDRESS    PID      FREE           SIZE
   0    0x7f5465a75018      0        no              8
  16    0x7f5465a75028      0       yes              8
  32    0x7f5465a75038      0        no              8
  48    0x7f5465a75048      0       yes             16
  72    0x7f5465a75060      0        no             32
 112    0x7f5465a75088      0       yes             40
 160    0x7f5465a750b8      0        no             16
 184    0x7f5465a750d0      0        no             16
 208    0x7f5465a750e8      0       yes             96
 312    0x7f5465a75150      0       yes             96
 416    0x7f5465a751b8      0       yes             88
 512    0x7f5465a75218      0        no            128
 648    0x7f5465a752a0      0       yes            368
1024    0x7f5465a75418      0       yes           1016

Notice the memory at ADDRESS 0x7f5465a75218 is located just in between of two world: one on its left all of smaller size, and one on its right of bigger size, proving our memory allocator worked just as intended by design. That’s why, instead of having (at least) 280 bytes of a single block on its left (0x7f5465a750e8, 0x7f5465a75150, and 0x7f5465a751b8 combined), that “potential” block is chunked to 3 blocks, completely upholding the rules of our allocator.

Now, what would happen if we were to allocate 64 bytes worth of memory? The answer is, our memory map would be as follow:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
POS           ADDRESS    PID      FREE           SIZE
   0    0x7f5465a75018      0        no              8
  16    0x7f5465a75028      0       yes              8
  32    0x7f5465a75038      0        no              8
  48    0x7f5465a75048      0       yes             16
  72    0x7f5465a75060      0        no             32
 112    0x7f5465a75088      0        no             88
 208    0x7f5465a750e8      0       yes             40
 256    0x7f5465a75118      0        no             16
 280    0x7f5465a75130      0        no             16
 304    0x7f5465a75148      0       yes             48
 360    0x7f5465a75180      0       yes             48
 416    0x7f5465a751b8      0       yes             88
 512    0x7f5465a75218      0        no            128
 648    0x7f5465a752a0      0       yes            368
1024    0x7f5465a75418      0       yes           1016
2048    0x7f5465a75818      0       yes           2040
4096    0x7f5465a76018      0       yes           4088
8192    0x7f5465a77018      0       yes           8184

It used block at ADDRESS 0x7f5465a75088 that is 88-bytes worth. Again, it’s located on the left-hand side of 0x7f5465a75218 (128 bytes) which we’ve allocated earlier.

When a given memory block is freed, it will be merged with the block to its right and/or to its left if they were free at the time of merging. When those blocks are merged, their overhead struct will be claimed and thus reusable, resulting in the SIZE of said merged block to be much bigger than when they were standing all by themselves.

To demonstrate, assume we had allocated 16 bytes (0x7f5465a75048) and 8 bytes (0x7f5465a75060) worth of space to end up with the following memory map:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
POS           ADDRESS    PID      FREE           SIZE
   0    0x7f5465a75018      0        no              8
  16    0x7f5465a75028      0       yes              8
  32    0x7f5465a75038      0        no              8
  48    0x7f5465a75048      0        no             16
  72    0x7f5465a75060      0        no             32
 112    0x7f5465a75088      0        no             88
 208    0x7f5465a750e8      0       yes             16
 232    0x7f5465a75100      0        no             24
 264    0x7f5465a75120      0       yes             40
 312    0x7f5465a75150      0        no             16
 336    0x7f5465a75168      0        no             16
 360    0x7f5465a75180      0       yes             64
 432    0x7f5465a751c8      0       yes             72
 512    0x7f5465a75218      0        no            128
 648    0x7f5465a752a0      0       yes            368
1024    0x7f5465a75418      0       yes           1016
2048    0x7f5465a75818      0       yes           2040
4096    0x7f5465a76018      0       yes           4088

Now, let’s free 0x7f5465a75048:

1
2
3
4
5
6
7
8
POS           ADDRESS    PID      FREE           SIZE
  0    0x7f5465a75018      0        no              8
 16    0x7f5465a75028      0       yes              8
 32    0x7f5465a75038      0        no              8
 48    0x7f5465a75048      0       yes             16
 72    0x7f5465a75060      0        no             32
112    0x7f5465a75088      0        no             88
208    0x7f5465a750e8      0       yes             40

If we were to free the region on its left, 0x7f5465a75038, our memory map will be merged all the way up to 0x7f5465a75028, making a super-sized block out of what used to be 8-bytes large, and far larger than when they are accounted individually: 32 bytes (0x7f5465a75028 + 0x7f5465a75038 + 0x7f5465a75048) since now the overhead structs will be a part of the addressable space.

1
2
3
4
5
6
7
8
POS           ADDRESS    PID      FREE           SIZE
  0    0x7f5465a75018      0        no              8
 16    0x7f5465a75028      0       yes             48
 72    0x7f5465a75060      0        no             32
112    0x7f5465a75088      0        no             88
208    0x7f5465a750e8      0       yes             40
256    0x7f5465a75118      0        no             16
280    0x7f5465a75130      0        no             16

Now of course this block is naturally bigger, but there is exactly no needs nor reasons to move it to the right-hand side just to follow the rules. In fact, doing so is extremely undesirable as we would have to travel further to reserve new blocks that is usually temporary in nature especially in these hotspot regions.

So far our algorithm has worked beautifully, but at this rate it’s far from desirable. In a production environment where the memory is in a chunked up state, when a user wanted to allocate simply one byte bigger than the unallocated tail block: the allocator will refuse to allocate even if the free memory size is suffice to fulfill such a request. For example, given our tails in this configuration:

1
2
3
4
5
6
     POS           ADDRESS    PID      FREE           SIZE
 4194304    0x7fec44cd2018      0       yes        4194296
 8388608    0x7fec450d2018      0       yes        8388600
16777216    0x7fec458d2018      0       yes       16777208
33554432    0x7fec468d2018      0       yes       33554424
67108864    0x7fec488d2018      0       yes       67108856

Reserving 67108857 bytes of memory, which will then be rounded up to meet our double-word boundary expectation, would not be allowed under current technique. That is because there is simply no block that the first-fit can found that can satisfy such a request. Fortunately, the fix for that is very easy: we just need to stitch memory back starting from the tail (the end tip of the memory) to a possible position nearing to the head such that the combined sum of those blocks will be (large) enough for the request. We call this technique stitching.

Without stitching we would not be able to reserve 77108856 bytes of memory as, again, the last block is way too small for that. But, with stitching, this is what would happen when we reserve 77108856 bytes of memory:

1
2
3
4
5
     POS           ADDRESS    PID      FREE           SIZE
 4194304    0x7fec44cd2018      0       yes        4194296
 8388608    0x7fec450d2018      0       yes        8388600
16777216    0x7fec458d2018      0       yes       40331640
57108864    0x7fec47f48998      0        no       77108856

Notice that we managed to reserve exactly that size, while transferring any extra byte to its left buddy. The process is done in this way: first, 0x7fec488d2018 would be merged with 0x7fec468d2018 which result in 0x7fec468d2018 having extra bytes. The 0x7fec468d2018 then transfer its extra bytes to its left buddy, which is 0x7fec458d2018, causing its size to widen from 16777208 bytes to 40331640 bytes. Now, since 0x7fec458d2018 has received extra bytes, 0x7fec468d2018 can no longer stay at its position thus it “indented” itself resulting it to be in the ADDRESS of 0x7fec47f48998. The expected behavior of these stitched blocks would remain similar. If they were to be freed, the whole block is freed, and perhaps merged to its left buddy or right buddy as appropriate. They are also subjected themselves from being chunked up, also if applicable.

Thus, as demonstrated, our algorithm is rather efficient in its use of the memory because when our user requested for 8 bytes space and the allocator found a 16 bytes block, the block can be chunked down and space-fitted so as to avoid wasting space. It is also clearly fast when it needs to find a suitable block as it used the plain-and-simple first-fit algorithm. On top of that, it’s relatively predictable in its behavior due to buddy allocator with some adjustments albeit.

There are still rooms for improvement, however. One that needed attention is that, current technique may fail to reserve memory even if the total free size is adequate when there are hurdle blocks which make the tail end to start at a different position past these hurdle(s), in other words: the new tail end will be of smaller size which significantly reduce the chance to reserve memory of bigger size. To visualize this, imagine we have this configuration:

1
2
3
4
5
     POS           ADDRESS    PID      FREE           SIZE
 8388608    0x7f99ea135018      0       yes        8388600
16777216    0x7f99ea935018      0       no        16777208
33554432    0x7f99eb935018      0       yes       33554424
67108864    0x7f99ed935018      0       no        67108856

Notice that block at POS 16777216 is a hurdle block because it sits in the middle. If we want to reserve 33554428 bytes (4 bytes larger than what POS 33554432 can offer), although our memory from the free size standpoint is completely capable to offer the space, our allocator will not return any block. That is because we will need to defragment our memory by moving any hurdle block so that the tail end is above them. To do so, we may need to move parts of our memory into the disk. For now, this is not implemented due to its relative complexity, yet it is not a rocket science.

Although we have just talked about the mechanism without showing a single code of our allocator, I can be quite sure that it’s a rather simple code due to the fact that we don’t play with chances. All memory blocks are initialized and known at any given time–they are in a way uniform in nature. They just work by following exactly the same rules, eliminating the needs of using many ifs or elses.


Escaping capital and privilege crises in Fitzgerald’s "Winter Dreams"

Everyone in a community should feel a sense of belonging. Yet, there are pervasive biases that can make others feel unwelcome. The Winter Dreams by F. Scott Fitzgerald offered us a glimpse of some of those biases, such as how we are never satisfied, causing crises in the process. Unfortunately, those crises have disadvantaged many due to wars, racism, slavery, colonization, and the most recent social upheaval of our time: climate change, to name a few. To put a stop to those crises, we must escape this evolutionary glitch where our communities tend to place the privileged over the rest of nature, race, gender, and even society itself.

Across taxonomy classes, it has been demonstrated that many animals—including humans—tend to want to feel that they are in charge. The sociological term for that is known as agency. We can see this in action when Dexter, the main character, decided to want to quit being a golf caddy. He said, “I don’t want to caddy anymore” (1) before arguing that he was too old. But, Dexter was not even fourteen; he was young. As everyone’s favorite caddy, he easily earned a monthly stipend of which the amount will not be made elsewhere. Indeed, it was quite a folly of Dexter to quit the job. But, to understand his behavior, we can see it from the perspective of agency. Many times over, those who are under the agency of others have no choice but to be put under the mercy of their superiors. The story recounted how Miss Jones comically treated her nurse, Hilda, to the point that Dexter “could not resist the monstrous conviction that the little girl was justified in beating the nurse.” Dexter himself was once exhorted by the caddy master “what you standing there like a dummy for?” Not only that the question is disparaging, but it also highlights the fact that Dexter does not have an agency in his work. This lack of agency morphing into a lack of respect must be among the reasons why Dexter decided to quit. Indeed, such a strongly implied hierarchical structure can push one to want to increase their agency.

There are many ways to increase the scale of one’s agency, the surest path of which is by being wealthy. To that end, the privileged few like Dexter can use their cultural and/or social capital to an advantage. For example, Dexter increased his wealth by owning the largest string of laundries in town at an extremely young age. The capital to fund such an enterprise was not obtained from his prosperous father but was borrowed from “his college degree and his confident mouth” (2). But the fact is that, it is very unlikely for people with no or fewer capital under their belt to be able to borrow money from outside sources at such a young age, let alone be financially sound before their twenty-seventh birthday. Without a doubt, private wealth ownership has always been concentrated in the hands of the few. Many government policies in place have deliberately been made to gatekept specific people. In a way, whether intended or not, that has advanced the legacy of racism and widened the wealth gap. This neglect of the greater to the advantage of the few is not unique in America. While in the past this would mean European settlers exploiting enslaved people and freshly appropriated lands from the native communities; today, a great many developing countries like China, Indonesia, and India are all-out to catch up with their developed peers by committing to horrendous exploitation without much regard for the Earth if at all in their pursuit to advance their agency.

But the desire to command an agency is not unique amongst men and nations and states alike. It would be naive to assume that this obsession with agency has left women fully innocent in perpetuity. The text recounts how the-most-beautiful Judy Jones was concerned to a great deal that her boyfriend “was poor as a church-mouse” (5). She must have thought that her beauty is an honored privilege on which she can capitalize to find the most well-rounded man to mate. Although to fall into that is acceptable on an individual level, our society as a whole must not risk either overvaluing or soft-pedaling others simply by privileges, such as education, race, skin color, nationality; nor outward appearances such as religion, sexual orientation, accent and so forth. However, those biases are so hard to overcome that we were rightly reminded not to judge a book by its cover, cliché regardless. Yet, in a world increasingly global, everyone must be afforded the same rights and the same sense of belonging in a community. Throughout history, a lot of injustice has been pushed on those who are different. But, we can end this cycle.

The truth is, those sharing the same values, grew up in the same neighborhoods, and even having the same skin tone can still feel left out of a community, let alone those having different frequencies. Our modern society is still learning to live with each other in peace. Even Dexter—himself so financially accomplished through his own labor, and his dad owned the second-best grocery store in town—felt like a trespasser when he played golf with the rank of Mr. Hart, Mr. T. A. Hedrick, and Mr. Sandwood. He had to ensure himself that it was not necessary “to remark that he had once carried Mr. Hart’s bag” (3) when he was still a 14-years-old golf cady. It’s lucky that Dexter can get richer through his labor. Indeed, being rich is something that we can always try. But, many of us may have a degree of insecurity from something that is completely out of control, such as skin color, stature, age, sexual orientation, family background and so forth. Yet, society must graciously function beyond such superficial marking so that no one feels disempowered for being different, that no dissenting voice should be ignored, and that social cohesion shall be maintained for the better. The framework governing our communities must be written to suit all of its members, not only those most politically active or the richest 1% benefactors. Such a framework should be designed to see a human as a human, assessing us not by our skin colors but their effects on other people, their communities, nature and the Earth.

A society where everyone feels a sense of belonging is essential if we want to respond hand in hand to our time’s most pressing challenges. A community should be a place where its members can feel a warm interpersonal relationship regardless of capital or privileges. Make no mistake: we cannot deny nor dismantle anyone’s privilege. Yet, we cannot afford to value some humans over the others. We must have an open-ended, adaptive framework written by, from, and for those in the community where people are assessed by their effects on other people, their communities, nature and the Earth. Otherwise, we will continue to lack the moral compass in our relationship with one another if we still judge one another by their outward appearances, capital or privileges.

When I have to come to Harvard

Today, we ended the class a little bit earlier than scheduled due to some circumstances. Actually, the class I got assigned to is a mix of students from 4 different classes namely the ICP, U1, U2 and U3. Students from U1 needed to leave 20 minutes earlier, as such, I have to call it a day. I have been informed of that even before the class started so it’s not surprising to me. But do you know what’s surprising to me?

What surprising to me is my students’ reaction when I made an announcement that the class has to end. Non-U1 students were not exactly happy to learn about that. They complained like “nooooo…” or something like that in English. But again, we should not leave anyone behind, so it has to be ended.

I am not sure what that translate to, but it seems they really like this class. Their eyes has always been wide open since day 1. They raised their hand to ask whenever they’re a bit lost instead of having a “meh… whatever it doesn’t matter to me” attitude. And imagine when 2 or 3—sometimes even 5—students doing that at the same time. Indeed, the class can be busy. Extremely busy. But it was fun!

Their enthusiasm is just impossible to ignore.

For instance, today’s material was about variable and it was quite a challenging concept for most. We learned about how to name a variable, its purpose, how we can assign data to it, how they can be used in various different scenarios, and so on and so forth. Even if all of the concept is in Indonesian, when I asked the whole class if this is difficult, some shouted “no” affirmatively while the others would say like “yeah it’s fairly difficult than the previous topic.”

But, even at that challenging topic, no student was afraid to ask me. It’s that level of enthusiasm. But, I guess, that was also the moment when I see it for myself that it’s not easy to judge a student’s interest in a given topic. For example, a student being quiet in the class than their peers doesn’t mean he/she is not interested in the subject as much as a louder student is. It happened over and over and over again that this quiet student always raised their hand to ask me, wanting me to remove their doubt as soon as they have one.

All of them are, so far, that enthusiastic.

Their eyes has always been wide open since day 1.

I noticed that, the class would be extremely quiet whenever I presented something new. To reinforce what I said, I’d ask them to type some code from the slide. Then, they will ask me more questions. Some students may then run into problems, and those students won’t hesitate to ask me too. That’s the class normal cycle and pace.

My benchmark is, if students shout “aaaaaaah……. right!” then I know they were in a eureka! moment. Listening to that eureka made me so happy.

Ultimately. For me, I hope when they think of what they want to be in the future, and they see software engineering, they can gauge what it is about. At least, they can say: “oh! software engineering! I did that when I was much younger. It’s not that hard and it was fun. It challenged my way of thinking. It’s a doable field for me. I wanted to be one!”

Or, even if they say: “it is not for me!” it’s totally fine. At least they are far better-informed of what they want to be, what the field is like, and so on. Not everyone has to be a software engineer. Although, I did say that in the future, almost everything we do in life can hardly be separated from the use of technology.

As much as I can’t wait to get my own “aaaaah… I see” moments when I study on-campus, I will without doubt feel a little bit sad to no longer be able to see those students of mine. Or by indirectly put this program on hold for awhile. But, I will work harder to ensure that this program doesn’t stand still even if I will have to go to Harvard to study on-campus. Even if I am not in Indonesia for yet another time, Indonesians students must be able to study computer science and software engineering whenever wherever with or without me.


In The Making: Coding as Part of Primary School Education

This morning today marked a new beginning as we finally able to collaborate with a school in the city of Gresik. A collaboration that saw for the first time the introduction of computer science into the school’s classroom.

But what’s the purpose?

My wish and desire to build a programming language stretched many years back when I was still an elementary school student. (I am not joking.)

At that time, I created a simple language that I thought would be cooler than C/C++, and so I called it D. It was a poor man’s attempt.

But what’s the purpose?

Learning programming language is difficult. Even more so when we have to, at first, be convenient at commanding a third, unrelated language. When I was an elementary school student, I tried to teach computer programming to my own younger brother, and the eldest son of my neighbor …and rightly so, it was a tremendously painful experience for all of us, due to, for the most part: the language barrier.

But this morning was different for me as I entered a new chapter in my life I have long been waiting to do so.

Intro to Computer Science 101

Remember that my younger brother and my neighbor’s eldest son was having a bad time learning a programming language with me?

It hasn’t changed that much. I still don’t see computer science being taught at schools the way math, physics do.

Children these days may be comfortable using various software on their PCs or mobile phones. But, how those things are made is beyond everyone’s guess.

So the question remained: how can we bring computer science education into Indonesian classrooms without making them feel they are absolutely not gonna make it. Believe it or not, for various factors, this has not been easy.

As this is something new, I made a basic agreement with my students that there’s no stupid student in my class, and by extension, there is no stupid question either.

Although we started slow, as we try not to left anyone behind, we learned together various new concepts such as string and integer. This Saturday, we will learn iteration. I can clearly see their enthusiasm.

Students were indeed very enthusiastic. For example, not all computers were working as expected. For those unlucky few, they couldn’t just accept the fact that they were not able to register and hack together what we’re learning. They wanted me to address the issue to the point I feel sad and I feel bad for answering their nagging by asking them to join their friends with working computers. Luckily, in the end, theirs started to work as well thanks to the help from the school’s teacher.

I am happy that in this intro 101 class, I can see that level of enthusiasm. In addition, I have not seen any indication of language barrier. The issue I faced years ago when teaching how to code to my own brother and my neighbor’s oldest son is gone without a mark. A great starting point.

But, how could the barrier be gone?

That the language barrier is gone is a fact (although I have not done a further research to back this claim). I said it as a “fact” because I did not receive a blank stare. Instead, questions/problems have moved to be so much more technical:

  • Why the program throws an error when a string literal is missing a double quote
  • What is a null?
  • Why calling a function cannot have a space in between of the function name and the right parenthesis.

How is this possible? I suspect, this is in part because in the class, students are learning using a programming language I carefully develop, inside a platform not unlike HackerRank but so much simpler.

Future works

I want to bring these kind of smiles to more and more students.

I truly have never felt this much satisfied/happier/determined/purposeful than ever before:

But this is just the beginning. I wanted to expand this offering to as many more schools, to as many more classes, to as many more labs throughout the country. I wanted to see computer science be like any other “normal” subjects normally taught at schools.

Would it be possible? I don’t know. I will keep updating on this journey as promised. At least if I failed, future generations have something to learn from; something to refer and offer a much better solution.

Thanks to Sayuti Mulyo, Amin, and SD NU 1 Gresik’s principal and teachers who have been very open to this program since the beginning. Harvard has played a part in this journey as well, as from the class of Prof. James Frankel, the professor teaching Compiler Design and Implementation, I have gained a much better understanding of compiler-making. I will always be forever indebted to the Extension School as its mere existence was the starting point that made all of this a possibility.


How to merge a subfolder git into its parent’s git repo

Since years ago I have this centralized repo where I kept notes, code snippets, diagrams, lab codes and basically everything I have learned that I think will be valuable. I do that because I know I would like to come again someday there and regain knowledge quickly. I find this organization to be extremely helpful for me.

So, naturally, when I took the CSCI-E95 last semester, which was awesome, I wanted to have whatever I will learn to be inside that centralized repo as well. And of course, the code artifact is of utmost importance.

5 years in a message

It is not that I am a defeatist when I wrote that life is about accumulating pain. There is no denying in that. What we do instead, is to lessen such a pain. We invented medicine, technology, and even cured the meats and add that tomato cheese flavor to that pizza so we can be less in pain. That’s something special about us humans.

And yet here we are. Here we are afraid to say: Israel, could you help lessen the pain felt by the Palestinians? …if you self-consider an ally to Israel. Here we are, afraid to say: Russia, would you stop making them in pain? …if Russia and you are best friend. And no, I am (trying to be) neutral. I don’t think I can solve, or help solve, any problem without being neutral. I would love to have Israeli friends (I used to work with a Jewish colleague of mine from NYC). I’d love to have Russian friends (one of my neighbors is from Russia). I’d love to have you, Americans, Africans, other Asians as a friend. Europeans too. Anyone.

Sometimes, when we consider ourselves an ally or a close friend to someone; we will defend that someone to a point we won’t do if they are not our close, best friend. In that case, would it be naive if I imagine a world where everyone is everyone else’s best friend? I guess so? At least Mr. Lennon assured I am not the only one.

The world doesn’t work that way! (Does it?) Then perhaps, I should have renamed the title of this blog post to 5,000 years in a message. Maybe, our children 5,000 years from now could prove me wrong.

But no! no! I urgently in need to title this post specifically 5 years in a message.

Because, I want to imagine what 5 years from now will be like, where the war is over.

Where the war is over, but not because we turn this ancestral home of Homo sapiens, wasted.


Living, accumulating pain

What makes you happy? Eating foods? Traveling? Reading books?

And what makes you sad?

What makes you …in pain?

JK Rowling tried to visualize pain in the form of dementor.

Absorbing every single piece of peace out of you.

I used to think it is weak to talk about our pains. It’s mellow. Emo. Not a sign of a mature adult.

Do you ever think that way?

Take a deep breath.

Pain sure sapped that energy of life. Take a deep breath.

Try to imagine a happy moment in life.

Try to be peaceful.

Just try… 🙂

And if that’s still so painful.

Try to see a happy end.

Try to be peaceful. Just try. A little bit more.

A possibly happy day.

Smiling freely. Only naturally.