tutorial

49 Serialisasi dan Deserialisasi Manual

Serialisasi dan deserialisasi merupakan proses fundamental dalam dunia pengembangan perangkat lunak modern. Keduanya menjadi tulang punggung dalam pertukaran data lintas sistem, penyimpanan objek kompleks ke dalam berkas, hingga komunikasi antara layanan menggunakan protokol tertentu. Akan tetapi, sering kali alat atau pustaka otomatis seperti JSON, Protocol Buffer, atau YAML yang kita gunakan “menyembunyikan” kompleksitas ini. Tapi apa yang terjadi ketika kita harus melakukan serialisasi dan deserialisasi secara manual?

Artikel ini membahas serialisasi dan deserialisasi manual—upaya eksplisit mengubah struktur data ke dalam format tertentu (dan sebaliknya) tanpa bergantung pada pustaka khusus. Kita akan menelusuri alasan mengapa teknik ini penting, tantangan yang muncul, beserta contoh kode di Python dan Java beserta simulasi prosesnya.


Apa itu Serialisasi dan Deserialisasi?

Secara sederhana:

  • Serialisasi adalah proses mengubah objek/struktur data menjadi format yang dapat disimpan atau dikirim (string, byte-stream, dsb).
  • Deserialisasi adalah proses kebalikannya: mengubah representasi data hasil serialisasi menjadi objek/struktur data kembali.

Jika pernah menggunakan:

import json
json.dumps({'name': 'Budi', 'age': 30})

Anda telah memakai serialisasi otomatis.


Mengapa Serialisasi Manual?

  1. Kontrol Penuh: Kadang-kadang format output atau input harus memenuhi standar yang sangat spesifik (misal: format ID yang fixed-length, penamaan field tak konvensional).
  2. Ukuran Data: SERIALIZATION library standar bisa menghasilkan output besar; manual bisa dirancang lebih minimalis.
  3. Kebutuhan Performa: Untuk data bervolume besar dan komunikasi dengan waktu kritis (low-latency), serialisasi manual memungkinkan optimasi tingkat rendah.
  4. Keamanan: Serialisasi otomatis kadang membuka celah injection/deserialization attack.

Serialisasi Manual: Studi Kasus

Mari kita gunakan sebuah contoh sederhana—serialisasi objek pengguna (user) dengan atribut: id: int, username: string, active: bool.

1. Spesifikasi Format Serialisasi

Kita tentukan format khusus:

  • id fixed 4 digit, leading zero (misal 42 => “0042”)
  • username max 8 karakter, di-pad dengan spasi jika kurang (misal “budi” => “budi “)
  • active dengan 1 (True) atau 0 (False)

Contoh hasil serialisasi, untuk user id=7, username=“lina”, active=True:

0007lina    1

2. Kode Serialisasi Manual

a) Python Implementation

class User:
    def __init__(self, id, username, active):
        self.id = id
        self.username = username
        self.active = active

    def serialize(self):
        id_str = str(self.id).zfill(4)
        username_str = self.username.ljust(8)
        active_str = '1' if self.active else '0'
        return f"{id_str}{username_str}{active_str}"

    @staticmethod
    def deserialize(serialized_str):
        id = int(serialized_str[:4])
        username = serialized_str[4:12].rstrip()
        active = serialized_str[12] == '1'
        return User(id, username, active)

# Simulasi proses
u = User(42, "neo", True)
ser = u.serialize()
print('Serialized:', ser)   # Output: "0042neo     1"

u2 = User.deserialize(ser)
print('Deserialized:', (u2.id, u2.username, u2.active))  # Output: (42, 'neo', True)

b) Java Implementation

class User {
    int id;
    String username;
    boolean active;

    User(int id, String username, boolean active) {
        this.id = id;
        this.username = username;
        this.active = active;
    }
    String serialize() {
        return String.format("%04d%-8s%d", id, username, active ? 1 : 0);
    }
    static User deserialize(String str) {
        int id = Integer.parseInt(str.substring(0, 4));
        String username = str.substring(4, 12).trim();
        boolean active = str.charAt(12) == '1';
        return new User(id, username, active);
    }
}

c) Go Implementation

package main

import (
	"fmt"
	"strconv"
	"strings"
)

type User struct {
	ID       int
	Username string
	Active   bool
}

