Data oriented

จุดเด่นหนึ่งของภาษาตระกูล LISP (รวมถึง Clojure ด้วย) ซึ่งแตกต่างจาก functional language ตระกูลอื่นๆ คือ มันมีแนวคิด data oriented ผสมอยู่ สามารถเห็นได้ชัดจาก syntax ของภาษาที่จริงๆ แล้ว เป็นแค่ list ธรรมดาๆ เท่านั้น ดังตัวอย่างโค้ดของการประกาศฟังก์ชันของ Clojure ด้านล่างนี้ ที่จริงๆ คือ list ที่มีค่าด้านใน 4 ค่า ได้แก่ defn, my-fuction, [a b] และ (println a b) ตามลำดับ


(defn my-function [a b] (println a b))

ความหมายของโค้ดด้านบนนี้ คือ ประกาศฟังก์ชัน ชื่อ my-function ซึ่งรับตัวแปร 2 ตัว คือ a และ b จากนั้น  print a และ b ออกมา

การมี syntax ในลักษณะนี้มีประโยชน์หลายอย่าง ทั้งความง่ายในการเขียน parser ของภาษา และทำให้ผู้ใช้สามารถเพิ่มความสามารถที่ต้องการลงไปในภาษาผ่านการเขียน macro โดยไม่ต้องรอให้ผู้พัฒนาภาษาเพิ่มความสามารถนั้นจากต้นทาง

นอกเหนือจาก syntax ของภาษาแล้ว Clojure ยังแสดงให้เห็นถึงแนวคิด data oriented ที่ผู้สร้างภาษาใส่เข้ามาผ่านสิ่งต่างๆ ในภาษาอีกหลายอย่าง วันนี้ผมจะขอตัวอย่างหนึ่งมาเล่าให้ฟังว่ามันช่วยเราจัดการกับ data ได้สนุกขึ้นอย่างไร

ขอยกตัวอย่างบางส่วนจาก issue api ของ Github


{

...,
"labels": [
  {
    "color": "red",
    "name": "bug",
  },
  {
    "color": "blue",
    "name": "feature",
  }
  ],
...
}

ถ้าหากผมต้องการเปลี่ยนสีของ object ที่สองจากสีน้ำเงินเป็นสีดำด้วย JavaScript ผมสามารถทำได้วิธีหนึ่งดังนี้

var issue = {
  "labels": [
    {
      "color": "red",
      "name": "bug",
    },
    {
      "color": "blue",
      "name": "feature",
    }
  ]
};
issue["labels"][1]["color"] = "black";

JavaScript ถือว่าเป็นภาษาที่ใช้จัดการกับ data ได้ง่ายแล้ว ลองนึกถึงภาษาที่ต้องใช้เมท็อด เช่น get ในการดึงค่าออกจาก object (map) ดูว่าโค้ดจะวุ่นวายแค่ไหน ทีนี้ลองมาดูตัวอย่างโค้ดของ Clojure กันบ้างครับ

(def issue {:labels [{:color "red" :name "bug"}
                     {:color "blue" :name "feature"}]})
(assoc-in issue [:labels 1 :color] "black")

ฟังก์ชัน assoc-in รับพารามิเตอร์ 3 ตัว ได้แก่

  • issue คือ data structure ที่เราต้องการทำการแก้ไข
  • [:labels 1 :color] คือ vector สำหรับระบุตำแหน่งของ data ที่เราต้องการเข้าไปแก้ไข ในที่นี้คือ key labels -> ตำแหน่งที่ 2 ใน vector (ตำแหน่งที่ 1 คือ 0) -> key color
  • black คือ ค่าใหม่

จะเห็นว่าความยุ่งยากอยู่ในระดับเดียวกับ JavaScript แต่สิ่งที่ได้เพิ่มขึ้นมา คือ data ก้อนใหม่ เพราะตัวภาษาไม่ไปแก้ map issue เหมือนที่ถูกแก้ไขในตัวอย่างภาษา JavaScript แต่ Clojure สร้าง map ใหม่ขึ้นให้เลย ซึ่งนี่ คือ ตัวอย่างหนึ่งคุณสมบัติ immutability ที่ functional language มีกันนั่นเอง

Clojure ยังมีฟังก์ชันที่ชื่อว่า update-in ซึ่งแสดงให้เห็นถึงความเป็น data oriented functional language ชัดเจนขึ้นไปอีก สมมติว่าผมอยากจะเปลี่ยนคำว่า feature เป็นอักษรตัวใหญ่ทั้งหมด ผมสามารถส่งฟังก์ชัน upper-case ให้แก่ update-in เพื่อทำการ apply ไปที่ค่าตาม path ที่ผมระบุ ซึ่งให้ผลลัพธ์ดังนี้

(update-in issue [:labels 1 :name] upper-case)
; => {:labels [{:color "red", :name "bug"}
               {:color "blue", :name "FEATURE"}]}

ฟังก์ชันกลุ่มนี้ทั้ง get-in, assoc-in, update-in ทำให้ผมเล่นกับ data ได้สนุกขึ้นมาก ลองจินตนาการถึง data ที่มีความซับซ้อนมากๆ แล้วเปรียบเทียบความวุ่นวายในการแก้ไขในชั้นลึกๆโดยยังคง immutability ไว้ ด้วยภาษาที่คุณใช้อยู่เป็นประจำในปัจจุบันดูครับ ว่าเป็นอย่างไร

แนวคิดของ Clojure คือ ให้เราพยายาม model domain ของเราอยู่ในรูป data structure พื้นฐานแล้วเราจะสามารถใช้ (reuse) build-in ฟังก์ชันที่มีอยู่มากมายเพื่อจัดการกับ data เหล่านั้นได้อย่างง่ายดาย แทนที่จะสร้าง class ต่างๆขึ้นมา แล้วต้องเขียนเมท็อดให้ไปรองรับ behavior และ property ของ class นั้นๆ

It is better to have 100 functions operate on one data structure than to have 10 functions operate on 10 data structures. – Alan J. Perlis

ใครที่ลงทะเบียนเรียนไว้เสาร์หน้า (11 ก.ค.) เจอกันครับ

Advertisements

One thought on “Data oriented

  1. Pingback: แนวทางการ design api บน Clojure | Tap

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s