Category: Tutorial & Panduan

Panduan praktis penggunaan AI

  • Buat Chatbot WhatsApp untuk Bisnis dengan AI + No-Code

    Buat Chatbot WhatsApp untuk Bisnis dengan AI + No-Code

    Cerita ini familiar: kamu punya bisnis kecil, WhatsApp jadi channel utama komunikasi dengan pelanggan, dan setiap hari ada pertanyaan yang sama berulang — “Stok ada?”, “Ongkir ke mana saja?”, “Bisa bayar apa?”. Kamu harus jawab manual satu-satu, dan kalau telat reply, calon pembeli kabur.

    Chatbot WhatsApp adalah solusinya. Dan yang menarik: kamu tidak harus jago coding untuk membuat ini.

    Sebelum Mulai: Pahami Dulu Opsinya

    Ada beberapa jalur untuk membuat chatbot WhatsApp:

    1. WhatsApp Business App — bisa setup auto-reply, tapi sangat terbatas. Ini bukan chatbot proper, cuma auto-responder sederhana.
    2. WhatsApp Business API + platform no-code — ini yang kita bahas. Lebih powerful, bisa integrasikan AI.
    3. Custom development — fullstack, bisa paling fleksibel tapi butuh developer dan waktu.

    Artikel ini fokus ke jalur kedua: WhatsApp Business API + platform no-code + AI.

    Tools yang Akan Kita Pakai

    Untuk setup yang accessible dan tetap powerful, kombinasi yang saya rekomendasikan:

    • Twilio atau WATI — sebagai gateway WhatsApp Business API
    • n8n atau Make (Integromat) — sebagai automation platform
    • OpenAI API atau Claude API — sebagai otak AI-nya
    • Airtable atau Google Sheets — sebagai “database” sederhana untuk data produk/FAQ

    Kalau mau yang lebih plug-and-play (dan budget lebih longgar), ada platform all-in-one seperti WATI, Respond.io, atau Tidio yang sudah bundle semuanya.

    Langkah 1: Setup WhatsApp Business API

    Ini bagian yang paling “teknis” dan perlu waktu.

    Opsi A: Pakai WATI (Recommended untuk Pemula)

    WATI adalah partner resmi WhatsApp Business API. Mereka sudah handle setup API, dan kamu langsung dapat dashboard untuk manage conversation.

    1. Daftar di wati.io
    2. Hubungkan nomor WhatsApp bisnis kamu (nomor baru, bukan yang sudah ada di WA biasa)
    3. Submit untuk verifikasi bisnis — biasanya 1-3 hari kerja
    4. Setelah approved, kamu sudah punya akses API

    Opsi B: Twilio WhatsApp Sandbox

    Untuk testing dulu sebelum production:

    1. Daftar Twilio, aktifkan WhatsApp Sandbox
    2. Join sandbox dengan kirim kode ke nomor Twilio yang diberikan
    3. Kamu bisa test webhook dan flow sebelum pakai nomor resmi

    Langkah 2: Desain Conversation Flow

    Sebelum setup di platform, desain dulu alur percakapannya. Pertanyaan kunci:

    • Apa skenario utama yang mau dihandle chatbot? (FAQ, order status, booking, dsb.)
    • Kapan chatbot harus handover ke manusia?
    • Tone komunikasinya seperti apa? (formal, santai, campuran?)

    Contoh flow sederhana untuk toko online:

    User: Halo / Hi / Permisi
    

    Bot: "Halo! Selamat datang di [Nama Toko]. Saya bisa bantu apa?

    1. Cek stok produk

    2. Cek ongkir

    3. Status pesanan

    4. Tanya yang lain"

    User: 1

    Bot: [Tanya nama/kode produk yang ingin dicek]

    Bot: [Check database/spreadsheet, reply dengan info stok]

    Untuk pertanyaan di luar flow yang sudah ditentukan, inilah AI masuk.

    Langkah 3: Setup Automation di n8n

    n8n adalah automation platform open-source yang bisa kamu self-host atau pakai cloud version-nya.

    Buat Workflow WhatsApp → AI → Reply

    1. Trigger Node: Webhook

    – n8n akan menerima pesan dari WhatsApp via webhook

    – Copy webhook URL, paste ke konfigurasi WATI/Twilio

    1. Switch Node: Route berdasarkan isi pesan

    – Kalau pesan adalah angka menu (1, 2, 3, 4) → route ke flow yang sesuai

    – Kalau pesan bebas → route ke AI node

    1. OpenAI/Claude Node: Generate jawaban

    – Setup system prompt yang menjelaskan konteks bisnis kamu

    – Pass pesan user sebagai input

    – Contoh system prompt:

    Kamu adalah customer service untuk [Nama Toko], toko online yang jual [produk].
    

    Jawab pertanyaan pelanggan dengan ramah dan singkat.

    Jam operasional: Senin-Sabtu 09.00-17.00 WIB.

    Kalau pertanyaan di luar kemampuanmu, minta pelanggan untuk hubungi WhatsApp admin.

    1. HTTP Request Node: Kirim balasan ke WhatsApp

    – Gunakan API WATI/Twilio untuk kirim pesan kembali ke user

    Langkah 4: Tambahkan “Memory” dengan Spreadsheet

    Supaya chatbot bisa jawab pertanyaan spesifik tentang produk kamu, integrasikan database sederhana:

    1. Buat Google Sheets dengan kolom: nama_produk, stok, harga, deskripsi
    2. Di n8n, tambahkan node Google Sheets yang fetch data ini
    3. Pass data ini ke context prompt AI

    Contoh prompt dengan konteks:

    Kamu adalah CS [Nama Toko]. Berikut data produk kami:
    

    [DATA_PRODUK_DARI_SHEETS]

    Jawab pertanyaan pelanggan berdasarkan data di atas.

    Kalau stok 0, bilang sedang kosong dan tawari untuk notify ketika ready.

    Dengan cara ini, ketika pelanggan tanya “Sepatu size 40 ada tidak?”, AI bisa cek data dan jawab akurat.

    Langkah 5: Handover ke Human Agent

    Ini penting: chatbot bukan untuk replace manusia sepenuhnya.

    Setup kondisi handover:

    • Kalau user bilang “mau beli” atau “mau order” → forward ke human
    • Kalau ada complain atau pertanyaan kompleks → forward ke human
    • Kalau di luar jam operasional → simpan request, notifikasi tim saat jam buka

    Di WATI, kamu bisa assign conversation ke agent tertentu. Di n8n, bisa tambahkan notifikasi ke Slack/email ketika handover terjadi.

    Estimasi Biaya

    | Komponen | Biaya Estimasi |

    |—|—|

    | WATI (starter) | ~$40/bulan |

    | n8n cloud | ~$20/bulan (atau free kalau self-host) |

    | OpenAI API | Pay per use, ~$0.002/1K token |

    | Total estimasi | ~$60-80/bulan |

    Kalau traffic masih rendah (ratusan pesan/hari), biaya OpenAI API-nya sangat kecil — mungkin hanya $2-5/bulan.

    Limitasi yang Perlu Kamu Tahu

    Verifikasi bisnis WhatsApp bisa lama. Meta kadang strict soal approval. Siapkan dokumen bisnis yang lengkap.

    Template message untuk outbound. Kalau kamu yang initiate pesan ke user (bukan reply), harus pakai template yang sudah diapprove Meta. Ini ada prosesnya.

    AI bisa salah. Selalu ada fallback ke human agent, dan monitor conversation secara berkala terutama di awal.

    Kesimpulan

    Membuat chatbot WhatsApp dengan AI dan no-code itu feasible. Dengan kombinasi WATI + n8n + OpenAI, kamu bisa punya sistem yang handle ratusan percakapan tanpa capek — dan tetap bisa masuk loop manusia ketika diperlukan.

    Kuncinya: mulai dari flow yang simpel, test dulu, baru expand. Jangan mau langsung sempurna di awal.


    Punya bisnis yang butuh chatbot WhatsApp? Atau mau setup otomasi yang lebih kompleks? Yuk ngobrol — hubungi mafadev.

  • Cara Integrasikan Payment Gateway di Aplikasi (Midtrans/Xendit)

    Cara Integrasikan Payment Gateway di Aplikasi (Midtrans/Xendit)

    Pertama kali saya integrasikan payment gateway, saya takut salah. Ini bukan bug biasa yang bisa di-rollback — ini uang sungguhan, transaksi nyata, customer yang bisa komplain.

    Rasa takut itu wajar. Tapi setelah beberapa kali integrasi, saya bisa bilang: lebih mudah dari yang terlihat, selama kamu tahu apa yang dilakukan dan tidak skip langkah testing.

    Di Indonesia, ada dua pemain utama yang paling sering dipakai: Midtrans dan Xendit. Keduanya sudah mature, punya dokumentasi yang baik, dan SDK yang tersedia untuk berbagai bahasa. Di artikel ini saya akan bahas keduanya — plus tips praktis dari pengalaman langsung.

    Midtrans vs Xendit: Pilih yang Mana?

    Sebelum mulai, penting untuk tahu perbedaan keduanya agar tidak salah pilih:

    Midtrans (sekarang bagian dari Gojek ekosistem):

    • Lebih lama di pasar Indonesia, database merchant lebih besar
    • Snap (UI pembayaran bawaan) yang polished dan mudah diintegrasikan
    • Support luas untuk metode pembayaran lokal: GoPay, OVO, DANA, VA bank, Indomaret/Alfamart
    • Cocok untuk aplikasi yang butuh minimal setup dan UX yang sudah terbukti

    Xendit:

    • Lebih developer-friendly dari sisi API design
    • Support untuk disbursement (kirim uang) yang lebih robust
    • Bisa handle multiple currency lebih baik untuk bisnis regional
    • Cocok untuk fintech, platform dengan kebutuhan payout, atau yang butuh API yang lebih fleksibel

    Untuk mayoritas e-commerce atau SaaS dengan user Indonesia: Midtrans cukup dan lebih simpel. Untuk platform yang butuh fitur disbursement atau regional expansion: Xendit lebih cocok.

    Integrasi Midtrans: Step by Step

    Setup Akun dan Konfigurasi

    1. Daftar di midtrans.com
    2. Masuk ke Dashboard → pilih environment Sandbox untuk development
    3. Ambil Server Key dan Client Key dari Settings → Access Keys

    Simpan di environment variables, jangan hardcode di kode:

    MIDTRANS_SERVER_KEY=SB-Mid-server-xxxxxxxxxx
    

    MIDTRANS_CLIENT_KEY=SB-Mid-client-xxxxxxxxxx

    MIDTRANS_IS_PRODUCTION=false

    Instalasi SDK

    # Node.js
    

    npm install midtrans-client

    Python

    pip install midtransclient

    PHP

    composer require midtrans/midtrans-php

    Buat Transaksi (Server-Side)

    Contoh dengan Node.js:

    const midtransClient = require('midtrans-client');
    
    

    const snap = new midtransClient.Snap({

    isProduction: process.env.MIDTRANS_IS_PRODUCTION === 'true',

    serverKey: process.env.MIDTRANS_SERVER_KEY

    });

    async function createTransaction(orderId, amount, customerDetails) {

    const parameter = {

    transaction_details: {

    order_id: orderId, // ID unik per transaksi

    gross_amount: amount // dalam Rupiah, integer

    },

    customer_details: {

    first_name: customerDetails.name,

    email: customerDetails.email,

    phone: customerDetails.phone

    },

    item_details: customerDetails.items

    };

    try {

    const transaction = await snap.createTransaction(parameter);

    return {

    token: transaction.token,

    redirect_url: transaction.redirect_url

    };

    } catch (error) {

    throw new Error(Midtrans error: ${error.message});

    }

    }

    Tampilkan Payment UI (Client-Side)

    Midtrans Snap menyediakan popup UI — kamu hanya perlu load script dan panggil satu function:

    <script src="https://app.sandbox.midtrans.com/snap/snap.js"
    

    data-client-key="YOUR_CLIENT_KEY"></script>

    <button onclick="bayar()">Bayar Sekarang</button>

    <script>

    async function bayar() {

    // Minta token dari backend kamu

    const response = await fetch('/api/create-transaction', {

    method: 'POST',

    body: JSON.stringify({ orderId: 'ORDER-001', amount: 150000 })

    });

    const { token } = await response.json();

    // Tampilkan payment popup

    window.snap.pay(token, {

    onSuccess: function(result) {

    console.log('Sukses:', result);

    window.location.href = '/success?order=' + result.order_id;

    },

    onPending: function(result) {

    console.log('Pending:', result);

    window.location.href = '/pending';

    },

    onError: function(result) {

    console.error('Error:', result);

    alert('Pembayaran gagal');

    },

    onClose: function() {

    console.log('Popup ditutup user');

    }

    });

    }

    </script>

    Handle Webhook (Notification)

    Ini bagian yang paling penting dan paling sering di-skip: webhook handler. Midtrans akan mengirim notifikasi ke endpoint kamu setiap kali status transaksi berubah.

    app.post('/api/midtrans-webhook', async (req, res) => {
    

    const notification = req.body;

    // Verifikasi signature — WAJIB!

    const snap = new midtransClient.Snap({

    isProduction: false,

    serverKey: process.env.MIDTRANS_SERVER_KEY

    });

    const statusResponse = await snap.transaction.notification(notification);

    const orderId = statusResponse.order_id;

    const transactionStatus = statusResponse.transaction_status;

    const fraudStatus = statusResponse.fraud_status;

    if (transactionStatus === 'capture' && fraudStatus === 'accept') {

    await updateOrderStatus(orderId, 'paid');

    } else if (transactionStatus === 'settlement') {

    await updateOrderStatus(orderId, 'paid');

    } else if (transactionStatus === 'cancel' || transactionStatus === 'deny' || transactionStatus === 'expire') {

    await updateOrderStatus(orderId, 'cancelled');

    }

    res.status(200).send('OK');

    });

    Perhatian: Jangan update status order hanya berdasarkan callback dari client-side (snap.pay onSuccess). User bisa manipulasi ini. Selalu andalkan webhook untuk update status final.

    Integrasi Xendit: Pendekatan yang Lebih Fleksibel

    Xendit lebih cocok kalau kamu mau kontrol lebih atas payment flow. Contoh membuat invoice (link pembayaran):

    const { Xendit } = require('xendit-node');
    
    

    const xendit = new Xendit({ secretKey: process.env.XENDIT_SECRET_KEY });

    const { Invoice } = xendit;

    async function createXenditInvoice(orderId, amount, customerEmail) {

    const invoice = await Invoice.createInvoice({

    data: {

    external_id: orderId,

    amount: amount,

    payer_email: customerEmail,

    description: Pembayaran Order ${orderId},

    success_redirect_url: https://yourdomain.com/success,

    failure_redirect_url: https://yourdomain.com/failed,

    }

    });

    return invoice.invoice_url; // URL yang dikirim ke customer

    }

    Xendit juga punya webhook yang perlu dihandle:

    app.post('/api/xendit-webhook', (req, res) => {
    

    // Verifikasi dengan callback token

    const callbackToken = req.headers['x-callback-token'];

    if (callbackToken !== process.env.XENDIT_CALLBACK_TOKEN) {

    return res.status(403).send('Unauthorized');

    }

    const { external_id, status } = req.body;

    if (status === 'PAID') {

    updateOrderStatus(external_id, 'paid');

    }

    res.status(200).send('OK');

    });

    Tips Kritis yang Sering Diabaikan

    Selalu Validasi di Server-Side

    Client bisa berbohong. Validasi payment status selalu dari webhook server-side, bukan dari callback client.

    Buat Order ID yang Unik dan Idempotent

    Format yang baik: ORDER-{timestamp}-{random}. Pastikan idempotent — kalau transaksi sama disubmit dua kali, tidak boleh charge dua kali.

    Log Semua Transaksi

    Simpan semua webhook payload ke database untuk audit trail. Kalau ada dispute, kamu butuh bukti lengkap.

    await db.transactionLogs.create({
    

    orderId,

    provider: 'midtrans',

    status: transactionStatus,

    rawPayload: JSON.stringify(notification),

    createdAt: new Date()

    });

    Test dengan Akun Sandbox yang Lengkap

    Midtrans dan Xendit punya sandbox environment dengan test credentials. Gunakan ini untuk test semua skenario: pembayaran sukses, pending, expired, fraud — jangan hanya test happy path.

    Setup Alert untuk Transaksi yang Aneh

    Transaksi dengan amount sangat besar, atau lonjakan transaksi tiba-tiba, butuh notifikasi ke kamu. Setup alert sederhana ke Slack atau email untuk edge cases ini.

    Checklist Sebelum Go Live

    Sebelum switch ke production, pastikan:

    • [ ] Server Key dan Client Key sudah ganti ke production keys
    • [ ] isProduction: true di konfigurasi
    • [ ] Webhook URL sudah di-register di dashboard dengan URL production
    • [ ] Test payment sukses di production dengan nominal kecil (Rp 1.000)
    • [ ] Error handling untuk semua skenario sudah diimplementasikan
    • [ ] Log transaksi sudah berjalan
    • [ ] Refund flow sudah di-test

    Butuh bantuan integrasi payment gateway untuk aplikasi atau toko online kamu? Yuk ngobrol — hubungi mafadev dan kita kerjakan dengan benar dari awal.

  • Cara Buat Workflow Otomatis dengan Make + AI

    Cara Buat Workflow Otomatis dengan Make + AI

    Ada satu momen yang saya ingat jelas: saya habiskan satu jam setiap Senin pagi untuk copy-paste laporan dari Notion ke Google Sheets, membuat summary-nya, terus kirim email ke klien. Satu jam. Setiap Senin. Selama berbulan-bulan.

    Sampai akhirnya saya duduk, buka Make, dan dalam dua jam setup workflow otomatis yang melakukan semua itu tanpa saya sentuh. Sekarang Senin pagi saya minum kopi sambil workflow itu jalan sendiri.

    Kalau kamu belum kenalan dengan Make (sebelumnya bernama Integromat), ini adalah platform otomasi yang menurut saya jauh lebih powerful dari Zapier untuk kasus-kasus yang kompleks. Dan ketika kita tambahkan AI ke dalamnya, workflow yang bisa kita bangun jadi beda level.

    Make vs Zapier: Kenapa Saya Pilih Make?

    Zapier bagus untuk otomasi sederhana: “kalau A terjadi, lakukan B.” Tapi Make punya visual editor yang lebih ekspresif, mendukung percabangan logika (branching), iterasi (looping), dan bisa handle data transformation yang kompleks tanpa harus keluar ke kode eksternal.

    Harganya juga lebih kompetitif untuk volume operasi yang sama.

    Yang paling penting: Make punya native module untuk OpenAI, Anthropic, dan berbagai AI provider lain — jadi integrasi AI jadi sangat mudah.

    Konsep Dasar Make yang Harus Kamu Tahu

    Sebelum masuk ke tutorial, beberapa istilah kunci:

    • Scenario: Satu workflow lengkap dari trigger sampai action akhir
    • Module: Satu blok dalam scenario — bisa trigger, action, atau data transformer
    • Trigger: Pemicu yang menjalankan scenario (misalnya: email masuk, form disubmit, jadwal tertentu)
    • Bundle: Satu “paket” data yang mengalir melalui scenario
    • Router: Percabangan — bundle bisa diarahkan ke jalur berbeda berdasarkan kondisi

    Tutorial: Workflow Otomatis Email + AI Summary

    Mari kita bangun sesuatu yang nyata: workflow yang otomatis membaca email masuk, menganalisisnya dengan AI, lalu mencatat hasilnya ke spreadsheet dan mengirim notifikasi Slack.

    Step 1: Setup Trigger Gmail

    1. Buat Scenario baru di Make
    2. Tambahkan module Gmail > Watch Emails
    3. Connect akun Gmail kamu
    4. Set filter: misalnya hanya email dengan label tertentu, atau dari domain spesifik
    5. Set interval polling: setiap 15 menit cukup untuk kebanyakan kasus

    Step 2: Tambahkan AI Analyzer

    Setelah trigger, tambahkan module OpenAI (atau Anthropic) > Create Completion:

    Prompt:
    

    Analisis email berikut dan berikan:

    1. Kategori email (inquiry, complaint, order, other)
    2. Tingkat urgensi (low/medium/high)
    3. Summary singkat (maksimal 2 kalimat)
    4. Action item yang disarankan

    Email:

    Subject: {{subject}}

    From: {{from.email}}

    Body: {{snippet}}

    Respond in JSON format.

    Set temperature ke 0.3 untuk hasil yang konsisten. Pilih model yang sesuai — untuk task klasifikasi seperti ini, model yang lebih kecil sudah cukup dan lebih hemat biaya.

    Step 3: Parse JSON Response

    AI akan return JSON, tapi Make menerimanya sebagai teks biasa. Gunakan module JSON > Parse JSON untuk mengubahnya jadi struktur data yang bisa dipakai modul selanjutnya.

    Step 4: Router — Percabangan Berdasarkan Urgensi

    Tambahkan Router untuk memisahkan handling berdasarkan tingkat urgensi:

    • High urgency → Tambahkan ke Notion urgent board + kirim Slack mention langsung
    • Medium urgency → Tambahkan ke Google Sheets + kirim Slack biasa
    • Low urgency → Hanya tambahkan ke Google Sheets

    Step 5: Google Sheets Logging

    Untuk setiap jalur yang berujung ke Sheets, tambahkan module Google Sheets > Add Row:

    • Timestamp: {{now}}
    • From: {{from.email}}
    • Subject: {{subject}}
    • Kategori: {{parseJson.category}}
    • Urgensi: {{parseJson.urgency}}
    • Summary: {{parseJson.summary}}
    • Action Item: {{parseJson.action_item}}

    Step 6: Slack Notification

    Tambahkan Slack > Create a Message dengan format yang informatif:

    Email Baru - [{{parseJson.urgency | upper}}]
    

    From: {{from.name}} <{{from.email}}>

    Subject: {{subject}}

    Category: {{parseJson.category}}

    Summary:

    {{parseJson.summary}}

    Suggested Action:

    {{parseJson.action_item}}

    Tips Praktis Membuat Workflow Make yang Solid

    Selalu Pakai Error Handler

    Make punya fitur Error Handler yang sering diabaikan pemula. Tambahkan di setiap module yang kritis — terutama koneksi ke API eksternal. Kalau AI gagal return JSON yang valid, scenario tidak harus crash total.

    Module AI -> [Error Handler] -> Fallback: kirim raw email ke Slack

    Manfaatkan Data Store untuk State

    Kalau workflow kamu perlu “ingat” sesuatu antar eksekusi (misalnya: sudah proses email ini atau belum?), gunakan Make Data Store sebagai mini-database. Gratis dan terintegrasi langsung.

    Batasi Token AI dengan Smart Preprocessing

    Sebelum kirim ke AI, trim dulu data yang tidak perlu. Email dengan thread panjang? Ambil 500 karakter pertama saja kalau cuma butuh summary. Ini hemat biaya dan hasilnya sering tidak jauh beda.

    Gunakan module Text Parser > Replace atau fungsi bawaan Make untuk pre-processing sederhana.

    Gunakan Webhooks untuk Trigger Real-time

    Kalau kamu tidak mau nunggu interval polling, pakai Webhook sebagai trigger. Banyak service (GitHub, Stripe, Typeform) bisa kirim data ke webhook Make secara real-time saat event terjadi.

    Contoh Workflow Lain yang Bisa Kamu Replikasi

    Workflow 1: Content Pipeline

    • Trigger: Jadwal (setiap Senin pukul 08.00)
    • Ambil trending topics dari RSS feed atau API
    • AI generates content outline
    • Simpan ke Notion sebagai draft
    • Notifikasi Slack ke tim konten

    Workflow 2: Customer Support Triage

    • Trigger: Form submission (Typeform/Tally)
    • AI klasifikasikan jenis support ticket
    • Route ke board yang tepat di Jira/Trello
    • Auto-reply ke customer dengan template yang dipersonalisasi AI

    Workflow 3: Invoice Processing

    • Trigger: Email attachment masuk
    • Parse PDF invoice dengan AI (atau Mindee/Google Document AI)
    • Ekstrak data: vendor, nominal, tanggal jatuh tempo
    • Tambahkan ke accounting spreadsheet
    • Buat reminder di Google Calendar

    Berapa Biaya Operasionalnya?

    Pertanyaan yang wajar. Mari hitung untuk workflow email yang kita bangun tadi:

    • Make: Plan Starter (500 operations/bulan) = gratis. Plan Core (10.000 ops) = sekitar $10/bulan
    • OpenAI API: Dengan gpt-4o-mini, ~200 token per email, $0.15 per juta token input = hampir tidak terasa untuk ratusan email
    • Total: Untuk 500 email/bulan, total biaya bisa di bawah $5

    Sangat masuk akal untuk penghematan waktu yang didapat.

    Kesimpulan

    Make + AI bukan hanya soal otomasi tugas berulang. Ini soal membangun sistem yang bisa berpikir dan membuat keputusan sederhana tanpa intervensi manusia di setiap langkah.

    Yang kamu perlu adalah:

    1. Identifikasi proses repetitif yang makan waktu
    2. Petakan alurnya (trigger → proses → output)
    3. Tentukan di mana AI bisa ambil keputusan
    4. Bangun, test, iterate

    Mulai dari yang kecil. Otomasi satu proses dulu, lihat hasilnya, baru expand. Jangan coba langsung otomasi seluruh operasional bisnis dalam satu scenario raksasa — itu cara paling ampuh untuk membuat workflow yang susah di-debug.


    Mau bangun workflow otomasi yang custom untuk bisnis kamu? Atau butuh bantuan integrasi Make dengan sistem yang sudah ada? Yuk ngobrol — hubungi mafadev.

  • Cara Membuat CLI Tool Sendiri dengan Bantuan AI

    Cara Membuat CLI Tool Sendiri dengan Bantuan AI

    Salah satu hal yang membuat saya produktif naik drastis beberapa bulan belakangan bukan apps baru yang mahal, bukan workflow mewah — tapi CLI tools kecil yang saya membuat sendiri untuk automasi hal-hal repetitif di pekerjaan sehari-hari.

    Dan yang membuat saya bisa membuat tools itu lebih cepat? AI sebagai pair programmer.

    Artikel ini bukan tutorial akademis. Ini lebih ke: “gini cara saya benar-benar membuat CLI tool dari nol dengan bantuan AI, langkah demi langkah.”

    Kenapa CLI Tool?

    Sebelum masuk ke cara membuat, validasi dulu kenapa CLI tool worth it:

    • Speed: Satu command untuk menjalankan serangkaian aksi yang biasanya butuh 5-10 langkah manual
    • Repeatable: Jalankan hal yang sama persis berkali-kali tanpa error manusia
    • Composable: Bisa di-pipe dengan tools lain di terminal
    • Shareable: Bisa dishare ke tim, bisa masuk ke repo, bisa di-versioning

    Contoh nyata yang saya membuat: tool untuk rename file markdown sesuai konvensi tertentu, tool untuk generate boilerplate project structure, tool untuk batch resize gambar dengan preset tertentu. Kecil-kecil tapi efeknya besar.

    Pilihan Stack

    Untuk CLI tool, ada beberapa pilihan populer:

    Node.js — Paling accessible kalau kamu JavaScript/TypeScript developer. Library seperti commander.js, yargs, atau oclif membuat ini mudah.

    Python — Bahasa scripting yang paling natural untuk automasi. Click dan Typer adalah library CLI yang elegant.

    Go — Kalau mau binary yang compiled, single-file, dan fast. cobra adalah library CLI standar di ekosistem Go.

    Bash — Untuk yang simple dan tidak perlu distribusi. Tapi scaling-nya terbatas.

    Untuk artikel ini, kita pakai Node.js dengan TypeScript karena paling gampang di-demo dan banyak developer sudah familiar.

    Setup Project

    Mulai dari scratch:

    mkdir my-cli-tool
    

    cd my-cli-tool

    npm init -y

    npm install commander chalk ora

    npm install -D typescript @types/node ts-node

    npx tsc --init

    Struktur direktori dasar:

    my-cli-tool/
    

    ├── src/

    │ ├── index.ts # Entry point

    │ ├── commands/ # Command handlers

    │ └── utils/ # Helper functions

    ├── package.json

    └── tsconfig.json

    Di Sini AI Masuk: Cara Efektif Pakai AI untuk Build CLI

    Ini bagian intinya. Bukan sekadar “tanya AI terus copy paste” — ada cara yang lebih efektif.

    Langkah 1: Describe Tool Kamu dengan Jelas

    Sebelum minta AI menulis kode, definisikan dulu dengan jelas:

    • Apa yang tool ini lakukan?
    • Input apa yang diterima?
    • Output apa yang dihasilkan?
    • Edge case apa yang perlu di-handle?

    Contoh prompt yang bagus:

    > “Bantu saya membuat CLI tool di Node.js dengan TypeScript. Tool ini bernama imgopt dan fungsinya: menerima path folder sebagai argument, scan semua file JPG dan PNG di folder tersebut, resize ke max-width 1200px (maintain aspect ratio), compress dengan quality 80%, dan simpan ke subfolder /optimized. Tampilkan progress bar saat processing. Kalau folder /optimized sudah ada, tanya konfirmasi sebelum overwrite.”

    Prompt spesifik seperti gini akan beri output yang jauh lebih berguna dari sekadar “membuat CLI tool untuk resize gambar.”

    Langkah 2: Generate Skeleton, Bukan Final Code

    Saya biasanya minta AI untuk buat skeleton/struktur dulu, bukan langsung kode lengkap:

    > “Dulu kamu beri prompt di atas — sekarang generate struktur folder dan file yang dibutuhkan, dengan function signatures yang perlu diimplementasi. Jangan tulis implementasi detailnya dulu.”

    Ini membuat kamu mengerti arsitekturnya sebelum detail kode ada. Lebih mudah untuk review dan understand.

    Langkah 3: Implement Bagian per Bagian

    Setelah struktur clear, implement satu command atau satu fungsi sekaligus:

    // src/index.ts — yang AI generate sebagai starting point
    

    import { Command } from 'commander';

    import { optimizeImages } from './commands/optimize';

    const program = new Command();

    program

    .name('imgopt')

    .description('CLI tool untuk optimasi gambar')

    .version('1.0.0');

    program

    .command('optimize <folder>')

    .description('Optimize semua gambar di folder')

    .option('-w, --width <number>', 'Max width (default: 1200)', '1200')

    .option('-q, --quality <number>', 'Quality 1-100 (default: 80)', '80')

    .option('-o, --output <folder>', 'Output folder (default: optimized)', 'optimized')

    .action(optimizeImages);

    program.parse();

    Lalu untuk setiap bagian yang perlu diimplementasi, tanya AI dengan konteks yang spesifik.

    Langkah 4: Iterasi dengan Error

    Ini yang sering dilewat. Ketika ada error, jangan langsung fix sendiri atau langsung paste ke AI tanpa konteks. Cara yang lebih efektif:

    1. Jalankan kode
    2. Kalau ada error, screenshot atau copy error message-nya
    3. Paste ke AI dengan konteks: “Ini error yang muncul ketika saya run dengan input [X]. Ini adalah kode yang saya jalankan: [kode]. Ini error-nya: [error]. Tolong explain kenapa terjadi dan bagaimana fix-nya.”

    Minta explanation, bukan sekadar fix. Ini membuat kamu belajar dan mengerti, bukan cuma copy-paste.

    Contoh Real: Tool Rename Markdown Files

    Ini tool sederhana yang benar-benar saya membuat. Masalahnya: saya punya banyak file markdown yang nama filenya inkonsisten, dan saya mau standardize jadi format YYYY-MM-DD-judul-kebab-case.md.

    Prompt ke AI:

    > “Membuat CLI tool Node.js TypeScript bernama mdren yang bisa rename file markdown. Command: mdren rename . Behavior: scan semua file .md di folder, extract tanggal dari frontmatter YAML (field date), extract title dari frontmatter (field title), convert title ke kebab-case, rename file ke format YYYY-MM-DD-judul-kebab-case.md. Tampilkan preview rename sebelum eksekusi dan minta konfirmasi. Kalau file tidak punya frontmatter, skip dan beri warning.”

    Dalam 2-3 iterasi dengan AI, tool ini jadi. Sesuatu yang kalau saya tulis manual dari nol mungkin butuh setengah hari.

    Publish ke npm (Opsional)

    Kalau mau share ke tim atau publik:

    // package.json
    

    {

    "name": "your-cli-tool",

    "bin": {

    "mytool": "./dist/index.js"

    },

    "scripts": {

    "build": "tsc",

    "prepublish": "npm run build"

    }

    }

    Setelah build dan npm publish, orang lain bisa install dengan npm install -g your-cli-tool.

    Tips Tambahan

    Tambahkan --dry-run flag untuk operasi yang destructive (rename, delete, overwrite). Jalankan dulu tanpa benar-benar eksekusi, lihat apa yang akan terjadi.

    Gunakan chalk untuk colored output — ini membuat CLI kamu jauh lebih readable, terutama untuk error (merah), success (hijau), dan warning (kuning).

    Error handling yang proper — jangan biarkan tool crash dengan stack trace mentah. Catch error dan beri pesan yang human-readable.

    Simpan di PATH kamu — entah via npm global install atau symlink manual, pastikan tool kamu bisa dipanggil dari mana saja di terminal.

    Kesimpulan

    CLI tool kustom adalah investasi produktivitas yang underrated. Dan sekarang dengan AI sebagai pair programmer, barrier untuk membuat tool sendiri jauh lebih rendah.

    Kuncinya: jangan minta AI menulis semua sekaligus. Iterate, tanya per bagian, minta explanation bukan cuma code dump. Treat AI seperti junior developer yang sangat cepat, tapi tetap butuh diarahkan dan di-review hasilnya.


    Punya ide CLI tool yang mau kamu membuat tapi tidak tahu mulai dari mana? Atau butuh partner untuk develop tools custom untuk workflow tim kamu? Yuk ngobrol — hubungi mafadev dan kita bangun bareng.

  • Refactoring Legacy Code dengan Bantuan AI

    Refactoring Legacy Code dengan Bantuan AI

    Kamu membuka file yang terakhir disentuh 3 tahun lalu. Tidak ada komentar. Variable bernama data2, tempVar, dan flag. Function sepanjang 400 baris. Tidak ada test. Dan ini harus kamu modify sekarang.

    Selamat datang di dunia legacy code.

    Setiap developer pasti pernah menghadapi ini — entah itu codebase warisan dari developer sebelumnya, project lama milik sendiri, atau “temporary solution” yang sudah jadi permanent. Dan sekarang, dengan bantuan AI, kita punya tools yang lebih baik untuk menghadapi situasi ini.

    Tapi AI bukan tongkat ajaib. Refactoring yang ceroboh bisa merusak sistem yang sebelumnya “jelek tapi jalan.” Artikel ini adalah panduan praktis dan realistis.


    Mengapa Legacy Code Itu Susah Disentuh?

    Sebelum bicara solusi, penting memahami masalahnya:

    Tidak ada test — tidak ada safety net. Kamu tidak tahu apakah perubahan kamu merusak sesuatu sampai ada yang laporan bug di production.

    Tight coupling — semua hal terhubung ke semua hal. Ubah satu bagian, tiga bagian lain ikut rusak.

    Context yang hilang — kenapa kode ini ditulis seperti ini? Ada bisnis rule tersembunyi? Ada workaround untuk bug di library tertentu? Dokumentasinya: tidak ada.

    Fear of change — “kalau masih jalan, jangan disentuh” adalah wisdom yang populer tapi juga trap yang membuat sistem makin susah di-maintain.


    Strategi Dasar: Understand Before You Change

    Rule nomor satu refactoring: jangan ubah kode yang tidak kamu mengerti.

    Ini bukan tentang paham setiap baris — tapi paham apa yang sistem ini lakukan secara keseluruhan, input apa yang masuk, output apa yang keluar, dan apa saja side effects-nya.

    Di Sinilah AI Sangat Membantu: Code Comprehension

    Sebelum ubah apapun, minta AI untuk bantu kamu memahami kodenya.

    Prompt yang efektif:

    Ini adalah fungsi [nama] dari codebase lama kami.
    

    Tolong jelaskan:

    1. Apa yang fungsi ini lakukan secara high-level
    2. Apa saja edge cases yang di-handle
    3. Ada tidak pola yang tidak umum atau mungkin workaround untuk bug tertentu
    4. Apa yang mungkin akan rusak kalau fungsi ini diubah

    [paste kode]

    AI tidak akan selalu benar — dia tidak tahu konteks bisnis kamu. Tapi dia bisa membantu kamu melihat pola yang mungkin terlewat ketika membaca cepat, dan mengajukan pertanyaan yang tepat.


    Framework Refactoring: Langkah Demi Langkah

    Fase 1: Characterization Tests

    Sebelum refactor, tulis test yang mendokumentasikan behavior saat ini — bukan behavior yang seharusnya. Ini yang disebut characterization tests atau approval tests.

    Tujuannya bukan memvalidasi kebenaran kode, tapi memastikan behavior tidak berubah setelah refactoring.

    Minta AI untuk bantu generate characterization test:

    Berikut adalah fungsi yang mau saya refactor:
    

    [paste kode]

    Tolong buatkan characterization tests menggunakan Jest yang:

    1. Capture behavior saat ini (bukan yang seharusnya)
    2. Cover semua branch yang ada
    3. Gunakan input yang realistis berdasarkan kode yang ada
    4. Tambahkan komentar yang menjelaskan KENAPA test ini ada

    Fokus pada mendokumentasikan apa yang terjadi sekarang, bukan apa yang seharusnya terjadi.

    Fase 2: Safe Zone Analysis

    Identifikasi bagian mana yang aman diubah dan mana yang berisiko:

    Relatif aman diubah:

    • Nama variable dan function (dengan rename yang proper)
    • Formatting dan whitespace
    • Extract method untuk blok kode yang ada
    • Komentar dan dokumentasi
    • Tipe data (dengan hati-hati)

    Butuh sangat hati-hati:

    • Logic bisnis yang ada
    • Urutan operasi
    • Error handling
    • Anything menyangkut database transactions
    • Code yang menyentuh external API

    Fase 3: Refactoring Bertahap

    Jangan lakukan big bang refactoring. Lakukan perubahan kecil, jalankan test setelah setiap perubahan.

    Urutan yang disarankan:

    1. Rename — perbaiki nama variable dan function yang tidak jelas
    2. Extract — pindahkan code blocks ke function terpisah tanpa mengubah logic
    3. Inline — hapus abstraksi yang tidak perlu
    4. Simplify conditionals — sederhanakan if-else yang complex
    5. Remove duplication — setelah kamu paham, baru konsolidasi yang duplikat

    Teknik Spesifik dengan AI

    1. Explain Complex Logic

    Tolong explain code ini baris per baris.
    

    Kemudian identifikasi bagian yang paling complex dan suggest cara

    untuk membuatnya lebih readable tanpa mengubah behavior.

    [paste kode]

    2. Rename Suggestions

    Variable dan function names berikut tidak cukup descriptive.
    

    Berikan suggestion nama yang lebih baik berdasarkan apa yang kode ini lakukan:

    • data2 → ?
    • tempVar → ?
    • processIt() → ?
    • flag → ?

    Konteks: [jelaskan apa yang kode ini lakukan]

    3. Extract Function

    Ini adalah fungsi yang terlalu panjang (400+ baris).
    

    Tolong identifikasi logical boundaries yang bisa di-extract

    menjadi function terpisah tanpa mengubah behavior.

    Berikan output dalam format:

    • Nama function baru yang disarankan
    • Baris mana yang masuk ke function tersebut
    • Parameter yang dibutuhkan
    • Return value

    [paste kode]

    4. Detect Patterns dan Antipatterns

    Review kode berikut dan identifikasi:
    
    1. Design patterns yang sudah diimplementasikan (bahkan kalau tidak disengaja)
    2. Antipatterns yang perlu diaddress
    3. Coupling yang berlebihan antara komponen
    4. Violation dari SOLID principles

    [paste kode]


    Trap yang Harus Dihindari

    Jangan Minta AI untuk “Rewrite Everything”

    Ini godaan terbesar. Kamu paste seluruh file dan bilang “tolong rewrite ini jadi clean code.”

    Masalahnya: AI tidak tahu business rules tersembunyi. Dia tidak tahu bahwa if (status === 3) itu sebenarnya adalah “kondisi khusus untuk merchant yang join sebelum tahun 2023.” Kode yang dihasilkan mungkin lebih bersih tapi kehilangan logic penting.

    Selalu refactor satu bagian kecil pada satu waktu, dan verify setelah setiap langkah.

    Jangan Abaikan Test yang Fail

    Kalau characterization test yang kamu tulis fail setelah refactoring, itu signal bahwa kamu mengubah behavior — baik sengaja maupun tidak. Investigasi dulu sebelum lanjut.

    Jangan Percaya AI 100% untuk Security-Critical Code

    Autentikasi, otorisasi, enkripsi, validasi input — review ini secara manual. AI mungkin menghasilkan kode yang terlihat bersih tapi punya subtle security issue.


    Toolkit Refactoring dengan AI

    Untuk Code Understanding:

    • Claude atau GPT-4 — explain dan analyze kode
    • GitHub Copilot Chat — inline explanation di editor

    Untuk Automated Refactoring:

    • Cursor / Windsurf — multi-file refactoring dengan konteks
    • JetBrains IDE — built-in refactoring tools yang kuat (rename, extract, inline)
    • VS Code refactoring tools — lebih basic tapi cukup untuk banyak kasus

    Untuk Testing:

    • Jest / Vitest — unit testing untuk JavaScript/TypeScript
    • Stryker — mutation testing untuk verify test quality

    Untuk Code Analysis:

    • SonarQube — static analysis untuk detect code smells
    • ESLint/TSLint dengan rule sets yang comprehensive

    Kasus Nyata: Refactoring God Function

    God function adalah function yang melakukan terlalu banyak hal — bisa ratusan bahkan ribuan baris. Ini salah satu yang paling umum di legacy code.

    Pendekatan step by step:

    1. Minta AI jelaskan apa yang function ini lakukan
    2. Identifikasi “natural sections” di dalam function
    3. Extract setiap section ke function terpisah dengan nama yang descriptive
    4. Test bahwa behavior sama
    5. Baru, kalau perlu, refactor lebih dalam di masing-masing function yang sudah di-extract

    Perlu diingat: tujuan awal bukan membuat kode sempurna — tapi membuat kode yang cukup dapat dipahami untuk bisa dimodifikasi dengan aman.


    Kapan Rewrite vs Refactor?

    Pertanyaan yang tidak ada jawaban universal:

    Pilih refactor ketika:

    • Sistem masih jalan dan ada user yang bergantung padanya
    • Business logic tersembunyi di kode, susah untuk didokumentasikan ulang dari awal
    • Risk of rewrite lebih tinggi dari benefit
    • Tim tidak punya waktu untuk rewrite total

    Pertimbangkan rewrite ketika:

    • Teknologi yang digunakan sudah tidak supported
    • Biaya maintenance lebih tinggi dari biaya rewrite
    • Kode sudah terlalu korup untuk diperbaiki secara incremental
    • Ada clear spec yang bisa jadi foundation untuk versi baru

    Rewrite total hampir selalu lebih susah dari yang diperkirakan. Mulai dari refactor, dan escalate ke rewrite hanya kalau refactor benar-benar tidak feasible.


    Kesimpulan

    Legacy code bukan musuh — ini aset yang perlu dirawat. AI sangat membantu untuk mempercepat pemahaman dan menemukan pola, tapi judgment dan kehati-hatian tetap di tangan kamu.

    Pendekatan yang benar: pelan, terstruktur, selalu ada test, dan ubah satu hal kecil pada satu waktu. Hasilnya mungkin tidak secepat yang diinginkan, tapi jauh lebih aman daripada refactoring yang tergesa-gesa.


    Punya codebase lama yang perlu dimodernisasi tapi tidak tahu harus mulai dari mana? Atau butuh bantuan merencanakan strategi refactoring yang aman? Yuk ngobrol — hubungi mafadev dan kita tackle bareng.

  • Buat Aplikasi AI Sendiri: Dari Nol sampai Deploy

    Buat Aplikasi AI Sendiri: Dari Nol sampai Deploy

    “Pengen membuat aplikasi AI tapi bingung mulai dari mana.”

    Ini yang paling sering saya dengar dari developer yang ingin masuk ke dunia AI. Banyak yang terjebak di fase research: baca terlalu banyak artikel, nonton terlalu banyak tutorial, tapi tidak ada yang dibangun.

    Artikel ini berbeda. Kita akan benar-benar build aplikasi AI sederhana tapi fungsional, dari nol sampai deploy. Bukan teori — ini praktek.


    Aplikasi yang Akan Kita Buat

    AI Document Q&A — sebuah aplikasi web di mana user bisa upload dokumen (PDF atau teks) dan bertanya tentang isinya. Sederhana tapi ini adalah foundation dari banyak use case enterprise nyata.

    Stack yang digunakan:

    • Backend: Node.js dengan Hono (lightweight, fast)
    • Frontend: HTML + vanilla JS (sesimpel mungkin agar fokus ke AI logic)
    • AI: Anthropic Claude API
    • Vector Database: Upstash Vector (free tier)
    • Deploy: Railway atau Fly.io

    Konsep yang Perlu Dipahami Dulu

    Sebelum coding, dua konsep penting yang perlu kamu mengerti:

    RAG (Retrieval-Augmented Generation)

    Masalah dengan langsung kirim dokumen ke LLM: dokumen besar tidak muat dalam context window, dan mahal kalau harus kirim seluruh dokumen setiap pertanyaan.

    Solusinya: RAG. Alurnya:

    1. Dokumen dipotong jadi chunk-chunk kecil
    2. Setiap chunk dikonversi jadi embedding (representasi numerik)
    3. Embedding disimpan di vector database
    4. Ketika ada pertanyaan, pertanyaan juga dikonversi jadi embedding
    5. Cari chunk yang paling relevan (nearest neighbor search)
    6. Kirim chunk relevan + pertanyaan ke LLM

    Embeddings

    Embedding adalah cara mengkonversi teks ke vektor angka di mana teks yang “maknanya mirip” akan punya vektor yang dekat satu sama lain. Model embedding yang populer: text-embedding-3-small dari OpenAI, atau embedding dari Voyage AI.


    Langkah 1: Setup Project

    mkdir ai-document-qa
    

    cd ai-document-qa

    npm init -y

    npm install hono @anthropic-ai/sdk @upstash/vector pdf-parse dotenv

    npm install -D typescript @types/node tsx

    Buat file .env:

    ANTHROPIC_API_KEY=sk-ant-xxx
    

    UPSTASH_VECTOR_REST_URL=https://xxx.upstash.io

    UPSTASH_VECTOR_REST_TOKEN=xxx


    Langkah 2: Setup Vector Database

    Daftar di upstash.com, buat Vector database baru dengan dimension 1536 (sesuai dengan model embedding yang akan kita pakai).


    Langkah 3: Document Processing

    Buat file src/document.ts:

    import Anthropic from '@anthropic-ai/sdk';
    

    import { Index } from '@upstash/vector';

    import pdfParse from 'pdf-parse';

    const anthropic = new Anthropic();

    const vectorIndex = new Index();

    // Potong teks jadi chunk dengan overlap

    function chunkText(text: string, chunkSize = 500, overlap = 50): string[] {

    const words = text.split(' ');

    const chunks: string[] = [];

    for (let i = 0; i < words.length; i += chunkSize - overlap) {

    const chunk = words.slice(i, i + chunkSize).join(' ');

    if (chunk.trim()) chunks.push(chunk);

    }

    return chunks;

    }

    // Generate embedding menggunakan Voyage AI via Anthropic

    async function generateEmbedding(text: string): Promise<number[]> {

    // Gunakan OpenAI embedding API atau Voyage AI

    // Untuk simplicity, kita gunakan mock 1536-dimension vector

    // Di production, integrasikan dengan embedding model yang proper

    const response = await fetch('https://api.voyageai.com/v1/embeddings', {

    method: 'POST',

    headers: {

    'Authorization': Bearer ${process.env.VOYAGE_API_KEY},

    'Content-Type': 'application/json'

    },

    body: JSON.stringify({

    input: text,

    model: 'voyage-3'

    })

    });

    const data = await response.json() as any;

    return data.data[0].embedding;

    }

    // Process dokumen: extract teks, chunk, embed, simpan

    export async function processDocument(

    buffer: Buffer,

    filename: string,

    mimeType: string

    ): Promise<{ chunks: number }> {

    let text = '';

    if (mimeType === 'application/pdf') {

    const pdfData = await pdfParse(buffer);

    text = pdfData.text;

    } else {

    text = buffer.toString('utf-8');

    }

    const chunks = chunkText(text);

    console.log(Processing ${chunks.length} chunks from ${filename});

    // Generate embeddings dan simpan ke vector database

    const vectors = await Promise.all(

    chunks.map(async (chunk, i) => {

    const embedding = await generateEmbedding(chunk);

    return {

    id: ${filename}-${i},

    vector: embedding,

    metadata: { text: chunk, filename, chunkIndex: i }

    };

    })

    );

    await vectorIndex.upsert(vectors);

    return { chunks: chunks.length };

    }

    // Cari chunk yang relevan dengan pertanyaan

    export async function searchRelevantChunks(

    query: string,

    topK = 5

    ): Promise<string[]> {

    const queryEmbedding = await generateEmbedding(query);

    const results = await vectorIndex.query({

    vector: queryEmbedding,

    topK,

    includeMetadata: true

    });

    return results

    .filter(r => r.metadata)

    .map(r => (r.metadata as any).text);

    }


    Langkah 4: Chat dengan Dokumen

    Buat file src/chat.ts:

    import Anthropic from '@anthropic-ai/sdk';
    

    import { searchRelevantChunks } from './document';

    const anthropic = new Anthropic();

    export async function askDocument(question: string): Promise<string> {

    // Ambil chunk yang relevan

    const relevantChunks = await searchRelevantChunks(question);

    if (relevantChunks.length === 0) {

    return 'Saya tidak menemukan informasi yang relevan dalam dokumen yang diupload.';

    }

    const context = relevantChunks.join('\n\n---\n\n');

    // Kirim ke Claude dengan konteks yang relevan

    const response = await anthropic.messages.create({

    model: 'claude-sonnet-4-5',

    max_tokens: 1024,

    messages: [

    {

    role: 'user',

    content: Kamu adalah asisten yang membantu menjawab pertanyaan berdasarkan dokumen yang diberikan.

    Berikut adalah bagian-bagian dokumen yang relevan dengan pertanyaan:

    ${context}

    Berdasarkan informasi di atas, jawab pertanyaan berikut:

    ${question}

    Kalau jawabannya tidak ada dalam dokumen, katakan dengan jelas bahwa informasi tersebut tidak ada dalam dokumen.

    }

    ]

    });

    return response.content[0].type === 'text'

    ? response.content[0].text

    : 'Tidak dapat menghasilkan respons.';

    }


    Langkah 5: API Server

    Buat file src/server.ts:

    import { Hono } from 'hono';
    

    import { serve } from '@hono/node-server';

    import { processDocument } from './document';

    import { askDocument } from './chat';

    const app = new Hono();

    // Upload dokumen

    app.post('/upload', async (c) => {

    try {

    const formData = await c.req.formData();

    const file = formData.get('file') as File;

    if (!file) {

    return c.json({ error: 'No file provided' }, 400);

    }

    const buffer = Buffer.from(await file.arrayBuffer());

    const result = await processDocument(buffer, file.name, file.type);

    return c.json({

    success: true,

    message: Dokumen diproses: ${result.chunks} chunks

    });

    } catch (error) {

    return c.json({ error: 'Gagal memproses dokumen' }, 500);

    }

    });

    // Tanya dokumen

    app.post('/ask', async (c) => {

    try {

    const { question } = await c.req.json();

    if (!question) {

    return c.json({ error: 'Question is required' }, 400);

    }

    const answer = await askDocument(question);

    return c.json({ answer });

    } catch (error) {

    return c.json({ error: 'Gagal mendapatkan jawaban' }, 500);

    }

    });

    // Serve static files untuk frontend

    app.get('/', (c) => {

    return c.html(

    <!DOCTYPE html>

    <html>

    <head>

    <title>AI Document Q&A</title>

    <style>

    body { font-family: sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; }

    textarea { width: 100%; height: 100px; margin: 10px 0; }

    button { background: #0070f3; color: white; border: none; padding: 10px 20px; cursor: pointer; border-radius: 5px; }

    #answer { margin-top: 20px; padding: 15px; background: #f5f5f5; border-radius: 5px; }

    </style>

    </head>

    <body>

    <h1>AI Document Q&A</h1>

    <h2>1. Upload Dokumen</h2>

    <input type="file" id="fileInput" accept=".pdf,.txt">

    <button onclick="uploadFile()">Upload</button>

    <p id="uploadStatus"></p>

    <h2>2. Tanya tentang Dokumen</h2>

    <textarea id="question" placeholder="Tulis pertanyaan kamu..."></textarea>

    <button onclick="askQuestion()">Tanya</button>

    <div id="answer"></div>

    <script>

    async function uploadFile() {

    const file = document.getElementById('fileInput').files[0];

    if (!file) return alert('Pilih file dulu');

    const formData = new FormData();

    formData.append('file', file);

    const res = await fetch('/upload', { method: 'POST', body: formData });

    const data = await res.json();

    document.getElementById('uploadStatus').textContent = data.message || data.error;

    }

    async function askQuestion() {

    const question = document.getElementById('question').value;

    if (!question) return alert('Tulis pertanyaan dulu');

    document.getElementById('answer').textContent = 'Mencari jawaban...';

    const res = await fetch('/ask', {

    method: 'POST',

    headers: { 'Content-Type': 'application/json' },

    body: JSON.stringify({ question })

    });

    const data = await res.json();

    document.getElementById('answer').textContent = data.answer || data.error;

    }

    </script>

    </body>

    </html>

    );

    });

    serve({ fetch: app.fetch, port: 3000 });

    console.log('Server running at http://localhost:3000');


    Langkah 6: Deploy

    Deploy ke Railway (paling mudah):

    # Install Railway CLI
    

    npm install -g @railway/cli

    Login dan deploy

    railway login

    railway init

    railway up

    Railway akan otomatis detect Node.js project dan deploy. Set environment variables melalui Railway dashboard.

    Atau deploy ke Fly.io:

    # Install Fly CLI
    

    curl -L https://fly.io/install.sh | sh

    Deploy

    fly launch

    fly secrets set ANTHROPIC_API_KEY=xxx

    fly secrets set UPSTASH_VECTOR_REST_URL=xxx

    fly secrets set UPSTASH_VECTOR_REST_TOKEN=xxx

    fly deploy


    Apa Selanjutnya?

    Ini adalah foundation. Dari sini kamu bisa extend ke:

    • Multi-document support — track dokumen per user dengan metadata filtering
    • Conversation history — chat yang ingat context percakapan sebelumnya
    • Streaming responses — jawaban muncul per token, bukan nunggu selesai semua
    • Authentication — user management dengan Supabase Auth
    • Document management — list, delete, organize dokumen yang sudah diupload

    Kesimpulan

    Membangun aplikasi AI tidak harus menunggu sampai kamu “siap” atau sampai kamu mengerti semuanya. Foundation dari semua aplikasi AI berbasis dokumen adalah sama: chunk, embed, retrieve, generate.

    Mulai dari yang sederhana, deploy ke production (walaupun belum sempurna), lalu iterate berdasarkan feedback nyata.


    Punya ide aplikasi AI yang mau dibangun tapi bingung bagaimana arsitekturnya? Atau butuh bantuan dari proof of concept sampai production-ready? Yuk ngobrol — hubungi mafadev dan kita wujudkan bareng.

  • Cara Generate Unit Test dengan AI (dan Kapan Jangan Percaya Hasilnya)

    Cara Generate Unit Test dengan AI (dan Kapan Jangan Percaya Hasilnya)

    Ini skenario yang pernah kamu alami (atau akan kamu alami): deadline besok, fitur baru sudah jalan, tapi test coverage-nya masih merah. Kamu buka AI assistant, paste kodenya, bilang “tolong buatkan unit test,” dan dalam 30 detik… ratusan baris test muncul. Coverage langsung hijau.

    Masalah selesai? Belum tentu.

    Di artikel ini kita bahas cara generate unit test dengan AI secara benar — termasuk kapan hasilnya bisa dipercaya, dan kapan kamu harus waspada.


    Kenapa AI Bagus untuk Generate Test?

    Sebelum ke bagian kritisnya, acknowledge dulu: AI memang genuinely helpful untuk testing. Berikut alasannya:

    1. Eliminasi Kebosanan Menulis Boilerplate

    Unit test itu repetitif. Setup mock, membuat assertion, cleanup — polanya sama terus. AI sangat baik untuk pekerjaan yang punya pola jelas. Kamu bisa describe apa yang mau ditest, AI yang urus boilerplate-nya.

    2. Coverage Kasus yang Terlewat

    Sering kali kita menulis test untuk happy path tapi lupa edge cases. AI bisa suggest: “Bagaimana kalau input-nya null? Kalau string kosong? Kalau number negatif?” — hal-hal yang kadang luput dari perhatian kita.

    3. Kecepatan Iterasi

    Untuk fungsi yang straightforward, AI bisa generate test dalam detik. Kamu bisa fokus pikiran ke logic yang lebih complex.


    Cara Generate Unit Test dengan AI: Step by Step

    Langkah 1: Siapkan Konteks yang Cukup

    Jangan cuma paste fungsinya saja. Berikan AI konteks lengkap:

    Ini adalah fungsi calculateShippingCost di file shipping.service.ts.
    

    Fungsi ini menerima weight (gram), destination (string kode kota),

    dan isMember (boolean).

    Aturan bisnis:

    • Berat < 500g: flat Rp 15.000
    • Berat 500g–2kg: Rp 20.000 + Rp 5.000 per 500g
    • Berat > 2kg: Rp 35.000 + Rp 4.000 per 500g
    • Member dapat diskon 10%
    • Pengiriman ke luar Jawa: tambah Rp 10.000

    Tolong buatkan unit test yang komprehensif dengan Jest.

    Semakin jelas konteks bisnis yang kamu berikan, semakin relevan test yang dihasilkan.

    Langkah 2: Minta Test untuk Kategori Spesifik

    Daripada minta “unit test” generik, minta kategori:

    • Happy path — input normal, output expected
    • Edge cases — batas-batas nilai (0, nilai maximum, nilai tepat di threshold)
    • Error cases — input invalid, null, undefined
    • Business rule tests — setiap aturan bisnis harus ada test-nya sendiri

    Langkah 3: Review Setiap Test Satu per Satu

    Ini bagian yang sering di-skip, dan ini bagian terpenting.


    Tanda-tanda Test AI yang Tidak Bisa Dipercaya

    1. Test yang Selalu Pass Apapun yang Terjadi

    // Test yang tidak berguna
    

    it('should calculate shipping', () => {

    const result = calculateShippingCost(1000, 'JKT', false);

    expect(result).toBeDefined(); // ini tidak test apapun yang bermakna

    });

    AI kadang generate test yang terlalu broad — hanya check bahwa fungsi tidak throw error, bukan check bahwa hasilnya benar.

    2. Test yang Assertion-nya Salah

    AI tidak selalu paham business logic kamu dengan sempurna. Contoh:

    // Kalau AI salah hitung thresholdnya
    

    it('should apply member discount', () => {

    const result = calculateShippingCost(1000, 'JKT', true);

    expect(result).toBe(18000); // AI mungkin hitung salah

    });

    Kamu harus verifikasi setiap expected value secara manual. Hitung sendiri dulu, baru compare dengan assertion AI.

    3. Mock yang Terlalu Agresif

    // Mock yang terlalu banyak = test yang tidak realistis
    

    jest.mock('./database');

    jest.mock('./logger');

    jest.mock('./config');

    jest.mock('./validator');

    // ...sampai test tidak lagi mencerminkan behavior nyata

    Kalau semua dependency di-mock, kamu mungkin test unit yang sangat isolated tapi tidak punya nilai untuk mendeteksi bug di integrasi komponen.

    4. Duplicate Test dengan Nama Berbeda

    AI kadang generate test yang pada dasarnya sama tapi dengan nama yang berbeda. Ini inflates coverage tanpa menambah nilai.


    Strategi yang Benar: AI sebagai Asisten, Kamu sebagai Reviewer

    Workflow yang Disarankan:

    1. Tulis test kritis secara manual dulu

    Logic bisnis paling penting? Tulis test-nya sendiri. Ini pastikan kamu paham apa yang di-test dan assertion-nya benar.

    2. Gunakan AI untuk melengkapi edge cases

    Setelah test utama ada, tanya AI: “Kasus apa lagi yang perlu saya test?” Biarkan AI suggest, kamu yang decide mana yang relevan.

    3. Review setiap assertion secara manual

    Untuk setiap test yang dihasilkan AI, tanyakan:

    • Apakah expected value ini benar? (hitung manual)
    • Apakah test ini bisa fail jika ada bug nyata?
    • Apakah test ini mencerminkan use case yang realistis?

    4. Jalankan mutation testing

    Tools seperti Stryker (JavaScript) atau PITest (Java) akan sengaja “mutasi” kode kamu dan check apakah test-mu gagal. Ini cara terbaik untuk verify apakah test AI kamu bermakna atau kosong.


    Prompt Template yang Efektif

    Berikut template prompt yang terbukti menghasilkan test berkualitas lebih baik:

    Saya punya fungsi berikut:
    

    [paste kode]

    Konteks bisnis:

    [jelaskan aturan bisnis, constraint, edge cases yang kamu tahu]

    Teknologi yang digunakan: [Jest/PyTest/JUnit/dll]

    Tolong buatkan unit test dengan kriteria:

    1. Setiap aturan bisnis harus ada minimal 1 test
    2. Test edge cases: nilai 0, null, undefined, nilai di batas threshold
    3. Test error handling untuk input invalid
    4. Berikan komentar singkat untuk setiap test yang menjelaskan KENAPA test itu penting
    5. Jangan gunakan mock kecuali untuk external dependencies (database, API)
  • Tambahan komentar “kenapa test itu penting” itu trik kecil tapi powerful — AI akan lebih focused menghasilkan test yang meaningful.


    Kapan JANGAN Bergantung pada AI untuk Test?

    • Payment dan financial logic — hitung manual, test manual, cek ulang manual
    • Security-related code — autentikasi, otorisasi, enkripsi
    • Data migration — kalau salah, data corrupt
    • Kode yang kamu sendiri belum sepenuhnya paham — jangan minta AI test sesuatu yang kamu tidak mengerti

    Untuk kasus-kasus ini: tulis test kamu sendiri, peer review dengan developer lain, dan treat test sebagai dokumentasi hidup dari behavior yang harusnya terjadi.


    Kesimpulan

    AI adalah alat luar biasa untuk generate unit test — asalkan kamu tidak menelan hasilnya mentah-mentah. Coverage yang tinggi tidak sama dengan test yang bermakna. Test yang bermakna adalah test yang akan fail ketika ada bug nyata, bukan test yang selalu hijau mau kode-nya benar atau salah.

    Gunakan AI untuk kecepatan dan saran edge cases, tapi tetap kamu yang memegang kendali atas kualitas dan kebenaran setiap assertion.


    Butuh review test suite kamu atau mau diskusi strategi testing yang tepat untuk project spesifik? Yuk ngobrol — hubungi mafadev dan kita cari solusi bareng.

  • Cara Buat Dokumentasi Otomatis dengan AI: Hemat Berjam-jam

    Cara Buat Dokumentasi Otomatis dengan AI: Hemat Berjam-jam

    Cara Buat Dokumentasi Otomatis dengan AI: Hemat Berjam-jam

    “Nanti didokumentasikan” — kalimat yang paling sering jadi kebohongan terbesar di dunia software development.

    Bukan karena developer malas. Tapi karena dokumentasi itu membosankan, memakan waktu, dan terasa seperti pekerjaan yang tidak langsung produce value. Kalau pilih antara buat fitur baru atau menulis docs, hampir semua orang pilih fitur.

    Masalahnya, enam bulan ke depan kamu (atau tim kamu) yang akan menderita membaca kode tanpa konteks. Dan waktu itu, “nanti” sudah jadi “tidak pernah”.

    AI mengubah ini. Bukan dengan menghilangkan kebutuhan dokumentasi, tapi dengan menghilangkan friction-nya.


    Tiga Jenis Dokumentasi yang Bisa Diotomasi

    Sebelum masuk ke workflow, penting untuk tahu mana yang bisa diotomasi dan mana yang tidak.

    Bisa diotomasi dengan baik:

    • Docstring dan JSDoc untuk fungsi
    • README untuk repository atau modul
    • API documentation dari kode
    • Changelog dari commit messages
    • Inline code comments

    Tetap butuh manusia:

    • “Kenapa” keputusan desain diambil
    • Konteks bisnis dan domain knowledge
    • Tutorial step-by-step yang butuh perspektif pengguna
    • Arsitektur decisions (ADR)

    Ekspektasi yang realistis: AI bisa handle 60-70% pekerjaan dokumentasi. Sisanya tetap butuh kamu. Tapi 60-70% itu cukup untuk secara signifikan mengubah berapa waktu yang kamu habiskan.


    Workflow 1: Docstring Otomatis untuk Fungsi

    Ini yang paling mudah dan langsung menghasilkan value. Untuk setiap fungsi yang kamu tulis atau modifikasi, minta AI generate docstring-nya.

    Di VS Code dengan Copilot / Windsurf / Cursor

    Untuk Python, tulis komentar """ di bawah function signature dan biarkan AI complete:

    def calculate_monthly_payment(
    

    principal: float,

    annual_rate: float,

    months: int

    ) -> float:

    """

    # AI akan complete dari sini

    Untuk JavaScript/TypeScript, tulis /** dan biarkan AI complete JSDoc:

    /**
    

    * AI akan generate JSDoc di sini

    */

    function calculateMonthlyPayment(

    principal: number,

    annualRate: number,

    months: number

    ): number {

    Batch Processing via Prompt

    Kalau punya banyak fungsi yang belum terdokumentasi, paste ke chat AI dan minta batch:

    Tambahkan JSDoc yang comprehensive untuk setiap fungsi di bawah ini.
    

    Sertakan: @param, @returns, @throws (jika relevan), dan contoh usage.

    [paste kode di sini]


    Workflow 2: README Generator

    README yang bagus itu seperti elevator pitch untuk project kamu. Tapi menulis dari nol itu melelahkan.

    Template Prompt untuk README

    Buatkan README.md yang komprehensif untuk project berikut.
    
    

    Stack: [list stack]

    Deskripsi singkat project: [apa yang dilakukan project ini]

    Target pengguna: [siapa yang akan pakai]

    Struktur project:

    [output dari tree -I node_modules -I .git]

    Package.json / requirements.txt:

    [paste konten file]

    README harus mencakup:

    • Deskripsi dan screenshot (placeholder)
    • Prerequisites
    • Cara install dan setup
    • Environment variables yang diperlukan
    • Cara run (development dan production)
    • Struktur folder penting
    • Contributing guide singkat
  • Hasilnya mungkin butuh adjustment, tapi struktur dasarnya sudah ada dan kamu tinggal polish.


    Workflow 3: API Documentation dari Kode

    Untuk REST API, ada tools yang bisa auto-generate dokumentasi dari kode atau dari OpenAPI spec. Tapi bahkan tanpa tools khusus, AI bisa sangat membantu.

    Dari Route Handler ke Dokumentasi

    Ini adalah route handlers Express.js untuk module users.
    

    Generate dokumentasi API dalam format yang readable (bisa markdown atau tabel).

    Sertakan: endpoint, method, request body/params, response format, dan error codes.

    [paste route handlers]

    Kombinasi dengan Swagger/OpenAPI

    Kalau kamu pakai framework yang support OpenAPI (FastAPI di Python, NestJS di Node.js), AI bisa membantu:

    1. Generate OpenAPI annotations untuk endpoint yang belum punya
    2. Review dan improve schema yang sudah ada
    3. Generate contoh request/response yang realistic

    Workflow 4: Changelog dari Git History

    Tidak ada yang suka menulis changelog. Tapi changelog yang bagus sangat valuable untuk user dan untuk tracking apa yang berubah.

    Otomasi dengan Git Log

    git log --oneline --since="2 weeks ago" > commits.txt

    Lalu prompt ke AI:

    Ini adalah commit history dari 2 minggu terakhir.
    

    Buatkan CHANGELOG.md entry yang proper untuk release v1.x.x.

    Kategorikan perubahan dalam: Features, Bug Fixes, Breaking Changes, Improvements.

    Tulis dalam bahasa yang user-friendly, bukan technical jargon dari commit message.

    [paste commit history]


    Workflow 5: Architecture Decision Records (ADR)

    ADR adalah dokumentasi tentang “kenapa” — kenapa kita pilih teknologi X, kenapa kita desain sistem seperti ini. Ini yang sulit diotomasi, tapi AI bisa membantu menstrukturkan pemikiranmu.

    Template ADR dengan AI

    Saya baru saja membuat keputusan teknis berikut:
    
    
    

    Buatkan ADR (Architecture Decision Record) yang proper menggunakan template MADR atau format Michael Nygard.

    AI akan menstrukturkan pemikiranmu ke format ADR yang terstandarisasi.


    Tools yang Bisa Dikombinasikan

    Untuk JavaScript/TypeScript Projects

    Untuk Python Projects

    Untuk API


    Setup CI/CD untuk Dokumentasi Otomatis

    Kalau mau lebih serius, setup pipeline yang otomatis generate docs ketika ada perubahan kode:

    # .github/workflows/docs.yml
    

    name: Generate Documentation

    on:

    push:

    branches: [main]

    jobs:

    docs:

    runs-on: ubuntu-latest

    steps:

    - uses: actions/checkout@v3

    - name: Install dependencies

    run: npm install

    - name: Generate TypeDoc

    run: npx typedoc --out docs src/

    - name: Deploy to GitHub Pages

    uses: peaceiris/actions-gh-pages@v3

    with:

    github_token: ${{ secrets.GITHUB_TOKEN }}

    publish_dir: ./docs

    Hasilnya: setiap push ke main otomatis update dokumentasi yang dipublish.


    Praktik Terbaik: Dokumentasi Tetap Human-Reviewed

    Meskipun AI bisa generate dokumentasi dengan cepat, ada prinsip yang perlu dijaga:

    1. Selalu review sebelum commit — AI bisa salah mendeskripsikan behavior fungsi
    2. Tambahkan “why” secara manual — AI tidak tahu alasan bisnis di balik keputusan
    3. Jaga akurasi lebih dari completeness — dokumentasi yang salah lebih berbahaya dari tidak ada dokumentasi
    4. Update secara reguler — dokumentasi outdated adalah technical debt

    Penutup

    Dokumentasi yang bagus itu bukan kemewahan — itu investasi yang membayar dirinya sendiri ketika tim berkembang, ketika kamu onboarding orang baru, atau ketika kamu sendiri kembali ke kode yang kamu tulis setahun lalu.

    Dengan AI, excusenya sudah tidak ada lagi. Setup workflow yang saya bagikan di atas bisa diimplementasikan dalam beberapa jam, dan efeknya akan terasa di setiap project ke depannya.

    Mau bantuan setup documentation workflow untuk project atau tim kamu? Atau perlu diskusi soal tools yang paling pas untuk stack yang sedang kamu pakai? Hubungi mafadev — kita atur bareng.

  • Prompt Engineering untuk Developer: Beda dengan Prompt Biasa

    Prompt Engineering untuk Developer: Beda dengan Prompt Biasa

    Prompt Engineering untuk Developer: Beda dengan Prompt Biasa

    Ada mitos yang perlu diluruskan: prompt engineering itu bukan tentang “trik sulap” untuk manipulasi AI. Dan untuk developer, ini bukan hal yang sama dengan cara orang awam pakai ChatGPT untuk menulis email.

    Sebagai developer yang pakai AI setiap hari — untuk debug, code review, architecture discussion, sampai generate boilerplate — saya belajar bahwa cara kamu berkomunikasi dengan LLM sangat menentukan kualitas output-nya. Bukan cuma “prompt yang panjang lebih baik”, tapi ada pola yang spesifik untuk kebutuhan teknis.

    Mari kita bahas yang benar-benar berguna — bukan teori akademis.


    Kenapa Prompt Developer Berbeda?

    Ketika orang awam pakai AI, mereka biasanya butuh output yang “cukup baik” — artikel, email, ringkasan. Ada ruang toleransi.

    Ketika developer pakai AI untuk coding, toleransinya jauh lebih ketat:

    • Kode harus bisa dijalankan — bukan hanya kelihatan benar
    • Harus kompatibel dengan stack dan versi yang sedang dipakai
    • Harus konsisten dengan konvensi codebase yang sudah ada
    • Salah sedikit di logic bisa buat bug yang susah dilacak

    Ini yang membuat prompt engineering untuk developer butuh pendekatan yang lebih terstruktur.


    Teknik 1: Berikan Konteks Stack yang Spesifik

    Prompt buruk:

    > “Buatkan fungsi untuk handle authentication”

    Prompt lebih baik:

    > “Buatkan fungsi authentication menggunakan Express.js v4, JWT dengan library jsonwebtoken v9, dan TypeScript. Middleware harus check Authorization header format ‘Bearer token’, verify token, dan attach decoded user ke req.user.”

    Perbedaannya bukan cuma panjang — tapi spesifisitas konteks. Dengan prompt kedua, AI tahu:

    • Framework yang dipakai (Express.js v4)
    • Library spesifik (jsonwebtoken v9)
    • Bahasa (TypeScript, bukan JavaScript)
    • Format yang diharapkan (Bearer token)
    • Output yang diinginkan (attach ke req.user)

    Hasilnya? Kode yang bisa langsung dipakai, bukan yang perlu banyak modifikasi.


    Teknik 2: Sertakan Kode yang Ada sebagai Referensi

    Ini yang paling sering dilupakan: tunjukkan contoh kode yang sudah ada di codebase kamu.

    Misalnya kamu mau generate fungsi baru yang konsisten dengan style tim:

    Ini contoh fungsi yang sudah ada di codebase kami:

    typescript

    async function getUserById(id: string): Promise {

    try {

    const user = await db.query.users.findFirst({

    where: eq(users.id, id)

    });

    return user ?? null;

    } catch (error) {

    logger.error(‘Failed to get user’, { id, error });

    throw new DatabaseError(‘Failed to fetch user’);

    }

    }

    Sekarang buatkan fungsi serupa untuk getPostsByUserId yang mengambil semua post milik seorang user, dengan pagination (page, limit).

    Dengan memberikan referensi kode nyata, AI akan mengikuti:

    • Library yang dipakai (Drizzle ORM dalam contoh di atas)
    • Pattern error handling
    • Naming convention
    • Return type pattern

    Teknik 3: Definisikan Output Format dengan Jelas

    Untuk debugging, bedakan antara minta penjelasan dan minta solusi:

    Minta penjelasan:

    > “Jelaskan kenapa kode ini throw ‘TypeError: Cannot read properties of undefined’ dan di baris mana masalahnya.”

    Minta solusi langsung:

    > “Fix bug ini. Berikan hanya kode yang diperbaiki tanpa penjelasan panjang.”

    Minta keduanya dengan struktur:

    > “Untuk kode ini: [kode]. Format jawaban: 1) Root cause dalam 1-2 kalimat. 2) Kode yang sudah difix. 3) Cara mencegah bug serupa.”

    Ini tampak kecil tapi penting. AI akan menyesuaikan output sesuai format yang diminta.


    Teknik 4: Role Prompting yang Relevan

    Role prompting untuk developer beda dengan “jadilah ahli”. Yang efektif adalah:

    > “Kamu senior backend developer dengan spesialisasi di database optimization. Review query SQL ini dan identifikasi bottleneck performance. Anggap table punya 10 juta baris.”

    Kuncinya: berikan konteks role yang spesifik termasuk constraints (table size, environment, etc). Ini membantu AI memberikan saran yang lebih realistic.


    Teknik 5: Chain of Thought untuk Problem Kompleks

    Untuk masalah yang kompleks — misalnya desain arsitektur atau debug issue yang tricky — minta AI untuk berpikir step by step sebelum memberikan jawaban:

    > “Saya mau implementasi rate limiting di API Express yang bisa scale horizontal (multiple instances). Sebelum berikan solusinya, pikirkan dulu: apa saja trade-off antara in-memory vs Redis-based rate limiting, dan kapan masing-masing approach lebih cocok?”

    Dengan minta AI “berpikir dulu”, output-nya cenderung lebih thoughtful dan mempertimbangkan edge cases.


    Teknik 6: Negative Prompting — Bilang Apa yang Tidak Kamu Mau

    Developer sering lupa ini. Explicit constraints bisa drastis meningkatkan relevansi output:

    > “Buatkan implementasi caching untuk API calls ini. Jangan gunakan library eksternal — hanya pakai built-in Node.js. Jangan implementasi invalidation dulu, fokus ke basic cache dengan TTL. Jangan ubah interface fungsi yang ada.”

    Tanpa negative prompting, AI sering menambahkan hal-hal yang tidak kamu butuhkan atau mengubah hal yang tidak boleh diubah.


    Teknik 7: Iterasi, Bukan Satu Prompt Ajaib

    Ini mindset yang paling penting: tidak ada single prompt yang sempurna.

    Workflow yang saya pakai:

    1. Prompt awal — broad, minta solusi umum
    2. Refinement — “Bagus, tapi ubah bagian X supaya Y”
    3. Validation — “Apakah ini handle edge case Z?”
    4. Polish — “Sekarang tambahkan error handling dan TypeScript types”

    Ini lebih efisien daripada mencoba buat satu prompt super-panjang yang cover semua hal sekaligus.


    Anti-Pattern yang Harus Dihindari

    Prompt yang terlalu vague:

    • “Buatkan API yang bagus”
    • “Bantu saya dengan database ini”

    Copas error tanpa konteks:

    • Hanya paste stack trace tanpa kode yang relevan

    Minta AI “tebak” stack kamu:

    • Tidak menyebutkan framework, versi, atau library

    Percaya output tanpa validasi:

    • AI bisa confident tapi salah. Selalu test kode yang dihasilkan.

    Template Prompt untuk Kebutuhan Umum

    Untuk debug:

    Environment: [Stack/framework/versi]
    

    Problem: [Deskripsi singkat]

    Error message: [Copy paste pesan error]

    Kode yang relevan: [kode]

    Yang sudah dicoba: [apa yang sudah kamu coba]

    Untuk generate feature baru:

    Stack: [list stack]
    

    Context codebase: [snippet kode yang relevan]

    Feature yang dibutuhkan: [deskripsi detail]

    Constraints: [hal-hal yang tidak boleh berubah]

    Untuk code review:

    Review kode ini untuk: [bug / performance / security / readability]
    

    Context: fungsi ini dipanggil oleh [konteks pemanggil]

    Kode: [kode]


    Penutup

    Prompt engineering untuk developer bukan skill tersendiri yang perlu dipelajari berbulan-bulan. Ini tentang kebiasaan memberikan konteks yang cukup, mendefinisikan output yang diinginkan, dan iterasi secara sistematis.

    Mulai dari teknik yang paling mudah: selalu sebutkan stack secara spesifik, dan sertakan kode referensi yang ada. Dua hal ini saja sudah mengubah kualitas output AI secara signifikan.

    Mau diskusi lebih dalam soal workflow AI untuk development tim atau project kamu? Atau butuh bantuan membangun sistem yang memanfaatkan LLM secara optimal? Hubungi mafadev — kita ngobrol dan cari solusinya bareng.

  • Cara Pakai AI untuk Debug Kode Lebih Cepat

    Cara Pakai AI untuk Debug Kode Lebih Cepat

    Debugging adalah aktivitas yang ironisnya paling banyak memakan waktu seorang developer, tapi paling sedikit dibahas secara serius. Kebanyakan tutorial fokus ke “cara menulis kode yang baru” dan skip ke bagian “oke, kalau ada error bagaimana?”

    Di era AI, debugging punya dimensi baru. Bukan karena AI bisa solve semua bug — karena tidak bisa. Tapi AI bisa jadi sparring partner yang sangat efektif kalau kamu tau cara menggunakannya dengan benar.

    Artikel ini adalah tentang teknik yang konkret dan bisa langsung kamu coba.


    Kenapa Debugging dengan AI Sering Tidak Efektif

    Sebelum bahas teknik yang bagus, saya mau bahas dulu kenapa banyak orang gagal dapat manfaat maksimal dari AI saat debugging.

    Masalah utama: Prompt yang terlalu generik.

    “Kode ini error, tolong fix” adalah prompt yang hampir selalu menghasilkan output yang tidak useful atau bahkan menyesatkan.

    AI butuh konteks. Tanpa konteks yang cukup, AI akan guess — dan guessing-nya bisa sangat confident tapi salah.


    Framework Debugging dengan AI: CERA

    Saya pakai framework sederhana yang saya sebut CERA untuk debugging session dengan AI:

    • Context — apa yang kamu build, stack apa yang dipakai
    • Error — error message lengkap, bukan cuma ringkasan
    • Reproduce — langkah atau kondisi yang membuat error muncul
    • Attempt — apa yang sudah kamu coba

    Kalau prompt kamu mencakup keempat elemen ini, response AI akan jauh lebih tepat sasaran.

    Contoh Prompt yang Buruk vs Bagus

    Buruk:

    > “Kenapa function saya error?”

    Bagus:

    > “Saya building REST API dengan Express.js dan MongoDB. Function getUserById ini melempar error ketika id yang dikirim adalah string yang valid tapi tidak ada di database. Error message: TypeError: Cannot read properties of null (reading 'email'). Saya sudah coba check apakah req.params.id valid dan formatnya benar. Ini kodenya: [kode]. Apa yang salah dan bagaimana fix yang tepat?”

    Perbedaannya bukan hanya panjang prompt — tapi informasi yang relevan yang kamu sertakan.


    Teknik 1: Paste Error Message Lengkap, Bukan Ringkasan

    Ini yang paling sering dilakukan salah. Orang sering ringkas error message karena merasa “panjang dan tidak relevan”.

    Jangan lakukan itu. Stack trace yang panjang justru punya informasi yang sangat berharga — AI bisa pinpoint baris kode mana yang jadi sumber masalah dari stack trace yang lengkap.

    Kalau error message-nya dalam bahasa yang kamu tidak familiar (misal kamu pakai Rust tapi tidak terlalu dalam), AI bisa translate makna error-nya ke dalam bahasa yang lebih mudah dipahami.

    Ini error yang saya dapat:
    
    

    TypeError: Cannot read properties of null (reading 'email')

    at getUserProfile (src/controllers/userController.js:45:28)

    at Layer.handle [as handle_request] (node_modules/express/lib/router/layer.js:95:5)

    at next (node_modules/express/lib/router/route.js:137:13)

    ...

    Kode di line 45:

    const email = user.email; // user ternyata null

    Dengan konteks ini, AI bisa langsung identifikasi bahwa masalahnya adalah kurangnya null check sebelum akses property.


    Teknik 2: Minta AI Jelaskan, Bukan Cuma Fix

    Ini penting banget kalau kamu mau belajar, bukan cuma “kode jalan lagi”.

    Setelah dapat fix dari AI, selalu tanya: “Tolong jelaskan kenapa fix ini benar dan apa yang menyebabkan bug ini.”

    Ini mengubah debugging session dari “tukang servis” menjadi “sesi belajar”. Dan kamu jadi lebih prepared untuk tidak membuat bug yang sama lagi.

    Contoh follow-up prompt:

    > “Okay, fix-nya masuk akal. Tapi bisa kamu jelaskan secara lebih dalam kenapa kondisi null ini bisa terjadi? Apakah ini perilaku normal MongoDB ketika document tidak ditemukan, atau ada sesuatu yang salah di query-nya?”


    Teknik 3: Pakai AI sebagai “Rubber Duck” yang Bisa Balas

    Rubber duck debugging adalah teknik klasik: jelaskan masalahmu ke bebek karet (atau objek apapun), dan sering kali dalam proses menjelaskan, kamu sendiri nemuin jawabannya.

    AI adalah rubber duck versi upgrade — yang bisa balas dan ajukan pertanyaan.

    Cara pakainya:

    1. Jelaskan problemmu ke AI seolah AI adalah teman yang tidak tau konteksnya
    2. Dalam proses mengetik penjelasan, sering kali kamu sudah menemukan bug-nya sebelum AI jawab
    3. Kalau belum ketemu, jawaban AI bisa jadi petunjuk berikutnya

    Ini teknik yang sounds simple tapi sangat efektif, terutama untuk bug yang complex dan tidak obvious.


    Teknik 4: Minta AI Review Asumsi Kamu

    Debugging yang lama sering terjadi karena kita terjebak dalam asumsi yang salah. Kita yakin bahwa bagian A sudah benar, padahal justru di sanalah bug-nya.

    AI bisa bantu break asumsi ini dengan tanya hal yang kita tidak tanya ke diri sendiri.

    Prompt yang berguna:

    > “Saya sudah debug selama 2 jam dan yakin masalahnya ada di layer database query. Tapi tetap tidak ketemu. Berdasarkan deskripsi berikut [deskripsi], asumsi apa yang mungkin salah dari cara saya framing masalahnya?”

    AI mungkin akan suggest: “Pernahkah kamu periksa apakah data yang masuk ke function sudah dalam format yang benar sebelum query dijalankan?” — dan itu bisa jadi eureka moment.


    Teknik 5: Binary Search dengan Bantuan AI

    Untuk bug yang susah di-isolate di codebase yang besar, binary search adalah teknik yang efektif: kurangi scope masalah terus sampai nemuin titik spesifiknya.

    AI bisa bantu di sini dengan cara:

    1. Kamu ceritakan symptom-nya
    2. AI suggest “component mana yang paling mungkin jadi sumber masalah”
    3. Kamu isolate component itu dan test
    4. Laporan hasilnya ke AI
    5. Repeat sampai nemuin bug

    Ini jauh lebih efektif dari review kode baris per baris secara acak.


    Teknik 6: Pakai AI untuk Generate Test Cases

    Satu cara terbaik untuk debug adalah: tulis test yang reproduce bug-nya. Kalau kamu bisa reproduce secara reliable, setengah pekerjaan debugging sudah selesai.

    Tapi menulis test cases itu kadang butuh waktu, terutama untuk edge cases yang tidak obvious.

    Minta AI:

    > “Berdasarkan fungsi ini [kode] dan bug yang terjadi ketika input-nya [kondisi], tolong generate test cases yang akan reproduce bug ini dan juga test cases untuk edge cases yang mungkin tidak ketahuan.”

    AI sangat bagus untuk generate test cases — ini salah satu penggunaannya yang paling underrated.


    Hal yang AI Tidak Bisa Lakukan dalam Debugging

    Biar seimbang, ini batasan AI yang perlu kamu tau:

    AI tidak bisa akses sistem kamu secara langsung. Dia tidak bisa lihat log production, tidak bisa inspect memori runtime, tidak bisa check state database kamu. Semua konteks harus kamu bawa ke AI, bukan sebaliknya.

    AI bisa confident tapi salah. Terutama untuk bug yang melibatkan race condition, timing issue, atau behavior yang sangat environment-specific — AI mungkin suggest solusi yang kedengarannya masuk akal tapi tidak nyentuh root cause-nya. Selalu verify fix-nya sebelum commit.

    AI tidak tau business context kamu. Bug yang berhubungan dengan logic bisnis yang spesifik butuh kamu yang jelaskan “kenapa seharusnya begini, bukan begitu.” AI tidak punya pengetahuan itu kecuali kamu provide.


    Quick Reference: Template Prompt Debugging

    Simpan ini:

    Context: [Saya sedang membangun ___. Stack yang dipakai: ___]
    
    

    Problem: [Deskripsi singkat masalah]

    Error message (lengkap):

    [paste error message dan stack trace lengkap]

    Kode yang relevan:

    [paste kode]

    Yang sudah saya coba:

    • [Attempt 1]
    • [Attempt 2]

    Pertanyaan: [Apa yang ingin kamu tau?]

    Template ini mungkin terasa berlebihan untuk bug kecil. Tapi untuk bug yang membuat kamu stuck lebih dari 15 menit, ini akan menghemat lebih banyak waktu dari yang kamu bayangkan.


    Stuck di bug yang tidak ketemu-ketemu? Atau mau ngobrol soal strategi debugging yang lebih sistematis untuk project kamu? Hubungi mafadev — dua kepala lebih baik dari satu, apalagi kalau salah satunya suka debugging.