// Serialize mengubah User menjadi string format: 4 digit ID, 8 karakter username (padding), 1 digit active (0/1)
func (u User) Serialize() string {
	activeInt := 0
	if u.Active {
		activeInt = 1
	}
	return fmt.Sprintf("%04d%-8s%d", u.ID, u.Username, activeInt)
}

// Deserialize mengubah string ke User struct
func Deserialize(data string) (User, error) {
	if len(data) < 13 {
		return User{}, fmt.Errorf("data too short")
	}
	id, err := strconv.Atoi(data[0:4])
	if err != nil {
		return User{}, fmt.Errorf("invalid ID: %w", err)
	}
	username := strings.TrimSpace(data[4:12])
	active := data[12] == '1'

	return User{
		ID:       id,
		Username: username,
		Active:   active,
	}, nil
}

func main() {
	u := User{ID: 42, Username: "ihsan", Active: true}
	serialized := u.Serialize()
	fmt.Println("Serialized:", serialized)

	parsed, err := Deserialize(serialized)
	if err != nil {
		panic(err)
	}
	fmt.Printf("Deserialized: %+v\n", parsed)
}

Output:

Serialized: 0042ihsan   1
Deserialized: {ID:42 Username:ihsan Active:true}

Catatan:

  • Username dipastikan selalu panjang 8 karakter, sesuai format Java-nya.
  • Fungsi Deserialize meng-handle input dengan validasi panjang minimal.
  • Struct mirip dengan pendekatan fixed-width serialization.

Diagram Alur Serialisasi dan Deserialisasi Manual

flowchart LR
    A[Objek User] -- serialize() --> B[Serialized String]
    B -- deserialize() --> A

Gambaran di atas memperjelas: serialisasi mengubah objek menjadi string yang disimpan, dikirim, atau diproses lebih lanjut; deserialisasi mengembalikannya ke bentuk semula.


Simulasi: Serialisasi Manual vs Otomatis

FiturManualOtomatis (JSON)
Kontrol formatPenuhTerbatas
Evolusi skemaRisiko human errorLebih terjamin
Error HandlingTanggung jawab devLib menyediakan
SpeedPotensi tinggiUmumnya cukup
KeamananWajib telitiRelatif aman*

Potensi Risiko dan Perhatian

  1. Human Error: Kesalahan offset (misal index slicing salah) akan menyebabkan data korup atau salah interpretasi.
  2. Compatibility: Jika format berubah, seluruh proses serialisasi/deserialisasi harus diperbarui konsisten.
  3. Scalability: Untuk objek nested/kompleks, kode manual cepat menjadi sulit dirawat.
  4. Validasi: Tidak ada validasi otomatis kecuali kita membangunnya sendiri (misal username harus 8 karakter atau kurang).

Best Practice Serialisasi Manual

  • Definisikan Spesifikasi Format secara jelas dan dokumentasikan.
  • Sertakan unit test untuk semua edge case (angka dengan panjang berbeda, nama pendek dan panjang, flag boolean).
  • Pisahkan kode serialisasi dari logika bisnis utama untuk memudahkan refactoring.
  • Gunakan exception handling agar error mudah ditemukan (misal incomplete string).
  • Jika struktur berkembang (misal: bertambah field), buat versioning dalam string serialisasi.

Kesimpulan

Serialisasi dan deserialisasi manual tetap menjadi senjata penting dalam toolkit seorang engineer, meski di era frameworks serba otomatis. Ia memastikan adanya fleksibilitas dan kontrol maksimal tatkala kebutuhan bisnis atau sistem mendorong pada standar spesifik dan performa optimal. Namun, semestinya disertai disiplin dokumentasi dan testing yang baik agar tidak menjadi sumber masalah laten di masa depan.

Jadi, di tengah kebebasan dan kekuatan serialisasi otomatis, pahami kapan harus “turun tangan” dan melakukan serialisasi secara manual. Kerap kali di situlah seni sejati berprogram tampil: mengubah struktur menjadi kode, dan kode menjadi struktur, secara presisi layaknya seorang tukang jam klasik.


*Catatan: Untuk konteks keamanan, baik manual maupun otomatis tetap memerlukan pengamanan dari serangan deserialization exploits pada data tak dipercaya.


Referensi:

comments powered by Disqus