Apa itu Repository Pattern?

TL;DR. Repository pattern hanya melakukan enkapsulasi terhadap proses data persistence saja.

5 min readNov 24, 2016

--

Sebelum membaca lebih lanjut tentang Repository pattern, ada baiknya kita memahami lebih dahulu salah satu konsep penting dalam OOP, yaitu interface. Bagi yang belum paham apa itu interface, bisa baca disini om.

What

Menurut saya pribadi, repository pattern adalah suatu pendekatan untuk memisahkan business logic kita dengan persistence/query logic. Yang dimaksud dengan persistence logic adalah baris-baris code yang khusus berinteraksi dengan Database, atau gampangnya disebut operasi CRUD (gak termasuk controller ya 😁).

Why

“Apalah ini gunanya kalo hanya untuk memisahkan business logic dengan persistence logic? Padahal kan code saya jalan normal aja tuh.” Pertanyaan menarik! Urjensi paling utama dari pengimplementasian Repository pattern adalah Separation of Logic, dimana konsep ini selaras dengan salah satu prinsip dasar huruf S dari SOLID principles, yaitu Single Responsibility Principle: satu class hanya boleh mengerjakan satu task saja. Kita akan melihat manfaatnya nanti.

How

Oke langsung aja ke kode ya bro. Biasanya, untuk melakukan operasi dasar CRUD, kita menuliskannya sebagai berikut:

class ArticleController {
// ... constructor etc ...
public function getArticle()
{
$id = $_GET['id'];
// Cari dari database MySQL
$sql = "SELECT * FROM article WHERE (...etc)";
if (! $result = mysqli_query($this->connection, $sql)) {
// Error
throw new \Exception('Artikelnya gak ketemu pak');
}
$row = mysql_fetch_row($result);
// Proses $row ...


echo json_encode(['article' => $row]);
}
// Rest of CRUD
}

Mohon maap nih om-om yang udah master kalo rada begah ngeliat code mysqli wkwk. Code-nya dimaksudkan untuk audience yang lebih general saja, dan untuk menunjukkan ide bahwa controller di atas ikut terlibat dalam melakukan operasi persistence.

“Lah tapi piye pak saya pake Laravel, atau CodeIgniter, atau framework MVC lainnya yang ada Model-nya. Jadi kan tetep aja pak saya ngambil/nyimpen data ke database lewat Model!”. Okayy. Di bawah ini saya coba buatkan contoh untuk pengguna Laravel:

class ArticleController extends Controller {
// ... constructor etc ...
public function createArticle(Request $request)
{
$id = $request->get('id');
// Cari ke database lewat model Article
$article = Article::
where('id', $id)
->where('status', 'published')
->orderBy('name', 'desc')
->get();


return response()->json(['article' => $article]);
}
// Rest of CRUD
}

Nah, sekarang saatnya kita melihat bagaimana Repository pattern memiliki peran andil dalam memisahkan persistence logic kita dari controller. Langkah awal kita adalah dengan membuat class ArticleRepository:

class ArticleRepository {
// ... constructor (bila perlu) ...
public function findById($id)
{
$article = Article::
where('id', $id)
->where('status', 'published')
->orderBy('name', 'desc')
->get();
return $article;
}
public function update(Article $article)
{
// ...
}
}
class ArticleController extends Controller {
// ... constructor (bila perlu) ...
public function createArticle(Request $request)
{
$id = $request->get('id');
// Cari ke database lewat Repository
$repo = new ArticleRepository();
$article = $repo->findById($id);


return response()->json(['article' => $article]);
}
public function updateArticle()
{
// ...
}
// Rest of CRUD
}

Udah gtu aja. Haha. Keliatannya makin ribet ya? 😛

Iyap mungkin bagi sebagian orang, metode seperti ini hanya akan semakin menambah layer yang dibutuhkan saja, padahal kan sudah ada yang lebih sederhana. Namun, disini kita bisa melihat kinerja controller yang “hanya” menerima input dan mengembalikan output dari user saja, dan memang seharusnya begitu. Tugas maen database? Sudah di-handle oleh class ArticleRepository. Ibarat tugas sekretaris ya sekretaris, bendahara ya bendahara, ga boleh dicampur-campur 😁

More!

Masih belum selesai. Saya masih meyimpan senjata utamanya, yaitu manfaat dari proses code-decoupling ini. Untuk mengetahuinya, mari kita gunakan interface!

