Holding Myself Accountable (Pt. 1)
Is this just a phase?
I missed the blog post for week 6 and 7. There needs to be a consequence for when I miss a week.
What Hurts the Most?
Right now the most “painful” thing would be harm to my wallet. But where should my money go?
- A charity
- A little bit weird because it’s not the worst thing to give money to a charity so would it have to be to a cause I don’t like?
- Securities
- Investing a bit of money into a stock. crypto, or something else makes my pocket less liquid for sure, but still benefits me so I won’t be necessarily upset but missing a week with this one
- A family member or friend
- I like this one because it has the dual effect of hurting my wallet and outing me to someone else that I didn’t “go to the gym”.
Using Cloudflare Workers and cron jobs within that Worker, we can easily run code, but this code needs to do the following:
- Run every week when I don’t fill out a blog post
- Take money from my account, securely
Running every week will be trivial. I’ll add a value I have to set to disable the cron job for that week. Taking the money out turns out, is a lot harder due to the sensitive nature of banking. I had wanted to send money to my brother every time I failed but the hoops I’d have to go through to make it clean and automated I don’t think is worth it for now.
I found this site Beeminder that has an API for charging a User (turns out these charges are how the service makes money) so I’ll use that.
Using Beeminder
Beeminder has a goal system itself that will charge you if you don’t complete a goal, but I’m a software developer and like to solve things in 5 hours that should’ve taken 5 minutes. I want to use their service as a free way to use Stripe to take money from my account in a predictable, customizable manner.
We can write some simple Javascript to send a POST request to the charge endpoint:
const createBeeminderCharge = async () => {
const url = "https://www.beeminder.com/api/v1/charges.json";
const data = {
auth_token: process.env.BEEMINDER_AUTH_TOKEN,
user_id: "danielbeans",
amount: "5",
note: "smh daniel...",
};
const params = new URLSearchParams(Object.entries(data));
try {
const response = await fetch(url, { method: "POST", body: params });
return await response.json();
} catch (error) {
console.error("Error:", error);
}
};
One of my past supervisors Michael loved commenting on my MRs to make my code “smaller” and more testable, which I’ve taken to heart:
const USER_ID = "danielbeans";
const BEEMINDER_AUTH_TOKEN = process.env.BEEMINDER_AUTH_TOKEN;
const BEEMINDER_BASE_URL = "https://www.beeminder.com/api/v1";
const sendBeeminderRequest = async (url, data) => {
data.auth_token = BEEMINDER_AUTH_TOKEN;
const params = new URLSearchParams(Object.entries(data));
const response = await fetch(url, { method: "POST", body: params });
return await response.json();
};
const createBeeminderCharge = async (amount, dry_run = true) => {
const url = `${BEEMINDER_BASE_URL}/charges.json`;
const data = {
user_id: USER_ID,
amount: "5",
note: "smh daniel...",
dry_run: "", // Curiously only needs to exist as a parameter to count as a dry run
};
if (dry_run === false) {
delete data.dry_run;
}
try {
return await sendBeeminderRequest(url, data);
} catch (error) {
console.error("Error:", error);
}
};
Then we can simply call:
createBeeminderCharge(5);
We will leave implementing this code to next week…