Kekuatan dan Kutukan Manusia
Sekalipun terbatas, namun potensi yang dimiliki manusia sangatlah besar. Tiga ribu tahun yang lalu, mungkin nenek moyang kita tidak pernah berpikir bahwa keturunannya akan berhasil menginjakkan kaki di bulan, membuat mobil listrik, atau menciptakan alat seukuran telapak tangan yang bisa menyimpan isi perpustakaan Alexandria.
Secara fisik, kita mungkin tak sehebat hewan-hewan lain. Kita tidak bisa terbang seperti elang, tidak bisa menyamarkan diri seperti bunglon, dan tak bisa menyelami laut semahir lumba-lumba.
Kekuatan terbesar kita berasal dari kemampuan mengkombinasikan apa yang ada dan menciptakan sesuatu yang semestinya tidak pernah ada. Kita mengkombanasikan suara menjadi kata, kata menjadi kalimat, kalimat menjadi cerita. Lalu kita mulai menciptakan fiksi, menciptakan dewa-dewa, menyepakati aturan sosial, membuat teori dan permodelan berdasarkan pengamatan. Kita juga memotong kayu menjadi balok-balok yang bisa dimanfaatkan untuk membuat senjata dan rumah, memanfaatkan sapi untuk membajak sawah, menciptakan mesin uap untuk menggantikan sapi, dan memantik ledakan teknologi informasi.
Dengan masa hidup dan tenaga yang terbatas, teknologi telah memungkinkan manusia untuk mencapai hal-hal yang semestinya tidak mungkin tercapai. Namun dengan teknologi pula, kita juga telah menciptakan kompleksitas yang sebelumnya tidak pernah terpikirkan.
Tahun 2010. Waktu itu teknologi yang tampaknya umum dipakai adalah PHP + MySQL. Tidak ada yang istimewa. LAMPP stack, filezilla (untuk upload ke FTP), dan CPanel untuk akses hosting. Aplikasi web adalah solusi yang praktis untuk berbagai hal. Client tidak perlu menginstall aplikasi tambahan, melakukan setting jaringan secara khusus, dan sebagainya. Hanya perlu punya web browser, dan bisnis bisa berjalan sebagaimana mestinya. Satu server untuk banyak client, satu solusi untuk jutaan masalah. Waktu itu saya pikir, teknologi informasi tidak akan berkembang terlalu banyak. Kalaupun ada yang berubah, paling-paling hanya antar muka saja. Tentu saja itu pendapat yang sangat naif.
Tahun 2020. Nyaris dua tahun sudah saya berkarir di perusahaan yang baru. Kejayaan web application memang masih tampak. Prinsip client-server pun masih terpakai, sekalipun client nya tak hanya terbatas pada web browser. Namun teknologi di balik itu sudah jauh berbeda. Satu server saja tak cukup untuk membendung ratusan ribu request per detik. Sekalipun ada bagian-bagian yang tampaknya tidak membutuhkan resource terlalu banyak, namun ada pula bagian-bagian yang membutuhkan alokasi resource secara fleksibel. Setiap komponen di belakang layar perlu di manage secara berbeda.
Sepuluh tahun yang lalu, mungkin saya pikir menaikkan/menurunkan resource, membuat routing internal, dan sebagainya, adalah pekerjaan seorang network/infrastructure engineer. Ya, tentu saja tidak salah. Namun mereka tidak melakukan semua itu secara itu secara langsung. Mereka memanfaatkan perangkat otomasi yang secara ajaib bisa melakukan semuanya di saat yang tepat (https://kubernetes.io/).
Para network/infrastructure engineer tidak perlu bangun tengah malam, untuk mengubah konfigurasi di nginx hanya karena ada peningkatan jumlah request secara mendadak. Mereka cukup melakukan konfigurasi awal, membantu developer membuat konfigurasi yang benar, dan bangun mendadak hanya saat ada masalah yang benar-benar besar.
Bahkan untuk membuat konfigurasi awalpun, mereka tidak sepenuhnya bekerja sendiri. Ada perangkat otomasi lain yang bisa membantu mereka menciptakan konfigurasi tersebut. Ya, bahkan file konfigurasi itupun masih bisa dikonfigurasi (https://helm.sh/).
Saya percaya, teknologi, seperti halnya evolusi, bukanlah satu garis lurus yang indah. Antara satu teknologi dan teknologi yang lain, mungkin saling bersaing, mungkin memanfaatkan prinsip yang sama, tapi implementasinya berbeda, atau mungkin dibangun secara tumpang tindih.
Software engineering adalah salah satu pekerjaan paling kotor dan tidak elegan. Tapi di situlah kita hidup dan bernafas. Menempelkan satu hal di atas hal yang lain, melakukan segala cara untuk membuat pekerjaan kita cukup maintainable dan tidak hancur di production.
Membuat Tool Otomasi
Beberapa software engineer terlahir secara spesial. Kenyataannya, hampir semua software engineer merasa spesial. Saking spesialnya, barangkali beberapa dari kita cukup yakin bahwa kita termasuk dalam 5% software engineer terbaik sepanjang masa.
Sebagaimana orang-orang spesial pada umumnya, banyak dari kita yang memiliki pemikiran kreatif-inovatif. Kita benci rutinitas. Kitapun kerap mengeluh bahwa beberapa tugas rutin itu semestinya bisa diotomasi. Maka kitapun mulai jatuh dalam lembah procrastination merancang sesuatu yang mulia untuk menghindari rutinitas.
Tooling dan otomasi bukanlah hal baru bagi seorang software engineer. Otak kita seolah memberikan reward khusus saat kita berhasil menghindari tugas-tugas menjemukan. Entah dengan cara mendelegasikannya pada orang lain, atau dengan menurunkan tingkat kesulitannya.
Tooling dan otomasi tak hanya membanjiri otak kita dengan serotonin, tapi juga (jika diterapkan secara tepat), bisa menghemat waktu, mengurangi pemakaian resource, dan mereduksi kesalahan.
Sayangnya, meyakinkan para manager dan engineer lain kerapkali bukanlah pekerjaan yang mudah. Sekalipun semua orang yakin akan keajaiban otomasi, namun menghabiskan terlalu banyak waktu untuk menciptakan otomasi justru menjauhkan kita dari tujuan utama.
Jika kita cukup baru di suatu bidang, biasanya kita akan sok tahu memiliki pemikiran terbuka sehingga bisa melihat hal-hal yang bisa diotomasi, dan tergoda untuk menciptakan alat otomasi kita sendiri. Tentu saja, saya sendiripun pernah (atau mungkin masih) berada dalam fase ini.
Dari pengalaman manis dan pahit yang saya alami, berikut adalah beberapa tips yang barangkali bermanfaat sebelum membuat tool otomasi sendiri:
- Lakukan secara manual dulu. Rasanya tool otomasi kita akan cukup valid jika setidaknya kita sudah terbiasa melakukan suatu pekerjaan secara manual. Kita akan bisa menciptakan formula terbaik, saat kita sudah pernah mengalami "rasa sakit" akibat melakukan sesuatu secara manual.
- Berkomunikasi dengan yang lebih ahli atau cari tahu tool-tool yang umum dipakai. Kita perlu tahu juga, apakah di luar sana sudah ada tool-tool yang biasa dipakai untuk mengatasi masalah kita. Jika perlu, kita bisa berdiskusi dengan orang-orang yang lebih senior, mengapa kita belum/tidak memakai tool-tool tersebut. Seringkali, yang kita butuhkan bukanlah sebuah tool otomasi yang 100% baru. Mungkin kita cuma butuh satu layer tipis yang bisa ditulis memakai shell script.
- Yang penting jalan dan bermanfaat. Seorang software engineer kerapkali mengharapkan karyanya elegan, mudah di maintain, dan mudah dikembangkan. Tentu saja itu semua adalah hal yang baik. Sayangnya, saat kita membuat sebuah tool otomasi, kita kerapkali tak memiliki kemewahan dari segi waktu. Bagaimanapun juga tool otomasi yang kita buat bukanlah produk utama perusahaan. Dalam hal ini jauh lebih baik bahwa tool yang kita buat bisa dipakai dan bermanfaat.
- Jangan memaksakan paradigma. Cobalah mengotomasi proses yang sudah ada, jangan memaksakan proses yang baru hanya semata-mata karena itu tertulis sebagai "best practice" di sebuah buku atau podcast. Pada akhirnya tool yang kita buat ini akan kita pakai di dunia nyata, bukan di dunia ideal yang ada dalam pikiran kita. Selain itu, usahakan tool yang kita buat bersifat opsional. Artinya, orang lain tidak harus menggunakan tool tersebut jika merasa tidak cocok.
- Jangan fanatik pada suatu teknologi.
Jangan. Secara umum jangan terlalu mendewakan satu teknologi dan menistakan teknologi lain. Tooling yang kita buat tidak harus ditulis menggunakan bahasa-bahasa kekinian. Kadang-kadang shell script saja sudah cukup. Pernahkah kalian melihat cara meng-copy file/directory yang lebih mudah dan straight-forward dari
cp -R <source> <destination>
? Tapi sebaliknya, jangan juga terlalu mendewakan shell script. Tentunya tidak masuk akal untuk membuat back propagation dengan hanya menggunakan shell script. - Belajar shell script.
Shell script memang bukan bahasa pemrograman terbaik. Namun harus diakui, bahwa sebagian besar tool otomasi yang ada selalu terkait dengan shell script. Bukan tanpa alasan airflow secara khusus menyediakan
BashOperator
. Bahkan sebagian besar framework CI/CD menggunakan file YAML yang di dalamnya berisi perintah-perintah shell script.
Inem Si Asisten Pribadi
Pada dasarnya, sebuah tool otomasi memiliki satu fungsi wajib: menyembunyikan detail yang terlalu kompleks, dan menyediakan interface yang lebih mudah.
Mari sejenak bayangkan kita adalah Tono, seorang developer node.js di sebuah startup yang tidak terlalu terkenal. Perusahaan tempat Tono bekerja memiliki panduan-panduan sendiri dalam membuat service/route. Sayangnya, mereka tidak menyediakan boilerplate khusus. Sebagai developer pemula, Tono juga kerap kali lupa untuk melakukan transpilasi, menginstall paket npm, dsb.
Maka di suatu senja, ditemani alunan musik indie, Tono mulai berpikir untuk menciptakan sesuatu yang bisa memudahkan pekerjaannya.
Sama seperti project-project hebat lainnya, Tono pun sangat berhati-hati dalam memilih nama yang cocok untuk pembantu virtualnya. Nama tersebut harus cukup mudah diingat, filosofis, dan representatif. Tono pun memutuskan untuk menamai project tersebut "Inem".
Setelah memutuskan nama yang catchy, Tono pun mulai mendefinisikan requirement yang harus dipenuhi Inem. Berikut adalah kesimpulan Tono:
- Inem harus bisa menjalankan service node.js lebih baik darinya. Jangan sampai ada step yang terlewat.
- Inem harus bisa membuat service
- Inem harus bisa membuat route pada sebuah service.
- Inem tidak boleh terlalu banyak menuntut.
Tono pun memulai petualangannya dengan membuat sebuah folder bernama "inem" di home directory nya. Jari-jari Tono bergerak cepat di atas keyboard mekanik kesayangannya. touch inem.sh && chmod 755 inem.sh
, demikian Tono membuat sebuah sebuah shell script dan membuatnya executable.
Tono menyeruput Americano di hadapannya. Lalu dengan cekatan ia kembali mengetikkan sebuah logika switch-case. Walaupun terlihat aneh, namun Tono bisa melihat bahwa pada dasarnya shell script pun mirip dengan bahasa pemrograman lain. Ia merasa agak janggal karena shell-script menggunakan notasi $1
, $2
, dan seterusnya untuk membaca input argument. Satu hal yang membuat Tono geli adalah penggunaan esac
untuk menutup case
. Tapi Tono bisa dengan mudah menyesuaikan diri dengan bahasa pemrograman kuno ini. Tak lupa pula, Tono membuat boilerplate nodejs service pada folder service-boilerplate
.
Inem: Membuat dan Menjalankan Service
#!/bin/sh
case $1 in
"run")
npm install
tsc
npm start
;;
"makeService")
# mendapatkan direktori tempat inem.sh bersarang
DIR="$(dirname "$0")"
# meng-copy service-boilerplate ke directory yang dituju ($2)
cp -R "$DIR/service-boilerplate" $2
;;
esac
Tono pun segera ingin melihat bagaimana inem beraksi. Pada awalnya ia menjalankan perintah ~/inem/inem.sh makeService gateway
. Sesuai harapannya, muncul sebuah directory dengan nama gateway
. Isi direktori tersebut persis sama dengan isi service-boilerplate
yang telah ia buat sebelumnya. Kini, Tono yakin, ia dapat membuat seribu service dalam semalam dengan bantuan Inem.
Tak lekas berpuas diri, Tono pun ingin menguji apakah perintah run
yang ia tulis sudah benar. Maka dengan cekatan, ia berpindah ke direktori gateway
dengan perintah cd
, dan kemudian menjalankan ~/inem/inem.sh run
. Sekalipun ada beberapa warning, namun Tono bisa yakin bahwa service gateway
yang dibuat Inem sudah berjalan dengan baik. Untuk memastikannya, Tono pun mengirimkan HTTP request dengan mengetikkan curl localhost:3000
. Tono merasa cukup puas. Tak sampai satu jam, ia telah menyelesaikan dua dari empat item list yang ia buat.
Malam masih panjang, Tono tak ingin waktunya habis untuk memanggil Inem. Mengetikkan ~/inem/inem.sh
tampaknya cukup melelahkan. Maka Tono pun memutuskan untuk membuat alias. alias inem=${HOME}/inem/inem.sh
. Kini Tono bisa memanggil Inem dengan lebih cepat.
Untuk menghasilkan efek yang lebih permanen, Tono bisa saja menambahkan alias tersebut pada ~/.bashrc
atau ~/.zshrc
. Tono juga mengamati, bahwa pada ~/.bashrc
miliknya terdapat alias seperti ini: alias ls='ls --color=auto'
. Sekarang Tono tahu, mengapa output tampilan ls
di komputernya selalu berwarna. Tono akhirnya sadar, mengapa ~/.bashrc
dan ~/.zshrc
sebaiknya diberi akses read only
. Tampaknya berbahaya jika seseorang memanfaatkan perintah alias
untuk memanipulasi terminalnya. Kelak, saat ia membuat perintah-perintah otomasi, ia tak akan secara sembarangan mengubah hak akses kedua file ini.
Inem: Membuat Route
Matahari mulai terbenam, tapi tidak dengan semangat Tono. Keberhasilan yang sudah Tono raih membuatnya makin bersemangat. Ditambah lagi dengan pompaan kafein yang membanjiri otaknya bersama alunan musik indie.
Kini Tono ingin membuat Inem sanggup membuat route dalam sebuah service. Pandangan Tono terfokus pada file app.js
pada boilerplate yang ia buat.
Tono bisa saja memanfaatkan copy paste untuk membuat route. Tapi tentu saja untuk benar-benar membuatnya ter load, ia harus secara manual mengedit app.js
. Tono berpikir, barangkali proses itu bisa diotomasi menggunakan regex, atau perintah sed
.
Tapi sudahlah, untuk saat ini, sebaiknya ia befokus pada apa yang bisa dikerjakan terlebih dahulu. Maka Tono mulai membuat route-boilerplate.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.send('get list of resources');
});
router.get('/:id', function(req, res, next) {
const id = req.params.id;
res.send(`get resource ${id}`);
});
router.post('/', function(req, res, next) {
res.send('insert the resource');
});
router.put('/:id', function(req, res, next) {
const id = req.params.id;
res.send(`edit resource ${id}`);
});
router.delete('/:id', function(req, res, next) {
const id = req.params.id;
res.send(`delete resource ${id}`);
})
module.exports = router;
Kembali ke masalah semula, Tono perlu menghubungkan route tersebut ke app.js
. Setelah menatap langit malam dan menghabiskan secangkir americano, Tono mendapatkan beberapa solusi yang tampaknya masuk akal.
- Tono bisa saja memanfaatkan regex dan perintah
sed
. Tapi tampaknya script nya akan menjadi sulit dibaca. Tono sendiri juga tidak akrab dengan regex. Mungkin ia bisa mengambil pendekatan ini jika ia sudah siap. - Tono bisa melihat setiap baris di
app.js
sebagai element array. Tono juga bisa memanfaatkan methodsplice
untuk memanipulasi array menggunakan javascript. Tampaknya dengan kondisinya sekarang, pendekatan inilah yang paling masuk akal.
Tono pun langsung mengimplementasikan idenya dengan cara memodifikasi inem.sh
dan membuat script route-injector.js
Isi inem.sh
yang baru adalah sebagai berikut:
#!/bin/sh
case $1 in
"run")
npm install
tsc
npm start
;;
"makeService")
DIR="$(dirname "$0")"
cp -R "$DIR/service-boilerplate" $2
;;
"makeRoute")
DIR="$(dirname "$0")"
cp "${DIR}/route-boilerplate.js" "$(pwd)/routes/${2}.js"
node "${DIR}/route-injector.js" "$(pwd)/app.js" "$2"
esac
Sedangkan isi dari route-injector.sh
adalah sebagai berikut:
const fs = require('fs');
const { argv } = process;
const fileName = argv[2];
const routeName = argv[3];
const content = fs.readFileSync(fileName, {encoding:'utf8', flag:'r'});
const lines = content.split('\n');
let requireInjectionIndex = 0;
for (let i=0; i<lines.length; i++) {
const line = lines[i];
if (line.startsWith('var app')) {
requireInjectionIndex = i > 0 ? i - 1 : i;
break;
}
}
lines.splice(requireInjectionIndex, 0, `var ${routeName}Router = require('./routes/${routeName}');`);
let appUseInjectionIndex = 0;
for (let i=0; i<lines.length; i++) {
const line = lines[i];
if (line.startsWith("app.use('")) {
appUseInjectionIndex = i;
break;
}
}
lines.splice(appUseInjectionIndex, 0, `app.use('/${routeName}', ${routeName}Router);`);
const newContent = lines.join('\n');
fs.writeFileSync(fileName, newContent);
Saat yang ditunggupun tiba, Tono harus menguji kelayakan Inem. Dengan cekatan, ia berpindah ke directory gateway
dan mengetikkan perintah sakti: inem makeRoute book
. Tono pun lantas membuka gateway/routes/book.js
dan gateway/app.js
untuk memastikan bahwa segala sesuatunya sudah terbuat sesuai harapannya.
Separuh senyuman terkembang di bibir Tono. Sekalipun cukup puas, namun Tono tahu bahwa asumsi dan harapan bisa saja salah. Ia benar-benar harus menjalankan service gateway
dan memberikan HTTP request untuk memastikan semuanya berjalan baik. Tono pun mulai mengetikkan inem run
, disusul dengan curl localhost:3000/book
.
Setelah tahu bahwa Inem bisa bertugas dengan baik, Tono pun tak ragu-ragu untuk mengembangkan senyumnya secara utuh.
Berkembang Bersama
Inem mungkin bukan tool yang sempurna. Beberapa di antara kalian mungkin merasa Tono seharusnya menggunakan teknik yang lebih baik. Script milik Tono barangkali sebaiknya dipecah supaya lebih modular. Antara template dan helper, sebaiknya dibuatkan directory yang terpisah. Beberapa kode yang yang berulang, mungkin bisa disatukan untuk mengurangi redundancy (walaupun sebenarnya redundancy tidak selalu buruk).
Tentu saja kalian benar. Tapi untuk saat ini, dengan kemampuan dan pengetahuan yang ia miliki. Tono sudah melakukan yang terbaik. Ia bisa menghemat waktu untuk membuat service
dan route
. Ia juga bisa mengurangi kesalahan saat menjalankan service.
Sebagai seorang engineer, personal automaton kita sebaiknya berkembang sesuai kemampuan dan pengetahuan kita.
Tono menutup laptop nya. Hari ini ia sudah bekerja cukup keras. Besok pun, masih ada pekerjaan yang menanti. Namun dengan adanya Inem di sisi Tono, ia siap menghadapi hari esok dengan lebih baik.
Discussion
xkcd yang berhubungan: xkcd.com/1205/