interface ArticleRepository {
public function findAll();
public function findById($id);
public function create(Article $article);
public function update();
}
/**
* Karena contoh di atas kita menggunakan Eloquent,
* maka saya ubah nama class ArticleRepository tadi menjadi..
*/
class EloquentArticleRepository implements ArticleRepository {
// Tinggal implement method-methodnya saja..
}
class ArticleController {
public function createArticle(Request $request)
{
$id = $request->get('id');
// Ubah nama classnya
$repo = new EloquentArticleRepository();
$article = $repo->findById($id);

return response()->json(['article' => $article]);
}
}

Dengan adanya interface sebagai penengah, kita menjadi lebih leluasa dalam pemilihan Repository artikel yang ingin kita gunakan: tinggal bikin aja Repository baru, yang penting mengimplementasikan interface ArticleRepository. Misal, saya tidak ingin menggunakan Eloquent sebagai mekanisme persistence-nya, saya mau pake ORM lain, seperti Doctrine aja. Bisa. Tinggal buat DoctrineArticleRepository. Atau saya mau yang klasik-klasik saja, make raw query, bissaaa, tinggal bikin RawQueryArticleRepository. Atau mau caching pake Redis saja. Bisa. Saya tinggal buat class RedisArticleRepository. Contoh lain, misal suatu saat nanti ternyata requirement aplikasi kita mengharuskan untuk berpindah database dari MySQL ke MongoDB. Saya tinggal bikin class MongoArticleRepository, buat detail implementasinya, lalu ubah deh instansiasi repository di controller-nya. Sangat fleksibel. Malah, bisa lebih fleksibel lagi kalo saya menggunakan Service Container yang memang support Dependency Injection (PHP-DI, Aura-DI, Laravel Container, dll). Secara umum, contoh kodenya bisa menjadi seperti ini:

class ArticleController {
/**
* Tinggal typehint ke ArticleRepository aja,
* urusannya Service Injector-nya nanti yang buat instance.
* Tergantung settingan kita
*/
public function createArticle(Request $request, ArticleRepository $repo)
{
$id = $request->get('id');
$article = $repo->findById($id);

return response()->json(['article' => $article]);
}
}

Lebih simple bukan?

Poin pentingnya adalah: Walau kita gonta-ganti database, walau saya ubah-ubah struktur database dan mekanisme peyimpanan/pengambilan data ke/dari database, kita jadi gak perlu khawatir perubahan itu akan mempengaruhi code di controller kita (atau bahkan komponen lain yang berhubungan dengan data persistence), karena perisistence logic-nya sudah kita enkapsulasi menggunakan Repository.

More (2)!

Dengan kemampuan memilih tipe repository yang kita inginkan, memungkinkan kita untuk membuat Repository yang khusus digunakan dalam test environment saja. Biasanya sih disebut InMemoryRepository, yang isinya hanya abstraksi dari collection atau array saja. Contoh:

class InMemoryArticleRepository implements ArticleRepository {
private $articles = [];
public function findById($id)
{
return $this->articles[$id];
}
public function findAll()
{
return (array) $this->articles;
}
public function save(Article $article)
{
$id = uniqid();
$article->setId($id); // misal aja lho

$this->article[$id] = $article;
}
// ... etc
}

Repository jenis ini nantinya bisa kita jadikan sebagai tumbal mock ketika melakukan proses unit testing. Saya tidak akan menuliskan bagaimana detilnya, karena saya rasa sudah di luar scope tulisan ini.

Then: Conclusion

Nah, begitulah kira-kira alasan keberadaan repository pattern dalam dunia OOP. Agar lebih jelas, saya akan coba rangkum poin-poin penting dalam tulisan ini:

  1. Tugas RP hanya untuk enkapsulasi persistence logic
  2. Meringakan tugas controller (atau komponen lain) dalam hal persistence
  3. Fleksibilitas ketika kita memutuskan untuk berganti QueryBuilder, ORM atau database

Saya harap tulisan ini bermanfaat bagi semua, kalau ada typo atau menemukan kesalahan dalam kode di atas, mohon dikoreksi. Atau kalau ada pandangan dan pendapat yang berbeda, boleh lah kita diskusikan di kolom komentar. Kalau dirasa tulisan saya bermanfaat, bisa lah ya direkomendasikan dengan pencet tombol 💚 di bawah, hehe.

Happy coding semua!

--

--

Software Developer @Chordify, Utrecht. NOTE: Please navigate to https://jihadwaspada.com. I no longer write on Medium