เมื่อเราอยากรู้ว่ามันทำงานได้ยังไง ก็แงะโค้ดมันเลย จะพาดูว่าปกติผมแงะโค้ดเพื่อทำความเข้าใจจุดที่สงสัยยังไง
ด้วยความสงสัยว่าตอนสั่ง mix run
หรือ mix test
มันไปโหลด config/runtime.exs
ตอนไหนเลยแงะโค้ดของ mix
ดูจนได้คำตอบ
เวลาสั่ง mix run
นั่นคือมันจะไปเรียก task ที่ชื่อว่า run ซึ่งเป็น task ที่ติดมากับตอนติดตั้ง elixir อยู่แล้ว ตัวโค้ดอยู่ที่ elixir/lib/mix/lib/mix/tasks/run.ex
(elixir คือ directory ที่เราลง elixir เอาไว้ ต่างกันไปขึ้นอยู่กับว่าติดตั้ง elixir ด้วยอะไร บน OS ไหน)
กลไกของ mix task คือ module สำหรับ task ต้องมี function run
ก็ไปแงะแถวนั้น ตอนแรกก็ยังไม่เห็นว่ามีส่วนไหนที่เกี่ยวข้องกับการโหลดไฟล์ config/runtime.exs
สิ่งที่พอจะทำได้คือลองค้นว่ามีไฟล์ไหนใน path elixir/lib/mix/lib/mix
ที่อ้างถึง config/runtime.exs
บ้าง
ค้นดูแล้วก็เจอไฟล์ที่น่าสงสัยตามรูป
tasks/app.config.ex
น่าสงสัยสุดเพราะบรรทัดที่ค้นเจอบอกเลยว่า
9: This is done by loading
config/runtime.exs
if one exists.
พอเปิดโค้ดในไฟล์ดูแล้วก็เจอโค้ดแบบนี้
config = Mix.Project.config()
runtime = config[:config_path] |> Path.dirname() |> Path.join("runtime.exs")
if File.exists?(runtime) do
Mix.Tasks.Loadconfig.load_runtime(runtime)
end
ชัดเลยว่า task นี้มันจะทำหน้าที่โหลดไฟล์ config/runtime.exs
ถ้ามีไฟล์นี้อยู่ ส่วนโค้ดที่โหลดจริงๆอยู่ในฟังก์ชัน Mix.Tasks.Loadconfig.load_runtime
ลองเปิดดูเจอโค้ดประมาณนี้
@doc false
# Loads runtime configuration, they do not support imports, and are deep merged.
def load_runtime(file) do
config = Config.Reader.read!(file, env: Mix.env(), target: Mix.target(), imports: :disabled)
Mix.ProjectStack.loaded_config(persist_apps(hydrate_apps(config), file), [])
config
end
เอาละเราคงไม่ขุดลึกไปกว่านี้ ณ จุดนี้เรารู้แล้วว่า task app.config
ทำหน้าที่โหลด config/runtime.exs
แต่ว่าตอนเราใช้งานเราเรียก mix run
กับ mix test
อ่ะไม่ได้เรียก mix app.config
มันต้องมีอะไรเชื่อมโยงกัน
เราค้นหาต่อโดยลองค้นว่ามีไฟล์ในที่มี app.config
อยู่ในไฟล์บ้าง แล้วก็เจอแบบนี้
และแล้วเราก็เจอว่าไฟล์ tasks/app.start.ex
นั่นไง พอเปิดดูโค้ดรอบๆบรรทัดนั้นก็เจอแบบนี้
@impl true
def run(args) do
Mix.Project.get!()
Mix.Task.run("app.config", args)
ชัดเลยว่าทุกครั้งที่ task app.start
ถูกเรียกนั้นมันจะเรียก app.config
ให้ทำงานด้วย เราคงไม่ต้องไปแงะ Mix.Task.run
แล้วเพราะชื่อก็ค่อนข้างชัดแล้วว่าเรียกแล้วมันจะไปสั่ง app.config
ให้ทำงาน
ต่อไปก็หาต่อว่าแล้วใครมันเรียก app.start
บ้างเหมือนเดิมค้น app.start
ดูว่าเจอที่ไฟล์ไหนบ้าง แล้วก็เจอแบบนี้
นั่นไงและแล้วเราก็เจอว่า tasks/run.ex
กับ tasks/test.ex
มีการเรียก app.start
ให้ทำงาน ลองเปิดดูโค้ดของทั้ง task run
กับ test
พบว่ามันไปเรียก app.start
เวลาสอง task นี้ทำงานจริงๆด้วย
สรุปคือ run
และ test
จะเรียก app.start
แล้ว app.start
เรียก app.config
แล้ว app.config
โหลด config/runtime.exs
อีกที
จริงๆที่เขียนมาประเด็นไม่ได้อยู่ที่ว่าจะรู้ไปทำไปหรอก ใช้ mix ไม่ต้องรู้ก็ได้ว่ามันโหลด runtime.ex ยังไง แต่ประเด็นคือถ้าเราสงสัยการทำงาน เรามีโค้ดมันอยู่ ไม่ต้องกลัวที่จะขุดเพื่อจะเรียนรู้มัน เครื่องมือสำคัญในการลงลุยอ่านโค้ดในแต่ละครั้งคือ
- Document เพราะเราต้องรู้ก่อนว่าสิ่งต่างๆที่เราลงไปขุดหลักๆมันไว้ทำอะไร มีองค์ประกอบอะไรบ้าง เช่นตอนขุดก็ต้องอ่าน document ของ mix ว่ามันมีหลักการยังไง แบ่ง task ยังไง โค้ดของ task อยู่ที่ไหน
- Text search tool อันนี้สำคัญก็คือเอาไว้ค้นหาไฟล์ที่มีข้อความ หรือส่วนของโค้ดที่เราสนใจ ว่ามันถูกอ้างอิงหรือเรียกใช้ที่จุดไหน
- Editor แน่นอนเจอไฟล์แล้วเราก็ต้องเปิดดูโค้ดโดยรอบมัน หาความเชื่อมโยงต่ออีกที
- Paper and Pen กระดาษและปากกา เอาไว้จดโน้ต เอาไว้วาดรูปเพื่อเชื่อมโยงความสัมพันธ์ ของโค้ดแต่ละไฟล์ แต่ละ module ที่เราแกะ
Top comments (2)
English?
Maybe in next next post.