ทำให้ App บน Windows เป็นสีขาว-ดำ

เนื่องจากว่าผมได้พยายามลองทำให้ Application บน Windows นั้นเปลี่ยนเป็นสีโทนขาว-ดำ เลยอยากจะแชร์สิ่งที่ได้ลองทำนะครับ (ถึงแม้ว่าผลของการ Implement นั้นยังไม่ถูกใจเท่าที่ควร)

ก่อนอื่นเลยผมขอเรียก app นี้ว่า Mourning App และเนื่องจากว่าต้องการทำสำหรับ Windows App ดังนั้นภาษาที่ผมใช้คือ C++ และ Win32 API ซึ่งตัว API ที่ใช้หลักๆคือ Magnification API ซึ่งเป็น Windows API ที่ปกติเอาไว้ทำพวก Tool ที่เป็นแว่นขยายต่างๆ

หลักการของ Mourning App ที่ผมทำมี 4 ขั้นตอน คือ

  1. หา Process ที่เราสนใจจะทำการ apply การทำภาพขาวดำก่อน

    API ที่ผมใช้ส่วนนี้คือ

    ::EnumProcesses ซึ่งทำให้เราได้จำนวน Process ที่กำลังรันอยู่ทั้งหมดมาพร้อมทั้ง Process ID ซึ่งเราจะใช้เอาไว้หาชื่อ Process ที่เราสนใจได้

  2. หา Window Handle (hwnd) ที่มันทำการแสดงผลอยู่ (visible) ของ Process นั้นๆ

    Code หลักๆที่ใช้ก็คือ  ::EnumWindows
    ซึ่งจากนั้นใน Callback ของ EnumWindowsProc นั้นจะได้ hwnd มาเรื่อยๆซึ่งผมจำการเช็ค

    if (!::IsWindow(hwnd) && !::IsWindowVisible(hwnd))
    return true;

  3. Render ทับตำแหน่ง application จริงๆด้วย Magnifier window พร้อมกับแปลงให้เป็นสีแบบ Gray Scale

    ส่วนนี้เป็นส่วนสำคัญที่สุด ซึ่งใช้ Magnification API โดยการสร้าง Window ด้วย Style : MS_CLIPAROUNDCURSOR

    m_hwndMag = CreateWindow(WC_MAGNIFIER, TEXT(“MagnifierWindow”),
    WS_CHILD | MS_CLIPAROUNDCURSOR | WS_VISIBLE

  4. ทำการ Refresh รูปบ่อยๆเพื่อให้ภาพเนียนที่สุดเวลา Application มีการ update หน้าจอ

    ส่วนนี้ไม่มีอะไรมากก็คือการตั้ง Timer เพื่อทำการ Refresh UI ครับแต่เราจะ Refresh เฉพาะ window ไม่ใช่ทั้งหน้าจอ Desktop

ตัวอย่างที่ได้ครับ

vscode
vscode in grayscale
chrome.png
Chrome เป็นสีเทา แต่ Edge ยังเป็นสีปกติ
ffx2.png
เกม FFX-2 ก็ทำให้ขาว-ดำ ได้นะครับ

ที่นี้มาดูผลที่ยังไม่น่าพอใจใน Implement ครั้งนี้ครับ

  1. ตัว render ภาพขาว-ดำนั้นเป็น Top Window ซึ่งทำให้ถ้ามี App ที่เปิดทับมันก็จะเป็นสีขาว-ดำด้วย
  2. ช้า เนื่องจากการ refresh นั้นบ่อยๆมีผลกับ Performance ทำให้ภาพมี delay บ้าง
  3. CPU ขึ้นตลอดเวลา 5% เนื่องจากต้อง query Process ตลอดเวลาในการเช็คว่ามี Window ของ Process ที่เราจะทำการ render ขาว-ดำ เปิดมาใหม่รึเปล่า

สุดท้ายนี้ ใครสนใจอยากดูตัวอย่างก็ Github เลยครับผม https://github.com/anurocha/mourning-win-app

เข้าสู่ C++ ยุคใหม่กับ Module System สำหรับ C++ 17/20

ไม่ยอมน้อยหน้าภาษา Modern เพราะหนึ่งใน Feature ที่มีการพูดถึงกันมากของมาตรฐานใหม่ของ C++ 17 ก็คือเรื่อง Module System (Link) ซึ่งเป็นแนวคิดทำให้ Library เป็น Module แบบจริงจัง โดยที่ทางกลุ่ม C++ Working Group ได้นำเสนอมานานแล้ว และมีแผนที่จะเอาเข้ามาเป็นส่วนหนึ่งของ C++ 17 แต่เหมือนว่าไม่น่าจะทัน C++ 17 แล้วครับ สรุปแล้วตอนนี้ Feature นี้อยู่ในขั้น Technical Specification ซึ่งน่าจะออกจริงใน C++ 20 (เลขข้างหลังเป็นเลขที่ เช่น 2017 หรือ 2020)

เป้าหมายของ Module System คือทำให้ C++ นั้นทำการ Compile ได้เร็วขึ้นและทำให้ Code นั้นมีการจัดการระดับ Component ได้ง่ายขึ้น เพราะปัจจุบัน #include นั้นใช้งานปนไปหมดทั้ง Headers, Inlines รวมทั้งบางทีมี Implemenation กันเลยทีเดียว

Microsoft นั้นได้ออก Preview สำหรับการทดลอง Module ใน Visual Studio 2015 Update 1+ มาลองดูกันเลยดีกว่า

ก่อนอื่นเลยครับ เนื่องจากว่า Visual Studio ในส่วนของ IDE นั้นยังไม่ Support ดังนั้นเราจะต้องทำการ Compile กับ Build ผ่าน Command Line นะครับ

สร้าง Module

ในการสร้าง Module นั้นให้เราสร้างไฟล์ใหม่มา ซึ่งโดยทั่วไปจะนิยมใช้ไฟล์ .ixx (ผมเดาว่ามาจาก Interface++)
เรามาสร้าง Module เอาไว้ Convert ค่าง่ายๆกัน

ไฟล์ converter.ixx

module converter;
export int CtoB(int x)
{
    return x + 543;
}

จาก code นี้จะเป็นการประกาศ Module ชื่อ converter ซึ่งมี function ‘CtoB’ ที่ทำการแปลง ค.ศ. ไป เป็น พ.ศ. ที่จะ export ออกไปให้ Code อื่นใช้

จากนั้นเราต้อง compile ด้วย commandline แบบนี้

cl /c /experimental:module converter.ixx

สิ่งที่ได้ก็คือไฟล์ converter.ifc กับ converter.obj

converter.png

เรียกใช้ Module

ที่นี้มาในส่วนของ Code หลักที่มี main entry point กันครับ ผมตั้งชื่อไฟล์ว่า main.cpp

ไฟล์ main.cpp

#include <iostream>
import converter;
int main()
{
 int year;
 std::cout << "Enter Year : ";
 std::cin >> year; 

 int bc = CtoB(year);
 std::cout << "Thai year is " << bc << std::endl;
 return 0;
}

Code ในส่วนนี้มีการเรียกใช้ Module ชื่อ ‘converter’ ด้วย keyword ที่ชื่อ import จากนั้นก็จะเรียกใช้ function ที่ชื่อ CtoB() ได้ทันทีเลยครับ

แน่นอนว่าเราต้อง compile ด้วย command line เช่นเคยโดยต้องระบุ converter.ifc เป็น parameter ของ module ที่จะเรียกใช้

cl /c /experimental:module /module:reference converter.ifc main.cpp

เมื่อรันเสร็จก็จะได้ main.obj มาครับ

main.png

ที่นี้จะเป็นว่าไม่มี .exe ให้เรา….สิ่งที่ต้องทำคือการสร้าง .exe ด้วย

link *.obj /OUT:main.exe

link.png

ทดสอบ

ลองรัน main.exe ที่ได้มาครับ ทำงานถูกต้องนะ 🙂

out.png

ลองด้วย Class

จากตัวอย่างข้างบนนั้นเป็นการสร้าง Module ด้วยการ export แค่ function แต่ถ้าเราอยากที่จะ  export Class ล่ะ เราก็ทำได้ครับ เช่น สร้าง Class  converter โดยมี method 2 ตัวให้เรียกใช้

module converter;
export namespace converterUtil
{
 class converter
 {
 public:
 int CtoB(int year)
 {
 return year + 543;
 }

 int CelsiusToFahrenheit(int c)
 {
 return (c * 1.8) + 32;
 }
 };
}

มาดูที่ main.cpp เราก็ทำการ import มาใช้และสร้าง Object ได้เลย เช่นใน ‘convt’ ตาม Code ด้านล่างนี้

#include <iostream>
import converter;
int main()
{
 converterUtil::converter convt;

 int year;
 std::cout << "Enter Year : ";
 std::cin >> year; 

 std::cout << "Thai year is " << convt.CtoB(year) << std::endl;

 int cel;
 std::cout << "Enter Temp in Celsius : ";
 std::cin >> cel; 
 std::cout << "Temp in Fahrenheit is " << convt.CelsiusToFahrenheit(cel) << std::endl;

 return 0;
}

ผลที่ได้ก็ Work ดีครับ!!

outex.png

สรุปแล้ว C++ Module น่าจะช่วยให้ C++ Developer ออกแบบและทำงานกับ Code ได้เป็นระเบียบเรียบร้อยขึ้น

และอีกอย่างคือจริงๆเท่าที่ผมลองในการสร้าง Module ถ้ามันมีใช้ header ตัวอื่นผมก็ยังทำให้มันเวิร์คไม่ได้นะ จึงต้องยกตัวอย่างแบบง่ายๆแบบนี้ครับ ซึ่งหวังว่าตัวจริงออกมาคงไม่วุ่นวายมากนะ

ณ. ตอนนี้เราก็มาเฝ้ารอ C++ 20 กันเลยกัย Module System!!

ปล. ดู Code ได้ที่ https://github.com/anurocha/cpp_module เลยครับผมอัพไว้ละ

Node.js – LoopBack กับการต่อ Database

ความเดิมตอนแรกสุดเลยนั้น ผมใช้ datasources เป็น memory เพราะว่าใช้ในการ Development ที่นี้เนื่องจากว่าผมอยากใช้ database เป็น NoSQL ผมก็เลยลองหาวิธีการดู ซึ่งก็ไม่ผิดหวังครับ LoopBack นั้นจัดการให้เราได้อย่างง่ายๆเช่นเคย

บทความก่อนหน้าเพื่อความเข้าใจพื้นฐานมากขึ้น

Node.js เขียน REST API ด้วย LoopBack
Node.js – LoopBack มาต่อกันที่การเพิ่ม REST API กับ Query กัน

ที่นี้เปิดดูไฟล์ datasources.json กันก่อนครับ จะเห็นว่าเป็นการ define ว่าใช้ memory

{
  "db": {
    "name": "db",
    "connector": "memory"
  }
}

แก้ datasources.json
ผมก็แค่เปลี่ยน configuration ในนี้ให้เป็น  ‘mongodb’ ซึ่งผมทดสอบกับ Azure DocumentDB service นะครับ ไม่ได้ตั้ง mongoDB เอง

nosql.png

ที่นี้เราลองมารัน LoopBack กันอีกรอบนึงครับ ปรากฎว่ารันไม่ผ่าน เพราะ LoopBack ไม่รู้จัก configuration นี้

no-connector.png

ติดตั้ง Connector
สิ่งที่เราต้องทำคือการ install mongodb connector ครับ ด้วย npm command ข้างบน

npm install loopback-connector-mongodb

เมื่อ install เสร็จก็จะสามารถรันได้แล้วครับ เช่นเดิมคือ port เบอร์ 3000

has-connector.png

ทดสอบ
ที่นี้เราลอง POST เพื่อใส่ข้อมูลกัน ผม POST  – anurocha กับ destiny ไปครับ

post-db.png

ที่นี้ลอง Query ดูใน Azure Dashboard ก็จะเห็นว่าลองใช้ Query Explore บน Azure ดูก็ได้ค่าที่ POST ไปจาก localhost ที่เราต่อกับ mongoDB บน Azure ถูกต้อง

azure-db.png

จะเห็นได้ว่า LoopBack นั้นช่วยให้เรา Connect ไปที่ Database ได้โดยที่ผมยังไม่ได้เขียน Code หรือ SQL เลยโดยที่ datasource ที่ LoopBack นั้นมี Connector ก็ดูได้ตามนี้ครับ (Database connectors) ซึ่งคร่าวๆก็มีครบหมดครับสำหรับตัวยอดนิยม MongoDB, MySQL, Oracle, PostgreSQL, Redis, SQL Server, SQL Lite และอื่นๆ

เป็นไงครับ POWER FUL มากๆ…

Node.js – LoopBack มาต่อกันที่การเพิ่ม REST API กับ Query กัน

หลังจากที่ผมพูดถึงความสามารถเบื้องต้นของ LoopBack ไปแล้วนั้นใน Node.js เขียน REST API ด้วย LoopBack ซึ่งจะเห็นได้ว่าเราสามารถสร้าง REST API ได้ง่ายมาก แต่ทีนี้ถ้าเราต้องการที่เพิ่ม API ล่ะจะทำได้ยังไง

เรากลับมาดูที่ไฟล์ user.js กันก่อนครับ ซึ่งเป็นไฟล์ว่างๆ

'use strict';

module.exports = function(User) {

};

สิ่งที่ผมอยากจะได้ก็คือถ้าเราต้องการ API เพื่อที่จะเอาค่าของ User 4 คนที่ได้คะแนนสูงสุดจะต้องทำยังไงบ้าง
สิ่งที่เราต้องทำคือการเพิ่ม remoteMethod (ซึ่งทาง LoopBack Framework จะทำการ Route มาเข้า Method ของเราครับ

'use strict';

module.exports = function(User) {
User.getTopUsers = function(cb){
cb(null, "getTopUsers Response");
};

User.remoteMethod (
'getTopUsers',
{
http: {path: '/gettopusers', verb: 'get'},
returns: {arg: 'users', type: 'string'}
}
);
};

จะเห็นว่า Code User.remoteMethod นั้นทำการ define ว่าถ้ามี HTTP Request ที่เป็น GET เข้ามาที่ Path /gettopusers นั้นจะทำการเรียก Method User.getTopUsers นั่นเอง

และใน Method ที่ชื่อ User.getTopUsers นั้นตอนนี้ผมลองให้ส่งค่ากลับไปว่า getTopUsers Response ที่นี้ลองรันดู LoopBack เพื่อเป็น Server ดูครับ

ลองเช็คกับ API Explorer ก็จะเห็นว่า API ที่เราเพิ่งเพิ่มเข้าไปมาแล้ว

new-api.png

เนื่องจากเป็น GET ผมลองเรียกผ่าน Browser ครับก็ได้ Response มาแบบนี้ ตามที่เขียนไว้

new-api-response.png

ที่นี้จาก API ที่ผมต้องการนั้น ผมอยากได้ User ที่คะแนนสูงสุด ซึ่งทาง LoopBack นั้นก็มี Build-in API ให้เราใช้ในการ Query ข้อมูลจาก Model ได้ครับ (Querying data) เช่น

'use strict';

module.exports = function(User) {
User.getTopUsers = function(cb){
User.find({
order: 'score DESC',
limit : 4
}, (err, instances)=&gt;{
cb(null, instances);
});
};

User.remoteMethod (
'getTopUsers',
{
http: {path: '/gettopusers', verb: 'get'},
returns: {arg: 'users', type: 'string'}
}
);
};

ซึ่งจาก Code ข้างบนนี้จะเป็นการใช้ User.find ซึ่งเป็นการ Query หา Model โดยมี Filter ว่า หา ‘score’ ที่มีค่าสูงสุด 4 entries แรก

ที่นี้ลองทดสอบกันอีกทีครับ

ผมลองใส่ ข้อมูลไปแบบนี้ตาม Order

[
{
“name”: “alpha”,
“score”: 70,
“id”: 1
},
{
“name”: “beta”,
“score”: 45,
“id”: 2
},
{
“name”: “catto”,
“score”: 39,
“id”: 3
},
{
“name”: “delta”,
“score”: 86,
“id”: 4
},
{
“name”: “sigma”,
“score”: 34,
“id”: 5
},
{
“name”: “fanta”,
“score”: 12,
“id”: 6
}
]

ทีนี้ลองเรียกผ่าน API /gettopusers ดูครับ

result.png

เราก็จะได้ Response ที่ทำการ Order มาแล้วตาม score โดยที่ delta(80), alpha(70), beta(45), catto(39) ตามลำดับที่เราได้ทำ Query ไว้อย่างง่ายดาย

มาถึงตรงนี้เราก็จะได้เห็นความ Powerful ของ LoopBack ไปอีกหนึ่งเรื่องนะครับ 🙂

powered-by-lb-med

Node.js เขียน REST API ด้วย LoopBack

powered-by-LB-med.png

เนื่องจากผมอยากลองเขียน REST ง่ายๆเอาไว้ลองกับงาน Side Project ดูครับ ส่วนตัวแล้วเคยจับ Express มาบ้างแบบน้อยนิด ซึ่งปกติก็ต้องมานั่งเขียน Route กันเองแล้วมาเช็ค Path เลยหา Framework อื่นดู ก็เจอว่ามีทั้ง Sails, Restify และอื่นๆ แต่ลองนึกดูเคยมีคนพูดถึง LoopBack ให้ผมฟัง ผมเลยลองมาใช้ตัวนี้ดีกว่า เพราะเห็นว่า IBM เป็นผู้สนับสนุนรายใหญ่ซึ่งจริงๆแล้วพัฒนาโดย StrongLoop

ก่อนอื่นเข้าไป official site https://loopback.io/ ก่อนเลย ก็เจอว่า Get Started ไม่มี Code ตัวอย่างเลยครับ งั้นมันทำงานยังไงกันนี่ เรามาลองดูกัน

ก่อนอื่นเท่าที่ผมเข้าใจ LoopBack เนี่ยจะใช้แนวคิดเรื่อง Model มากกว่าการ Route ซึ่งหมายความว่าการที่เราจะเพิ่ม API เข้าไป ก็จะเป็นการทำงานเกี่ยวข้องกับ Model (เหมือนกับการเขียน function handler ของ Model) เพราะหน้าที่การ Route นั้น LoopBack จัดการให้เราหมดแล้ว ผ่าน Express นั่นแหละ….

เริ่มแรกเราต้อง Install ตัว LoopBack ก่อนครับ (เป็น commandline interface – CLI)

$ npm install -g strongloop

หลักจากนั้นเราจะต้องทำการสร้าง Project จาก Template ครับด้วย

$ slc loopback

จากนั้นเราจะต้องทำการตั้งชื่อ Project เลือก Directory รวมถึงเลือก LoopBack version

create-proj.png
ผมตั้งชื่อว่า loopback-aro

สิ่งที่ได้คือ Folders และ ไฟล์ต่างๆหน้าตาแบบนี้โดยผมสร้าง Project แบบ api-server ฉะนั้นส่วนที่จะต้องแก้น่าจะทำใน Folder ชื่อ server

folder-struct.png

หลังจากนั้นเราก็ลองทำการสร้าง Model กันครับ เพราะอย่างที่ผมบอกไปข้างต้นว่า loopback นั้นใช้ Model driven ในการพัฒนา REST API

 

$ slc loopback:model

ผมจะสร้าง Model ง่ายๆใช้สำหรับเก็บข้อมูล user ละกันครับ ตัว CLI มันก็จะให้เราตอบไปว่าจะใช้ Feature อะไรของ LoopBack บ้าง เช่น

  • จะใช้ data-source แบบไหน (ค่าปกติคือ memory ซึ่งใช้สำหรับการ Dev เพราะไม่งั้นเราปิด server แล้วค่าจะถูกลบทิ้งครับ เพราะ memory ถูกคืนให้ OS)
  • ใช้ PersistedModel เพื่อทำใช้สามารถเก็บ Model เข้า database ได้ง่าย
  • ทำการเปิด REST API สำหรับ Model ตัวนี้
  • และ อื่นๆ

create-model.png

ที่นี้ผมก็จะสร้าง properties หรือ attibutes ของ user ครับ โดยที่มี

  • name เป็น string
  • score เป็น number

create-prop.png

เมื่อสร้างเสร็จแล้วเราก็จะเห็น Folder ชื่อ common ถูกสร้างขึ้นมารวมทั้งมี Subfolder ชื่อ Model ที่มีไฟล์ user.js/json ซึ่งตรงกับที่เราสร้างข้างต้น

common-folder.png

เราจะเห็นว่า

  • user.js คือ code javascript เปล่าๆ (ที่เอาไว้ให้เราเขียน logic สำหรับ expose REST API เพิ่ม)
  • user.json นั้นจะเป็นการประกาศพวก Properties ต่างๆ (หมายความว่าเราไม่ต้องใช้ CLI ในการสร้าง Model ก็ได้ถ้าเรารู้จักโครงสร้างของ Framework)

model-files.png

ที่นี้เราลองมารันดูครับ

node .

run.png

ลองเข้าผ่าน localhost:3000/explorer ดูก็จะพบว่ามี API Tool (หน้าตาเหมือน Swagger ให้เลยครับ)

explorer

เรามาลอง POST เพื่อสร้าง Model object ดีกว่า

anurocha-80.png

จะเห็นว่าหลังจากกดปุ่ม Try it out! ก็จะทำการยิง http request ไปที่ /api/user และได้รับ message ตอบรับว่า 200 และได้รับ id:1 เป็นค่า key

anurocha-res.png

ดังนั้นถ้าผมลอง GET ด้วย id :1 เราควรจะได้ object นี้กลับมากนะครับ ลองผ่าน Postman (ซึ่งเป็น Tool ที่ใช้ได้การส่ง HTTP request) กันดีกว่า

ได้ response ตามคาด!

get-postman.png

จะเห็นว่าการสร้าง REST API แบบง่ายๆด้วย LoopBack นี่ไม่ต้องเขียน Code เลยซักบรรทัด

แต่ความสามารถของ LoopBack ยังมีอีกเยอะ เช่นการ Extend API ให้ซับซ้อนยิ่งขึ้น การติดต่อกับ Data-source แบบอื่นๆเช่น MySQL หรือ MongoDB เจอกันคราวหน้าครับ 🙂
Notes:

เพิ่ม API อ่านต่อได้เลย

ตัวเลขมหัศจรรย์ Magic Number

สิ่งหนึ่งที่ผมเชื่อว่า Developer ทุกคนเคยทำก็คือการเขียน “ตัวเลขมหัศจรรย์” ลงไปใน Source Code แล้วมันคืออะไรล่ะ

Magic Number ก็คือตัวเลขที่อยู่ใน Code แบบโผล่มาแบบงงๆลอยๆ โดยที่ไม่มีใครรู้ที่มาเลย (นอกจากคนเขียน ซึ่งผ่านไป 3 เดือนก็ลืม 55)

ยกตัวอย่าง Magic Number กันแบบง่ายๆก่อน

            for (int i = 0; > 50; ++i)
            {
                Console.WriteLine("Hello");
            }

ในกรณีนี้ Magic Number คือ “50” เพราะอยู่ดีๆมันก็โผล่มา ถ้าคนมาทีหลังอาจจะงงว่า 50 คือเลขอะไร ตั้งใจเขียนมารึเปล่า

วิธีแก้ปัญหาอย่างง่ายที่สุดคือเราเปลี่ยนมาใช้ตัวแปร const แทนครับ (สำหรับ C++/C#)

            const int LOOPTIME = 50;
            for (int i = 0; i > LOOPTIME; ++i)
            {
                Console.WriteLine("Hello");
            }

ซึ่งจะทำให้ Code เรานั้นรู้ว่าเราต้องการ Loop 50 รอบจริงๆนะ ไม่ใช่พิมพ์ผิดอะไร

ตัวอย่างที่ 2

ผมมี Method/Function นึงทำอะไรบางอย่างแบบนี้

       static public double CalPrice(int price)
        {
            return price + (price * 0.07);
        }

แน่นอนครับ Magic Number ก็คือ 0.07 ที่ Code ผ่านไป 3 เดือน เราก็จะงงว่าทำไมมันต้อง 0.07 ด้วย นี่มัน Method เอาไว้ทำอะไร

เราก็แก้ด้วยวิธีเดิมครับคือการใช้ตัวแปร const มาแทน พร้อมตั้งชื่อให้สื่อความหมาย

        private const double VAT_RATE = 0.07;
        static public double CalPrice(int price)
        {
            return price + (price * VAT_RATE);
        }

โอ้ว นี่คือ การบวก Vat 7% นี่เอง!!!

เอาล่ะที่นี้เรารู้จัก Magic Number กันแล้ว มาลองสรุปกันดีกว่า

ข้อดี :

  • เขียนง่าย
  • เร็ว
  • อ่านแล้วจบ
  • ดูแล้วเหมือนจะสบายตา (ช่วงที่เพิ่งเขียนเสร็จ)

ข้อเสีย :

  • คนอื่นมาอ่าน Code อาจจะงง
  • แถมหนักกว่าอีกเพราะคนเขียนเองก็งงถ้าผ่านไปซักระยะ
  • Code อาจจะ Maintain ยากขึ้นเพราะมี Magic Number ทำให้คนที่ไม่รู้ ก็จะไม่กล้าแตะ และต้องมานั่งไล่ Logic ถ้าต้องการแก้

มาถึงตรงนี้ลองกลับไปดู Code ที่เป็น Production ของเรากันสิว่า คุณเป็นนักมายากล Magic Number กัน(มาก)รึเปล่า

piq_52779_400x400
I love Magic (but sorry not Magic Number!!) 

Note* Picture from Final Fantasy

 

รัน Typescript ผ่าน Node ตรงๆด้วย ts-node

ปกติแล้ว Node.js นั้นจะทำการ execute JavaScript เท่านั้น ซึ่งถ้า Developer นั้นอยากเขียน Project ด้วย TypeScript ก็จะต้องทำการ compile จาก .ts ให้เป็น .js ก่อน

พอดีเห็น GitHub มีโปรเจคหน้าสนใจชื่อว่า ts-node ซึ่งทำให้เราสามารถรัน .ts ไฟล์ได้ตรงๆเลยครับ
Link: https://github.com/TypeStrong/ts-node

การใช้งานก็คือรัน commandline นี้เพื่อทำการรัน Node

ts-node main.ts

มาลุยกันครับ

เริ่มจากเรามี TypeScript file (.ts) ที่สั่งสร้าง http server ชื่อ main.ts

import * as http from "http";

class HttpServer {
private server : http.Server;
public start(){
this.server = http.createServer( (request, response) => {
response.write('Hello...!');
response.end();
});

this.server.listen(8080);
console.log("start server...");
}

public stop(){
this.server.close(()=>{}
);
}
}

let serv = new HttpServer();
serv.start();

ทีนี้เราก็ลอง install ts-node ก่อนครับ

npm install ts-node

เรามาลองรันกันดูครับ

ts-node main.ts

เวิร์คดี!!

runable.png

ถ้าเรามาลองดู Process Tree เราก็จะพบว่าจริงๆแล้วตัว ts-node นั้นก็ทำการรัน node process และทำการรัน bin.js ซึ่งเป็น code ของ ts-node เพื่อให้มันสามารถรัน main.ts ได้

process_tree.png

สรุปแล้วผมคิดว่าโปรเจคนี้น่าสนใจนะครับ เพราะช่วยลดขั้นตอนการ compile ไป JavaScript ไป 🙂
ทั้งนี้ทั้งนั้นต้องทดสอบว่าถ้าเป็นโปรเจคที่ซับซ้อนจะเป็นยังไงบ้าง…

เพิ่มคุณภาพของ Code ด้วย CppCheck

นอกจากการที่ทำ Feature ให้เสร็จตามกำหนดแล้วนั้น Developer ก็ควรจะต้องใส่ใจในคุณภาพของ Software กันด้วย ซึ่งหลายๆครั้งก็เป็นเรื่องที่ถูกละเลยและทำให้เกิด Bug แบบง่ายๆขึ้น

ทั้งนี้ทั้งนั้นในวงการเราก็มีเครื่องมือช่วยเหลือในการตรวจเช็คพวก Error พวกนี้ตั้งแต่การ Compile
ขั้นตอนหรือเครื่องมือนี้เรียกว่า Static Code Analysis 

สำหรับ C++ นั้นอย่างที่รู้ๆกันว่าเป็นภาษาที่มีประวัติยาวนานและเขียนได้หลาย Paradiam หรือปนกันทั้ง C และ C++ รวมทั้ง Framework ต่างๆที่ใช้ใน Software ซึ่งนี่แหละทำให้เกิด Error ได้ง่ายขึ้นไปอีก

พอดีผมเห็นข่าวว่าตัว CppCheck 1.75 เพิ่งจะ ออก (https://sourceforge.net/p/cppcheck/news/2016/08/cppcheck-175/) และผมไม่เคยใช้เจ้านี้เลยขอลองหน่อย

Cppcheck เป็นเครื่องมือที่ช่วยในการดักและแจ้งปัญหาเหล่านี้  ซึ่งเป็น Error ที่ไม่เกี่ยวกับ Compile นะครับ ยกตัวอย่างเช่น

  • Out of bounds
  • Memory leaks!
  • ตัวแปรที่ไม่ได้ initialize
  • Code ซ้ำๆ
  • และอื่นๆ

หลังจาก Install แล้วก็ลองรันโปรแกรมดู

cppcheck.png

ที่นี้เราลองเขียน Code เพื่อทดสอบ CppCheck กัน

// ConsoleApplication3_cpp.cpp
//

#include "stdafx.h"
#include 
#include 

using namespace std;

class Phone
{
public:
void Call() {}

private :
std::wstring _owner;
bool _enabled;
};

int main()
{
Phone *p = new Phone();
p = new Phone();
p->Call();
return 0;
}

Code นี้ผมวาง Error ไว้หลายตัวครับ เรามาลองให้ CppCheck ช่วยหาดีกว่า

cppcheck_1.png
ทำการเลือก Folder ของ Source Code ที่จะทำการ Scan หา Error

เลือกเสร็จ เจอ 3 ตัว! บรรทัดที่ 22 10 และ 23 (ตามคาด)

cppcheck_errorreport.png

 

ตัวอย่าง Error พวกนี้มาลองวิเคราะห์กัน

  1. Line 22: “Variable ‘p’ is reassigned a value before the old one has been used.”

    Phone *p = new Phone();
    p = new Phone();
    จะเห็นว่า pointer ‘p’ มีการชี้ไปที่ Object ที่สร้างจาก Class Phone แล้วไม่ได้ใช้เลยแต่ก็เอาไปชี้ที่ Object อีกตัว

  2. Line 10: “The class ‘Phone’ does not have a constructor.”

    class Phone
    {
    public:
    void Call() {}

    private :
    std::wstring _owner;
    bool _enabled;
    };
    จะเห็นว่า Class Phone เรานั้นไม่มี Constructor แต่เรามี private Members เช่น _owner กับ _enabled ซึ่งสำหรับ C++ นั้นพวก Members ควรจะทำการ Initialize ค่าก่อน เพราะ bool นี่อาจจะเป็น true/false ก็ไม่รู้ :S

  3. Line 23: “Memory leak: p”

    int main()
    {
    Phone *p = new Phone();
    p = new Phone();
    p->Call();
    return 0;
    }
    อันนี้ชัดเจนครับสำหรับ C++ Developer เพราะมีการ new ก็ต้องมีการ delete นะครับ เพราะไม่งั้น LEAK! จากตัวอย่างจบ function main แล้วเราไม่ได้ Delete ทาง CppCheck ก็เลยฟ้องซะเลย

จากตัวอย่างจะเห็นข้างต้นก็พอจะเห็นได้ว่า CppCheck นี้น่าจะช่วยเหลือเราได้ในการปรับปรุงใน Code ของเรามีคุณภาพมากขึ้นและ BUG แบบง่ายๆนั้นลดลง

“Quality is not an act, it is a habit.” – Aristotle
คุณภาพไม่ใช่หน้าที่ แต่เป็นอุปนิสัย – อริสโตเติล

JS++ อะไรกันนี่…

jspp_logo

เมื่อวันก่อนผมอ่าน Twitter แล้วมันก็เด้งบทความเกี่ยว JS++ มาให้อ่าน http://sdtimes.com/the-case-for-js-plus-plus/ ซึ่งเนื้อหาหลักๆที่ผมเข้าใจคือ ทางผู้พัฒนาต้องการอุดช่องว่างของ JavaScript ซึ่งหลักๆก็คือเรื่อง Type และ Object Oriented  ซึ่งโปรเจคแนวนี้ก็มีเยอะมากในวงการเช่น Dart หรือ TypeScript

ส่วน JS++ เองนั้นผู้พัฒนาคือ บริษัท Onux ซึ่งมี Official Site อยู่ที่ https://www.onux.com/jspp/
Platform ที่ทาง JS++ รองรับในตอนนี้คือ Windows กับ Linux เท่านั้น และในปัจจุบันนี้ อยู่ที่ Version 0.4.1 ซึ่งเป็น Early Access Preview อยู่

เมื่อ Install เสร็จก็จะได้ไฟล์ประมาณนี้

jspp_files.png

ลองเช็ค version ดูด้วย  js++ –version ก็ได้เป็น 0.4.1

jspp_ver.png

หลักการทำงานของ JS++ นั้นก็คือเราต้องเขียน Code ด้วย Systax ของ JS++ จากนั้นทำการ Compile ให้ออกมาเป็นไฟล์ .js ที่ Browser เข้าใจ

ที่นี้ลอง Hello World ง่ายๆ ด้วยการสร้างไฟล์ test.jspp

external document;

document.write("Hello World!");

ลอง Compile กันดูครับ

jspp_compiledไฟล์ที่ออกมาก็หน้าตาแบบนี้ครับ ซึ่งเป็นสิ่งที่ js เข้าใจ

// Compiled with JS++ v.0.4.1

!function(){document.write("Hello World!");}();

งั้นลองกับ Node.js หน่อยดีกว่า

import Convert;

external require;
external http = require("http");
external console;

string hostname = '127.0.0.1';
int port = 1337;

http.createServer(void(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World\n');
}).listen(port, hostname, void() {
console.log("Server running at http://" + hostname + ":" + Convert.toString(port) + "/");
});

Compile มาได้แบบนี้ (ดีจริง minify มาให้พร้อม)

// Compiled with JS++ v.0.4.1

!function(){var http=require("http");var hostname='127.0.0.1';var port=1337|0;http.createServer(function(req,res){res.writeHead(200,{'Content-Type':'text/plain'});res.end('Hello World\n');}).listen(port,hostname,function(){console.log("Server running at http://"+hostname+":"+(port+"")+"/");});}();

ลองรันดูก็ WORK ดีครับ

jspp_nodejs.png

ที่นี้ผมลองเอา Code จากหน้า Offical Page ที่มี Class มาลองอีกทีครับ ปรากฏว่า Compile Error เพราะหา Class ไม่เจอ…!@#$

jspp_cls.png

สรุป…ผมว่าสำหรับ Build นี้อาจจะยังไม่ถึงเวลาของ JS++ ในการใช้งานจริงครับ และผมก็คิดว่าทางตัวโปรเจคนี้ก็ยังความท้าทายในการเป็น Framework ที่ฮิตอยู่คือ

  1. ไม่เป็น Open Source
  2. ไม่มี บ.ยักษ์ใหญ่ช่วยหนุน
  3. ไม่มี Roadmap ชัดเจนสำหรับ Release ถัดๆไป

ผมคิดว่า ณ วันนี้ถ้าต้องการมองหาทางเลือกอื่นในการพัฒนา App หรือ Service โดยไม่ต้องใช้ JavaScript ตรงๆ ลองมอง TypeScript หรือ Dart ดีกว่าครับ…(ส่วนตัวตอนนี้ศึกษา TypeScript ครับ)

C++ ภาษานี้ก็ยัง Powerful อยู่เช่นเดิม

c_0

ถ้ามีคนมาถามผมว่าอยากเริ่มเขียนโปรแกรมจะเริ่มจากอะไร ผมก็จะตอบว่า ลองเขียน Java, C# ดูซึ่งเป็น OOP เต็มรูปแบบ มีเครื่องมือครบ และมี Syntax ที่ดีมาก หรือว่าพวกภาษา Script เช่น JavaScript, Python ก็ได้ เพราะจะได้เป็นการหัดคิดแบบเป็น Logic และฝึกแก้ปัญหา

แต่ถ้า ถามว่าอยากเขียนโปรแกรมให้เก่งแบบมองภาพรวมของ Software Architecture ออกจะต้องยังไง
ผมก็จะตอบว่าเขียน C++ ดู

ถึงแม้ว่าภาษา C จะเกิดมาตั้งแต่ปี ค.ศ. 1972 และ C++ มาตอน 1983 แต่ภาษานี้ก็ยังคงความนิยมและคุ้มค่าต่อการศึกษาครับ

เพราะ…C++

  1. เป็นภาษาที่อยู่ระดับเกือบระดับต่ำสุดเป็นรองแค่ Machine Code กับ Assembly ทำให้เราต้องรู้ว่า CPU มันทำงานยังไง
  2. เป็นภาษาที่ใกล้ชิดกับ OS ทำให้เราต้องรู้ว่า OS แต่ละแบบทำงานยังไงมีส่วนประกอบอะไรบ้างสำหรับโปรแกรมหรือ App ของเรา เช่นการจัดการ Process, Thread, File System, Memory, การทำงานระหว่าง Process (IPC)
  3. ไม่ค่อยมี Tool หรือ Function สำเร็จรูปมาให้แบบ Built-In ทำให้การที่เราจะเขียนอะไรง่ายๆ เช่นจะเขียนแปลง String ก็ต้องเขียนเองเยอะ ซึ่งข้อดีคือทำให้เข้าใน Logic/Algorithm ได้ดีขึ้น และมีนิสัยไม่ขี้เกียจที่จะลงแรงเองถึงแม้งานที่ดูเหมือนง่ายอาจจะต้องเขียนกัน 20-30 บรรทัด
  4. ไม่มี Memory Management ที่ฉลาดๆ เราที่จะเขียนก็ต้องฉลาดที่จะใช้เอง ต้องรู้ว่า Memory เก็บยังไงหลังจากที่ทำการ Allocate แล้ว และต้องรู้ว่าจะคืน Memory ให้ระบบตอนไหน
  5. เป็นภาษาที่ถูกต่อยอดไปเป็นภาษาสมัยใหม่หลายๆภาษา เช่น Java, C#, Objective-C, Swift, PHP, Python, Perl, Ruby, JavaScript และอื่นๆอีกมาก ทำให้เราสามารถไปศึกษาภาษาพวกนี้ได้เร็วขึ้น(จริงๆนะ)
    เปรียบเทียบกับทำให้เหมือนเรารู้ภาษาละตินซึ่งเป็นรากฐานของภาษาในยุโรปเกือบทั้งหมด!
  6. ทำให้รู้กระบวนการของการ Compile โปรแกรมตั้งแต่ เขียน Code ไปจนได้ไฟล์ Executable ออกมา
  7. เข้าใจการทำงานของ Framework หลายๆอย่างในปัจจุบัน เช่น OS, Web Browser, .NET Framework หรือ JVM รวมทั้ง Game Engine ต่างๆ และยังใช้เขียนต่อกับ Hardware ด้วย
  8. ส่วนมากจะเป็นสะพานเชื่อมการทำงานระหว่าง Technology เช่นเขียน .NET app ให้คุยกับ Web
  9. Performance ถึงแม้ว่าทุกวันนี้ CPU เราจะแรง แต่ถ้าต้องการรีด CPU ทุก clock cycle การใช้ C++ ก็ช่วยได้นะครับ
  10. Debug ได้ถึง Memory รวมทั้งสามารถ Deassembly Code มาดูเพื่อทำ Reverse Engineer ได้ ถ้าเราเก่งพอ :p
  11. เขียนได้หลาย Paradiam เช่น Imperative, Object-Oriented, Generic Programming (และทำให้ Code มั่วดีด้วยครับถ้าเขียนบนกันทุก Paradiam 555)
  12. ที่สำคัญ ภาษา C++ นั้นยังมีการพัฒนาอยู่เสมอซึ่ง version หลังๆก็คือ C++11/C++14 และที่กำลังจะมาคือ C++17 (เลขข้างหลังคือเลขปี ค.ศ.ที่จะออก) ซึ่งสิ่งที่เพิ่มเข้ามาทำให้เขียน Code ได้ง่ายขึ้น เช่นเดียวกับภาษายุคใหม่แหละครับ

 

C++ is still ROCK (as always)!

ปล.

  • บทความนี้ความเห็นส่วนตัวนะครับ 🙂
  • C++ เป็นภาษาแรกที่ผมอยากเขียนหลังจากที่ผมรู้จักคอมพิวเตอร์ ตอน ม.ปลาย (เพราะอยากเขียนเกม) แต่ไม่สำเร็จเพราะเข้าไม่ถึงผมเลยหนีไปเขียนเวป PHP, C#, Java ตอนเรียนมหาวิทยาลัย
  • C++ เป็นภาษาที่ใช้ในโปรเจคแรกของชีวิตการทำงาน Developer ของผม