“Remember you will die”. Marcus Aurelius and Steve Jobs pondered this thought daily. How much richer would your life be if you did so too?
This practice would certainly help me when I’m mindlessly scrolling Twitter from the bathroom stall, so I decided to create a Twitter Bot anyone can follow to get daily death reminders.
Curious to compare how a junior, a senior and a staff engineer would approach this project, I scheduled three pair-programming sessions, starting with a junior engineer friend…
## Juniors build
![[juniorsenior_api.png]]
We start browsing newspapers’ obituary sections: “Let’s copy their format: a short message and a picture. We can remove the last name. We’re going to need a scraper, a database, and code to run the Twitter Bot. Let’s start with the toughest one, the bot”.
My friend instantly opens the Twitter documentation, Postman, and starts building the three-legged authentication flow. His first lines of code are:
```tsx
// Upload
var upload_pic_config = {
method: 'post',
url: 'https://upload.twitter.com/1.1/media/upload.json?media_category=tweet_image&oauth_consumer_key=XXX&oauth_token=XXX&oauth_signature_method=HMAC-SHA1&oauth_timestamp=XXX&oauth_nonce=XXX&oauth_version=1.0&oauth_signature=XXX',
headers: {
'Cookie': 'guest_id=v1%XXX; guest_id_ads=v1%XXX; guest_id_marketing=v1%XXX; personalization_id="XXX
...formData.getHeaders()
},
data: formData
};
```
He then moves on to database querying when uploading to Twitter suddenly breaks! Some tokens expired. It’s weird: it works when we input the same headers in Postman!
Turns out Postman does some behind-the-scenes magic to fill in empty headers. We struggle to understand how to generate these hidden tokens… until the session ends.
This is an elegant sign of the impending civilization collapse from bad software. If a few generations of engineers don’t learn the principles behind their tools and those break, we’re back to Middle Ages. If you think I’m a drama queen, enjoy [this talk](https://www.youtube.com/watch?v=ZSRHeXYDLko) by Jonathon Blow. Or read about Dune’s [Butlerian Jihad](https://dune.fandom.com/wiki/Butlerian_Jihad). Or worse, read on.
## Seniors glue
The second pairing session is with a senior engineer friend. She wants to see the existing code: “What the hell are you doing?! Looks like junior engineer code to me. You shouldn’t rebuild the wheel, it’s much faster to glue existing wheels together”.
She opens npm, searches for “Twitter API”, and finds the perfect one. It has no dependencies, many built on top of it, and it’s actively maintained and used.
![[juniorsenior_npm.png]]
Her first line of code is:
```tsx
import { TweetV2PostTweetResult, TwitterApi } from 'twitter-api-v2'
```
“With this package, I bet we’ll be done in 45 minutes”. 47 minutes later, she transpiles Typescript into Javascript, creates a standalone executable file, and shouts: “Done!”
## Staff engineers architect
The most interesting session is that with the Staff Engineer. He has an entirely different approach, centered around asking clarifying questions, focusing on architecture, and aggressively optimizing for time-to-production.
### **Clarifying questions**
Unlike the other two, he starts with “let’s not look at the code” and follows up with 15 minutes of clarifying questions:
- What makes you want to build this?
- Are you trying to build a throwaway program, just to understand how it works, or do you want to push it to prod’ and maintain it for a long time?
- What features do you want to build now vs what can wait?
We then look at the code from the previous sessions. “This doesn’t match your needs. It’s going to be very hard to maintain. And you’re missing out on the biggest potential learning from this project - architecture.”
### Architecture
“Architecting systems is one of the most powerful skills in tech. And it’s the longest to learn. You’ll save years by paying attention to it earlier. So even if this is overkill for this project, let’s have you learn how to properly architect a project.”
“First, let’s create a `database`. It’ll make your code easier to maintain. You’ll have logs of what you scraped, and what failed to get posted on Twitter. Then, you’ll have to build a `post-on-Twitter` micro-service and `scraper` micro-service.”
“To make everything robust, we’ll use the database to store all the [states](5.%20Juniors%20build,%20seniors%20glue,%20staff%20engineers%20architect..md): the outcome of your code should be influenced by what’s in the database, and nothing else. Your Bot should only post on Twitter once a day, even if your server reboots itself mid-execution. Or if you accidentally run your code 1,000 times in a row.”
His first lines of “code” are:
```sql
CREATE TABLE obituaries (
id SERIAL PRIMARY KEY,
name character varying NOT NULL,
picture_url character varying NOT NULL,
is_twitted boolean NOT NULL DEFAULT false,
);
```
“The last line encapsulates the obituary state, `is_twitted`. To make sure every obituary is only ever twitted once, we end the `post-to-twitter` micro-service with:”
```tsx
// Mark obituary as twitted
await db_client.query(`UPDATE obituaries SET is_twitted = TRUE WHERE id = ${obituary_to_tweet.id}`)
```
“Writing robust code takes a bit longer but pays back quickly. We can’t let it prevent you from getting to production today though!”
### Optimizing for time to production
![[juniorsenior_cron.png]]
The biggest threat to this project isn’t technical difficulty but lack of motivation. We need to build momentum, and there’s no better way than getting to production. Let’s cut scope - we can scrap manually for now.”
We were in production one hour later.
## Conclusion
A junior, a senior, and a staff engineer ~~walk into a bar~~ approach problems very differently. Here’s what I learned from each pair-programming sessions:
**Junior**
- **Enjoy the process.** Building everything yourself takes much longer, but is deeply satisfying. It opens the door to the fascinating complexity of the software ecosystem, and builds stronger foundations.
**Senior**
- **Use packages.** Don’t rebuild the wheel.
**Staff**
- **Ask clarifying questions.** This reflex is useful across industries. For example, my very unscientific research highlights a stark correlation between a hairdresser’s skills and the number of questions they ask.
- **Focus on building a clean architecture.** And on making code robust.
- **Optimize for time to production.** It builds momentum, which builds motivation.
**Other learnings:**
- **Pair programming drastically accelerates growth.** Software engineering is a craft, and the best craftsmen come from programs that pair juniors with several masters, like the [Compagnons du Devoir](https://en.wikipedia.org/wiki/Compagnons_du_Devoir), or [GitStart.dev](https://www.gitstart.dev/). I learned a lot by watching them code, from their high level approaches to their VS Code katas.
- **Make your side-projects count.** It takes the same time to build a Bot that posts “HelloWorld” and one that encourages [Memento Mori](https://en.wikipedia.org/wiki/Memento_mori) meditation.
---
## Appendix
- Steve Jobs mentioned pondering death every day in [this section](https://www.youtube.com/watch?t=544&v=UF8uR6Z6KLc&feature=youtu.be) of his Stanford Commencement speech.
- Learnings summary in table format
| | Junior | Senior | Staff |
| --- | --- | --- | --- |
| First action | Opens the docs and coding | Searches for a package | Asks clarifying questions |
| Emphasis | Getting hands dirty | Finding shortcuts | Growing architecture skills |
| Achieved during the session | Small features done, but overall program doesn’t work | Code runs but is unmaintainable code and doesn’t run in prod’ | A subset of the features run in prod’ |
- Side by side
- First lines of codes
Junior
```tsx
// Upload
var upload_pic_config = {
method: 'post',
url: 'https://upload.twitter.com/1.1/media/upload.json?media_category=tweet_image&oauth_consumer_key=XXX&oauth_token=XXX&oauth_signature_method=HMAC-SHA1&oauth_timestamp=XXX&oauth_nonce=XXX&oauth_version=1.0&oauth_signature=XXX',
headers: {
'Cookie': 'guest_id=v1%XXXX; guest_id_ads=v1%XXXXX; guest_id_marketing=v1%XXXXXX; personalization_id="XXXXXXXXXX
...formData.getHeaders()
},
data: formData
};
```
Senior
```tsx
import { TweetV2PostTweetResult, TwitterApi } from 'twitter-api-v2'
```
Staff
```sql
CREATE TABLE obituaries (
id SERIAL PRIMARY KEY,
name character varying NOT NULL,
picture_url character varying NOT NULL,
is_twitted boolean NOT NULL DEFAULT false,
);
```
- Approach to making code robust
Junior (😅)
```tsx
```
Senior
```tsx
get XXXX(){ return `${this.scrappingFolder}/website-${this.today}.html` } // prettier-ignore
[...]
hasAlreadyRunToday = () => existsSync(this.XXXX)
```
Staff: states are stored in the database
```tsx
// Don't post if last tweet was within 24h
if (**db_tweet_response**.rows.length > 0) {
const last_tweet_time = db_tweet_response.rows[0].tweet_time
const now = new Date()
const diff_ms = now.getTime() - last_tweet_time.getTime()
const diff_hours = Math.floor(diff_ms / 3600000)
if (diff_hours < 24) {
console.log('Last tweet was within 24h, not posting again')
return
}
}
```
- Note: all the code presented on this page is licensed under [GNU GPL v2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).