Month: June 2018

  • Transpose rows into columns using the Oracle PIVOT operator

    ก่อนหน้านี้เราเคยนำเสนอบทความวิธีการทรานสโพส (หมุน) ข้อมูลจากแถวเป็นคอลัมน์ ด้วยการใช้ฟังก์ชัน SUM และ DECODE กันมาแล้ววันนี้ลองมาใช้อีกวิธีในการแสดงผลดังกล่าวด้วย PIVOT ก่อนอื่นมาดูในส่วน syntax ของ PIVOT กันก่อน

     

    PIVOT Syntax

    SELECT * FROM
    (
      SELECT column1, column2
      FROM tables
      WHERE conditions
    )
    PIVOT 
    (
      aggregate_function(column2)
      FOR column2
      IN ( expr1, expr2, ... expr_n) | subquery
    )
    ORDER BY expression [ ASC | DESC ];

    โดยที่

    aggregate_function คือ aggregate function เช่น SUM, COUNT, MIN, MAX, หรือ AVG

    IN ( expr1, expr2, … expr_n ) คือ รายการค่าของ column2 ที่ต้องการจะแสดงในส่วนคอลัมภ์

     

    คราวนี้ลองมาดูตัวอย่างกัน 

    สมมติเรามีข้อมูลคะแนนภาษาอังกฤษของนักศึกษาใหม่ซึ่งประกอบด้วย 6 ฟิลด์ข้อมูลแสดงดังตัวอย่างด้านล่าง
    ข้อมูล: ตาราง TEST_NEW_STUDENT เป็นตัวอย่างข้อมูลคะแนนภาษาอังกฤษของนักศึกษาใหม่จำนวน 16 รายการ

    โจทย์ เราต้องการจะแสดงจำนวนของนักศึกษาแยกตามคณะที่สังกัด โดยให้แสดงข้อมูลอยู่ในรูปแบบคอลัมภ์

    ดังนั้นจึงเราสามารถเขียนคิวรีโดยใช้ PIVOT เพื่อแก้ปัญหาข้างต้นได้ดังนี้

    SELECT *
    FROM (SELECT ‘TotalStudent’ fac_summary, fac_id FROM test_new_student)
    PIVOT
    (COUNT (fac_id)
    FOR fac_id
    IN (’06’ Engineering, ’08’ Science, ’12’ Natural_Resources))

     

    ผลลัพธ์ที่ได้ : แสดงข้อมูลจำนวนนักศึกษาซึ่งประกอบด้วย จำนวนนักศึกษาคณะวิศวกรรมศาสตร์ คณะวิทยาศาสตร์ และคณะทรัพยากรธรรมชาติ ตามลำดับ โดยแสดงข้อมูลในรูปแบบคอลัมภ์

  • Oracle : Transpose rows into columns using SUM and DECODE

    วันนี้เราจะนำเสนอวิธีการทรานสโพส (หมุน) ข้อมูลจากแถวเป็นคอลัมน์ โดยการประยุกต์ใช้ฟังก์ชัน SUM และ ฟังก์ชัน DECODE ก่อนอื่นจะขออธิบายในส่วนของฟังก์ชัน SUM และ DECODE กันก่อน

    ฟังก์ชัน SUM

    SUMจัดเป็นฟังก์ชันประเภท Aggregate Function ทำหน้าที่ในการคำนวณผลรวมของค่าในคอลัมภ์ มีรูปแบบการใช้งานดังตัวอย่างข้างล่างนี้

    SELECT SUM(aggregate_expression)
    FROM tables
    [WHERE conditions];

    โดยที่

    aggregate_expression คือ คอลัมภ์ที่ต้องการค่าผลรวม โดยที่ข้อมูลในคอลัมภ์จะต้องเป็นชนิดตัวเลขเท่านั้น

    มาดูตัวอย่างการใช้งานกัน

    SELECT fac_id, SUM (eng_score) sum_eng_score
    FROM test_new_student
    GROUP BY fac_id;

    ผลลัพธ์ที่ได้ : แสดงผลรวมของคะแนนภาษาอังกฤษของแต่ละคณะ

    ฟังก์ชัน DECODE

    DECODE เป็นการเขียนเงื่อนไขบนชุดคำสั่ง select  โดยมีลักษณะการทำงานเหมือน IF-THEN-ELSE โดยถ้าเข้าเงื่อนไขที่กำหนด ต้องการให้ทำอะไรก็ให้ระบุลงไป

    Syntax:

    DECODE( expression , search , result [, search , result]... [, default] )

    โดยที่

    expression คือ ค่าที่จะเอามาใช้เปรียบเทียบเงื่อนไข
    compare_value คือ ค่าที่สามารถจะมาเปรียบเทียบได้กับ expression
    return_value คือค่าที่จะแสดงออกมาเมื่อ ค่าของ expression = compare_value
    default_return_value คือค่าที่จะแสดง เมื่อ expression <> compare_value

     

    ลองมาดูตัวอย่างการใช้งานกัน 

    สมมติเรามีข้อมูลคะแนนภาษาอังกฤษของนักศึกษาใหม่ซึ่งประกอบด้วย 6 ฟิลด์ข้อมูลแสดงดังตัวอย่างด้านล่าง
    ข้อมูล: ตาราง TEST_NEW_STUDENT เป็นตัวอย่างข้อมูลคะแนนภาษาอังกฤษของนักศึกษาใหม่จำนวน 16 รายการ

     

    ตัวอย่างคิวรีในการใช้ฟังก์ชัน DECODE

    SELECT fac_id,
    DECODE (
    fac_id,
    ’06’, ‘คณะวิศวกรรมศาสตร์’,
    ’08’, ‘คณะวิทยาศาสตร์’,
    ’12’, ‘คณะทรัพยากรธรรมชาติ’,’null’)
    fac_name,stud_name_thai,stud_sname_thai,sn_code,eng_score
    FROM test_new_student;

    ผลลัพธ์ที่ได้

    โดยความหมายของด้านบนคือ

    ถ้าค่า fac_id ของตาราง test_new_student เป็น ’06’ ก็ให้แสดง คำว่า ‘คณะวิศวกรรมศาสตร์’

    ถ้าค่า fac_id ของตาราง test_new_student เป็น ’08’ ก็ให้แสดง คำว่า ‘คณะคณะวิทยาศาสตร์’

    ถ้าค่า fac_id ของตาราง test_new_student เป็น ’12’ ก็ให้แสดง คำว่า ‘คณะทรัพยากรธรรมชาติ’

     

    โดยปกติถ้าเราเขียนคิวรีเพื่อนับจำนวนนักศึกษาโดยแยกตามคณะที่สังกัดของนักศึกษา เราสามารถเขียนคิวรีได้ดังนี้

    SELECT fac_id, COUNT (*) fac_summary
    FROM test_new_student
    GROUP BY fac_id;

    ผลลัพธ์ที่ได้ : แสดงจำนวนนักศึกษาแยกตามคณะที่สังกัด การแสดงผลปกติจะแสดงในรูปแบบแถว

     

    คราวนี้ลองมาตั้งโจทย์ใหม่โดยยังมีความต้องการเหมือนเดิมคือ นับจำนวนนักศึกษาโดยแยกตามคณะที่สังกัดของนักศึกษา แต่เปลี่ยนจากการแสดงในรูปแบบแถวให้แสดงในรูปแบบคอลัมภ์แทน

    จากโจทย์เราสามารถประยุกต์ใช้งานฟังก์ชัน sum และ decode เพื่อจะแปลงข้อมูลในรูปแบบแถวให้อยู่ในรูปแบบ
    คอลัมภ์ได้ โดยเราสามารถเขียนคิวรีได้ดังนี้

    SELECT ‘TotalStudent’ faculty,
    SUM (DECODE (fac_id, ’06’, 1)) Engineering,
    SUM (DECODE (fac_id, ’08’, 1)) Science,
    SUM (DECODE (fac_id, ’12’, 1)) Natural_Resources
    FROM test_new_student

    ผลลัพธ์ที่ได้ : แสดงข้อมูลจำนวนนักศึกษาซึ่งประกอบด้วย จำนวนนักศึกษาคณะวิศวกรรมศาสตร์ คณะวิทยาศาสตร์ และคณะทรัพยากรธรรมชาติ ตามลำดับ โดยแสดงข้อมูลในรูปแบบคอลัมภ์

  • ปัญหาการเชื่อมต่อฐานข้อมูล Oracle ไม่ได้ เนื่องจาก Listener

    สำหรับผู้ดูแลระบบที่เคยทำงานดูแลฐานข้อมูล Oracle คงเคยเจอกับปัญหาการเชื่อมต่อไปยังฐานข้อมูลไม่ได้ ซึ่งเมื่อไล่เรียงหาสาเหตุแล้ว ก็มีมากมายหลายสาเหตุด้วยกัน เช่น ปัญหาที่ตัวฐานข้อมูลเอง หรือ ปัญหาทางด้านระบบเครือข่าย ฯลฯ ซึ่งในบทความนี้จะเล่าถึงประสบการณ์ที่ได้พบเจอปัญหานี้เช่นกัน โดยสาเหตุนั้นเกี่ยวกับตัว Listener

    เหตุการณ์ที่เกิดขึ้นช่วงที่พบปัญหา

    ได้รับแจ้งจากผู้ใช้ว่าไม่สามารถเข้าใช้งานระบบได้  ซึ่งเมื่อได้รับแจ้งจึงทำการตรวจสอบและพบว่าปัญหาเกิดจากการที่ระบบไม่สามารถเชื่อมต่อไปยังฐานข้อมูลที่พัฒนาด้วย Oracle ได้ โดยที่ระบบเครือข่ายยังใช้งานได้ปกติ ดังนั้นสิ่งที่ทำต่อมาคือการตรวจสอบเฉพาะฐานข้อมูลว่าเกิดปัญหาอะไรขึ้น โดยสิ่งที่ทำคือ

    • ทดลองเชื่อมต่อผ่าน SQL Developer ซึ่งเป็นเครื่องมือหนึ่งที่ใช้สำหรับบริหารจัดการฐานข้อมูล Oracle ผลลัพธ์คือ ไม่สามารถเชื่อมต่อได้ โดยมีข้อความแจ้งเตือนว่า socket timeout
    • ทดลองเชื่อมต่อผ่าน Enterprise Manager ซึ่งเป็นเครื่องมือสำหรับบริหารจัดการฐานข้อมูลอีกตัวซึ่งได้ติดตั้งมาพร้อมกับตอนที่สร้างฐานข้อมูล  ซึ่งก็ไม่สามารถเชื่อมต่อได้เช่นกัน และได้ลองสั่ง Startup DB ฐานข้อมูล จากเครื่องมือตัวนี้ อาการผิดปกติก็ยังคงเหมือนเดิม
    • ทดลองเชื่อมต่อผ่าน ผ่าน SQL Plus ซึ่งใช้งานผ่าน command prompt  ปราฏว่าสามารถเชื่อมต่อได้
    • ใช้คำสั่ง expdp เพื่อ dump ข้อมูลมาสำรองไว้ก่อน  สามารถทำได้เช่นกัน
    • แสดงว่าตัวฐานข้อมูลยังสามารถเข้าถึงได้อยู่ จึงพุ่งประเด็นไปที่ Listener เพราะเป็นตัวกลางที่จัดการให้ระบบหรือเครื่องมือภายนอกสามารถเชื่อมต่อมายังฐานข้อมูลได้
    • ทดลอง config Listener ใหม่ ด้วยเครื่องมือ Net Configuration Assistant พบว่าใช้เวลาตั้งค่านานมาก แต่ก็สามารถ config ได้
    • ลอง restart Listener และ Windows แล้ว อาการยังเหมือนเดิม
    • ใช้คำสั่งบน command prompt ที่เกี่ยวกับ Listener ได้แก่ lsnrctl และ tnsping เพื่อตรวจสอบ Listener และ TNS พบว่าใช้เวลานานมาก จึงสันนิษฐานว่า อาจจะเป็นปัญหาที่ Listener แน่นอน เพราะยังเข้าถึงฐานข้อมูลผ่านช่องทางบางช่องทางได้

    การแก้ไขปัญหา

    • เมื่อได้ข้อมูลจากการตรวจสอบแล้ว ว่ามีปัญหาจาก Listener จึงได้ค้นข้อมูลใน internet เกี่ยวกับการเชื่อมต่อ Listener ที่ใช้เวลานาน พบว่ามีผู้แนะนำให้ตรวจสอบที่ไฟล์ listener.log ใน \app\Administrator\diag\tnslsnr\Win-User\listener\trace (ตัวอย่างนี้จะเป็น path ที่เป็น oracle 11)
      ***หมายเหตุ โฟลเดอร์ Win-User เป็นโฟลเดอร์ที่ต้ังตามชื่อ user ใน Windows
    • ถ้าขนาดไฟล์ถึง 4 GB จะมีปัญหาได้ ให้ทำการหยุด service ของ Listener แล้ว rename ชื่อไฟล์ listener.log  ใหม่ เมื่อ start listener แล้ว ไฟล์ listener.log ก็จะถูกสร้างมาใหม่
    • เมื่อได้ทำการตรวจสอบพบว่าไฟล์มีขนาด 4 GB จริง และได้ทำการแก้ไขตามวิธีที่มีการแนะนำ พบว่าสามารถเชื่อมต่อกับฐานข้อมูล Oracle ได้เป็นปกติ
    • สำหรับกรณีศึกษาที่มีผู้นำเสนอไว้สามารถเข้าดูได้ผ่าน URL https://vjdba.wordpress.com/2013/09/24/93/
  • การสร้างฟอร์มกรอกข้อมูลใน Word

    เราอาจจะสร้างฟอร์มเพื่อส่งให้ผู้อื่นกรอกเอกสาร ตามฟอร์มที่เราออกแบบไว้ โดยจะต้องไปเรียกใช้ Develper ที่แถบ Ribbon โดยไปที่เมนู File –> Options –> Customize Ribbon เลือก Develper ดังรูป

    จะเห็นว่ามีแถบ Developer ปรากฏอยู่

    เรามาเริ่มสร้างฟอร์มกัน ในที่นี้จะสร้างฟอร์มเล็ก ๆ ดังรูป

    จากนั้นคลิกแถบ Developer แต่ละ Control ที่จะนำมาใช้ แต่ละตัวทำหน้าที่อะไรบ้าง

    • หมายเลข 1 เป็นข้อความที่สามารถจัดรูปแบบได้
    • หมายเลข 2 เป็นข้อความที่กรอกอิสระ
    • หมายเลข 3 เป็นการแทรกรูปภาพ
    • หมายเลข 4 เป็นฟิลด์รายการที่มีตัวเลือก สามารถเลือกได้
    • หมายเลข 5 เป็นการแทรกฟิลด์แบบมีตัวเลือก เช่นเดียวกับหมายเลข 4
    • หมายเลข 6 เป็นรูปแบบวันที่ให้เลือก

     

    จากนั้นเมื่อเรารู้จักหน้าที่ของแต่ละ Control แล้ว เราก็เลือกใช้ให้ตรงกับความต้องการ โดยในส่วนของตำแหน่ง เราจะใช้ Combo box เมื่อคลิก Combo box  1 ครั้งให้ไปเลือกที่ Properties จากนั้นจะปรากฏดังรูป

    เมื่อเรียบร้อยแล้วจะได้ดังรูป

    เพื่อป้องกันการแก้ไขข้อความหัวข้อ คือให้กรอกได้เฉพาะข้อมูลที่มีช่องให้กรอกเท่านั้น โดยไปที่แถบ Developer –> Restrict Editing จะแสดงดังรูป

    จากนั้นที่ข้อ 2 ให้ติ๊กเลือกและกำหนดเป็น Filling in forms เพื่อป้องกันการแก้ไขข้อความ แล้วคลิกปุ่ม “Yes, Start Enforcing Protection” จะแสดง Dialog ดังรูป

    ระบุ Password ที่จะใช้ป้องกันการแก้ไขข้อความ จากนั้นคลกปุ่ม “OK” จากนั้นลองไปคลิกที่หัวข้อจะไม่สามารถแก้ไขข้อความได้ จะแก้ไข/กรอกได้เฉพาะที่ให้กรอกข้อมูลนั้น

     

     

     

     

     

     

  • เขียน PHP ใน wordpress

    1. สิ่งที่ต้องมี ไซต์ wordpress และ user ที่สามารถติดตั้งและใช้งาน Plugins ได้ ส่วนใหญ่คือ user ที่มีสิทธิ administrator
    2. ติดตั้ง Plugins ชื่อ PHP Code snippets (จริง ๆ Plugins ที่ทำหน้าที่นี้มีหลายตัว แต่ใช้ตัวนี้มานานแล้ว) แล้วเปิดการใช้งานให้เรียบร้อย

      PHP Code snippets
      PHP Code snippets
    3. เมื่อติดตั้งและเปิดใช้แล้วจะมีเมนู PHP snippets ปรากฏขึ้นที่แถบด้านซ้ายมือ

      PHP snippets
      PHP snippets
    4. เมื่อคลิกที่ PHP snippets จะได้ดังรูป (แต่อันนี้จะมี code ของผู้เขียนอยู่แล้วสาม code)

      PHP snippets
      PHP snippets
    5. คลิก Add snippet เพื่อสร้าง code

      PHP Snippet
      New Code
    6. ใส่ชื่อ code ในช่องแรก และใส่ code PHP ในช่องที่สอง

      PHP snippet
      Coding
    7. คลิก Where there is a shortcode เพื่อให้ code ทำงานเฉพาะหน้าที่มีการระบุ  shortcode แต่หากต้องการให้ code นี้ทำงานทุกหน้าสามารถคลิกที่ Run everywhere และสามารถเขียนคำอธิบายได้ในช่อง  Description

      PHP snippet
      Run at
    8. คลิก Publish เพื่อเปิดการใช้งาน code คลิก snippet เพื่อดูสถานะ ถ้าได้ดังรูปแปลว่า code ถูกเปิดใช้งานแล้ว

      PHP snippet
      Code status activated
    9. ถ้าต้องการปิดไม่ให้ code ทำงานสามารถคลิกปุ่ม Deactivate ได้

      PHP snippet
      Code status deactivated
    10. วิธีเรียกใช้งานให้สร้าง Pages หรือ Posts แล้วนำ shortcode ไปใส่ไว้ shortcode สามารถดูได้ในช่อง  Where use? ตัวอย่าง
    11. จาก code นี้ถ้าเรียกหน้า https://licensing.psu.ac.th/login โดย user ที่ยังไม่ login จะ redirect ไปหน้า login ก่อน
    12. จบขอให้สนุก

     

  • Download multiple files as Zip Archive (Compressed) file in ASP.Net MVC

    ในบทความนี้จะขอกล่าวถึงการ  download file ครั้งละหลายๆไฟล์ โดยมีการระบุว่าต้องการ   download file ใดบ้าง โดย  ผู้ใช้สามารถกดเลือกได้ทั้งละหลายๆไฟล์ หรือไฟล์เดียว แล้วแต่ความต้องการของผู้ใช้งาน โดยหลังจากที่มีการกดปุ่มแล้วระบบจะทำการ zip ไฟล์รวมเป็น 1 ไฟล์ โดยในบทความนี้จะขอเสนอวิธีการพัฒนาโดยใช้ ASP.NET  ในรูปแบบ MVC ค่ะ

     

     

    ในส่วนของ java script

    function DownloadFiles() {

    var items = [];

    $(“input:checkbox[name=chkThis]:checked”).each(function () {

    items.push($(this).val());

     

    });

     

    if (items.length <= 0) {

    alert(‘กรุณาเลือกข้อมูลที่ต้องการ Download ด้วยค่ะ/ครับ!!’);

    }

    else {

    $.ajax({

    type: ‘POST’,

    contentType: ‘application/json; charset=utf-8’,

    url: ‘@Url.Action(“DownloadAndZipFile”, “NoteUpload”)’,

    data: JSON.stringify({ fileItemsAll: items }),

    success: function (resultDownload) {

    //window.location = ‘/NoteUpload/Download?fileGuid=’ + resultDownload.FileGuid

    //                   + ‘&filename=’ + resultDownload.FileName;

    window.location = ‘/NoteUpload/Download?fileGuid=’ + resultDownload.FileGuid;

    },

    error: function (data) {

    alert(data);

    }

    });

    }

    //   return items;

    }

    ในส่วนของ controller

    public ActionResult DownloadAndZipFile(IEnumerable<int> fileItemsAll)

    {

    if (!(ViewBag.IsAuthorized = (azResult = azService.Authorize(AccountingOperation.NoteUploadReader, this).Result).IsAuthorize))

    {

    Danger(string.Format(“ไม่มีสิทธิ์ใช้งานในส่วนนี้: {0} ({1})”, azResult.Operation.OP_NAME, Convert.ToString(azResult.OperationEnum)));

    return View();

    }

     

    string handle = Guid.NewGuid().ToString();

    MemoryStream output = new MemoryStream();

     

    var zipMs = new MemoryStream();

    string strZipName = “Accounting” + DateTime.Now.ToString(“yyyyMMdd”);

     

    TempData[handle] = fileItemsAll;

     

    var resultDownload = new { FileGuid = handle, FileName = strZipName + “.zip” };

    return this.Json(resultDownload, JsonRequestBehavior.AllowGet);

    }

     

    public FileResult Download(string fileGuid)

    {

    if (!(ViewBag.IsAuthorized = (azResult = azService.Authorize(AccountingOperation.NoteUploadReader, this).Result).IsAuthorize))

    {

    Danger(string.Format(“ไม่มีสิทธิ์ใช้งานในส่วนนี้: {0} ({1})”, azResult.Operation.OP_NAME, Convert.ToString(azResult.OperationEnum)));

    return null;

    }

     

    var zipMs = new MemoryStream();

    string zipFisYear, zipPeriod, fileC, FileF, FileFinance, fileID, fileNameZip = null;

     

    if (TempData[fileGuid] != null)

    {

    using (ZipFile zip = new ZipFile())

    {

    foreach (var item in TempData[fileGuid] as IEnumerable<int>)

    {

    var dataItemSelect = db.NoteUploadViews.Where(g => g.ID == item).FirstOrDefault();

    var financeID = db.FinanceBudgets.Where(g => g.FINANCE_BUDGET_ID == dataItemSelect.FINANCE_BUDGET_ID).FirstOrDefault();

    zipFisYear = dataItemSelect.FISCAL_YEAR_ID.ToString();

    zipPeriod = dataItemSelect.QUARTER.ToString();

     

    var dataORG = db.Organizations.Where(g => g.ORG_ID == dataItemSelect.ORG_ID && g.FISCAL_YEAR_ID == dataItemSelect.FISCAL_YEAR_ID).FirstOrDefault();

    fileC = Right(“000” + dataORG.ORG_ID, 3);

    FileF = Right(“000” + dataItemSelect.ORG_ID, 3);

    FileFinance = Right(“000” + financeID.FINANCE_ID.ToString(), 3);

    zipFisYear = Right(“0000” + dataItemSelect.FISCAL_YEAR_ID.ToString(), 4);

    zipPeriod = dataItemSelect.QUARTER.ToString();

    fileNameZip = zipFisYear + zipPeriod + “.zip”; //JAR+ Format for Zip name = FiscalYear|PeriodID >> 25601

     

    var fileType = dataItemSelect.FILE_TYPE;

    var fileNameInzip = fileC + FileF + FileFinance + dataItemSelect.ID.ToString() + “.” + fileType;  //JAR+  Format for  File Name = Campus|Fac|Finance|ID >> C01F010031

     

    byte[] fileDatas = (byte[])dataItemSelect.FILE_DATA;

     

    zip.AddEntry(fileNameInzip, fileDatas);

    }

     

    zip.Save(zipMs);

     

    byte[] fileData = zipMs.GetBuffer();

    zipMs.Seek(0, SeekOrigin.Begin);

     

    zipMs.Flush();

    Response.Clear();

    Response.AddHeader(“content-disposition”, “attachment;filename=” + fileNameZip);

    Response.BinaryWrite(fileData);

    Response.End();

    }

    }

     

    return File(zipMs, “application/zip”);

    }

    จากตัวอย่างข้างต้นจะเห็นว่าในปัจจุบัน มีความต้องการไม่น้อยที่จะ download ไฟล์หลายๆไฟล์ แล้วรวมเป็นไฟล์เดียว เพื่อความสะดวกในการจัดเก็บข้อมูล และวิธีการพัฒนาก็ไม่ได้ยุ่งยาก ผู้เขียนจึงหวังเป็นอย่างยิ่งว่าจะเป็นประโยชน์ไม่มากกว่าน้อยสำหรับผู้พัฒนาในรูปแบบ MVC นะคะ

     

     

     แหล่งอ้างอิง

    https://www.aspsnippets.com/Articles/Download-multiple-files-as-Zip-Archive-Compressed-file-in-ASPNet-MVC.aspx

    https://www.carlrippon.com/zipping-up-files-from-a-memorystream/

  • การบริหารโครงการโดยใช้เครื่องมือ Team Foundation Server (Phase 4 : การวางแผนงาน)

    จาก บทความ “การบริหารโครงการโดยใช้เครื่องมือ Team Foundation Server (Phase 3 : ขั้นตอนการคัดเลือกความต้องการ และความหมายของ State)” ทำให้เราทราบแล้วว่าในรอบการพัฒนา (Sprint) เราจะต้องดำเนินการตามความต้องการ หรือ Backlog item ใดบ้างแล้วนั้น ต่อไปเราจะมาดูเรื่องการกำหนดทรัพยากรบุคคล และมอบหมายงานต่อไป


    ขั้นตอนการกำหนดทรัพยากรบุคคล ที่จะมาทำโครงการ

    เป็นขั้นตอนของการสร้าง Team และการเลือกคนเข้ามาอยู่ในทีมนั้นเอง ซึ่งแต่ละโครงการทีมงานอาจจะเป็นคนละคนกันได้ ในการสร้าง Team และกำหนดบุคลากร สามารถดำเนินการได้ตามขั้นตอนดังนี้

    จาก TFS เลือก หมายเลข 1 ตามรูปที่ 1

    รูปที่ 1

    ทำการสร้าง Team โดยทำตามขั้นตอนตามรูปที่ 2

    รูปที่ 2

    จะปรากฎหน้าจอ เพื่อให้ใส่ข้อมูลรายละเอียดต่างๆ เกี่ยวกับข้อมูล Team ที่จะสร้าง ดังรูปที่ 3

    รูปที่ 3

    โดย

    หมายเลข 1 คือ ชื่อของ Team ที่ต้องการเพิ่ม

    หมายเลข 2 รายละเอียดเพิ่มเติม เกี่ยวกับ Team

    หมายเลข 3 ประเภทของการตั้ง Team เพื่อจุดประสงค์ ใด โดย TFS มีให้เลือก ดังรูปที่ 4

    รูปที่ 4

    เมื่อเราได้ Team แล้ว เราจะมา Add สมาชิก หรือทรัพยากรบุคคล ใน Team ที่สร้าง โดยทำตามขั้นตอน ในรูปที่ 5

    รูปที่ 5

    จะปรากฎหน้าจอ ดังรูปที่ 6 จากนั้น จะทำการ Add Members หรือสมาชิกในทีม โดยทำตามขั้นตอน ข้อ 1 ในรูปที่ 6

    รูปที่ 6

    จะปรากฎหน้าจอ เพื่อให้การพิมพ์ชื่อ เพื่อจะ Add Member ดังรูปที่ 7 โดยสามารถ ได้ ทีละหลายๆ คน และทำการ Save changes เพียงครั้งเดียว

    รูปที่ 7

    จากขั้นตอนนี้ เราจะได้สมาชิกในทีมที่จะมาดำเนินการโครงการ หรือทรัพยากรบุคคลที่จะมาทำให้โครงการสำเร็จนั่นเอง


    ขั้นตอนการกำหนดงานย่อย (Tasks) และมอบหมายงาน

    จากบทความก่อนหน้า นั้น เราได้มีการสร้างรอบการพัฒนา ที่เรียกว่า Sprint ไว้แล้ว และได้ตกลงกับผู้ใช้เพื่อเลือกความต้องการ หรือ Backlog items ที่จะทำให้แล้วเสร็จในรอบการพัฒนาที่สร้างไว้ ซึ่งจะทำให้เห็นว่ามีความต้องการอะไรบ้างที่จะต้องทำให้เสร็จ จากนี้ Project Manager จะต้องทำการแตกงาน หรือ Task ลงไปว่าในแต่ละ Backlog item แต่ละตัวนั้น จะมีงานย่อย หรือ Task อะไร บ้าง ซึ่ง Project Manager จะต้องวางแผนไว้ และสามารถมาบันทึกใน TFS ได้ ดังขั้นตอนต่อไปนี้

     

    จาก TFS เลือกโครงการที่ต้องการสร้าง Task ย่อย ตามหมายเลข 1 รูปที่ 8

    รูปที่ 8

    คลิกเลือก ตามรูปที่ 9 เพื่อไปสู่การบันทึก Task

    รูปที่ 9

    เมื่อทำตามขั้นตอนข้างต้น ทำการเลือก Sprint และ Backlog ในขั้นตอนที่ 1 และ 2 ของรูปที่ 10 จะได้หน้าจอเหมือนรูปที่ 10

    รูปที่ 10

    จากรูปที่ 10 จะแสดงรายละเอียดของ Backlog Items ทั้งหมด ในรอบ  Sprint 5 ที่ได้ตกลงกับผู้ใช้ แล้วว่าจะดำเนินการเรื่องใดบ้างนั่นเอง

     

    จากนั้น ให้ทำตามขั้นตอนในรูปที่ 11

    รูปที่ 11

    จากรูปที่ 11 ทำการกดเลือกหมายเลข 1 ก็จะปรากฎข้อมูลดังหน้าจอ ในรูปที่ 11 ขึ้นมา

    โดย หมายเลข 2 ด้านซ้ายสุด จะเป็นชื่อ Backlog item หรือหัวข้อความต้องการ ส่วนด้านขวา ที่อยู่ในกรอบที่เหลือง คือ Task ย่อย หรืองานย่อยที่แตกออกมาให้เห็นว่าจะต้องดำเนินการอะไรบ้าง เพื่อให้ Backlog สำเสร็จ ในหมายเลข 2 จะเป็นตัวอย่างที่ได้สร้างไว้แล้ว

     

    ในกรณีที่ต้องการสร้าง Task หรืองานย่อย ผู้เขียนขอยกตัวอย่าง ใน Backlog item ที่ เป็น “รายงาน งบกระแสเงินสด” นะค่ะ หากต้องการสร้าง Task ย่อย ให้กดที่เครื่องหมายบวก (+) ดังขั้นตอนที่ 3 ในรูปที่ 11 ค่ะ ซึ่งจะได้หน้าจอ ดังรูปที่ 12

     

    ก่อนอื่นเลย Project Manager จะต้อง List มาก่อนว่าจะมี Task ย่อย ๆ อะไรบ้าง ก่อนจะมาบันทึกใน TFS ซึ่งในกรณีนี้ สำหรับงานพัฒนาระบบ ก็จะหนีไม่พ้น ตามกระบวนการ SDLC นั่นเอง ซึ่งหลักๆ จะประกอบไปด้วย

    • Desgin and Analysis
    • Develop
    • Review Develop
    • ส่งมอบเพื่อทดสอบ
    • System Test
    • Review System Test
    • Delpyment    เป็นต้น

    รูปที่ 12

    สำหรับรูปที่ 12 เป็นตัวอย่างของการสร้าง Task โดยมีรายละเอียดดังนี้

    หมายเลข 1 : ชื่อ Task ย่อย

    หมายเลข 2 : รอบการพัฒนาที่จะให้ดำเนินการ ซึ่งจะ Default ตาม Backlog item นั้นๆ

    หมายเลข 3 : ทำการ Assign ให้ใครดำเนินการ

    หมายเลข 4 : ระยะเวลาที่มอบหมายงานให้ ซึ่งชื่อจะปรากฎตามที่ ได้ Add ไปในขั้นตอนการกำหนดทรัพยากรบุคคล

    หมายเลข 5 : เป็นขั้นตอนใด ซึ่งประกอบด้วย

    Design

    Development

    Documentation

    Requirements

    Testing

    Deployment

    หมายเลข 6 : เป็นการอธิบายรายละเอียดของ Task ว่าจะดำเนินการ หรือมีเงื่อนไขอย่างไรบ้าง

    และกดหมายเลข 7 เพื่อทำการบันทึกข้อมูล

     

    หลังจากที่ทำการบันทึกข้อมูล Task ทั้งหมดเข้าสู่ TFS เรียบร้อยแล้ว Project Manager สามารถตรวจสอบ หรือดูภาพรวม ได้ทำตามขั้นตอน ในรูปที่ 13 คือ

    ขั้นตอน 1 จาก TFS เลือก Backlog

    ขั้นตอน 2 สำหรับส่วนที่ 2 จะแสดงรายละเอียด Task ย่อยต่างๆ ในแต่ะ Backlog item ทำให้ใเห็นว่ามี Activity ใดบ้าง Assign ให้ใคร และต้องใช้เวลาเท่าไหร่

    ขั้นตอน 3 สำหรับส่วนที่ 3 แสดงให้ว่า

    Work : จำนวนชั่วโมงที่ใช้ในเวลาทำงาน

    Work By Activity : จำนวนชั่วโมงของแต่ละ Activity

    Work By Assign To : จำนวนชั่วโมงที่ได้มอบหมายให้แต่ละบุคคล

    รูปที่ 13

    ถึงตอนนี้ ก็จะทำให้เห็นปริมาณของงาน และระยะเวลาที่ต้องใช้ทั้งในภาพรวมของรอบการพัฒนานั้นๆ ภาพรวมของแต่ละ Activity และยังสามารถเห็นในภาพรวมของการมอบหมาย หรือ Assign ให้แต่ละคนภายในทีมงานด้วย


    ในครั้งต่อไป จะมาอธิบายขั้นตอนในการ บันทึกผลการปฏิบัติงาน และการติดตามงานโดยใช้เครื่องมือ TFS กันต่อนะค่ะ อย่าลืมติดตามกันนะค่ะ ขอบคุณค่า ^____^

     

  • เขียน CSS Selectors อย่างไรให้มีประสิทธิภาพ ?

    ในการเขียน css selectors นั้น เรารู้ดีว่ามี selectors แบบไหนให้เราเลือกใช้ได้บ้าง และแต่ละแบบนั้นมีวิธีการใช้งานอย่างไร แต่หลายๆ คน อาจไม่รู้ว่าการเขียน selectors ในแต่ละแบบนั้น มันมีผลต่อ performance ด้วย

     Web Browsers แบ่ง CSS Rules ออกเป็นกลุ่มๆ

    เรามาทำความเข้าใจถึงหลักการทำงานของ web browsers กันก่อน ไม่ว่าเราจะเขียน css rules อย่างไร web browsers จะแบ่ง rules ของเราออกเป็น 4 กลุ่ม ด้วยกัน ดังนี้

    • IDใช้เวลาในการหาน้อยที่สุด
    • Classใช้เวลาในการหามากกว่า ID เล็กน้อย
    • Tagใช้เวลาในการหามากกว่า Class
    • Universalใช้เวลาในการหามาก

    ซึ่งการจะดูว่า rule นี้ถูกจัดให้อยู่ในกลุ่มไหนนั้นจะดูจาก “key selector” หรือ selector ที่อยู่ขวาสุดนั่นเอง

     กลุ่ม ID

    rule ที่ถูกจัดให้อยู่ในกลุ่มนี้จะต้องมี id selector เป็น key selector

    #latest-news { }
    ul#latest-news { }
    #latest-news[title=”Latest News”] { }
    section > div > ul#latest-news:first-child { }

    จากโค้ดด้านบน จะได้ว่า rules ทั้ง 4 แบบ ถูกจัดให้อยู่ในกลุ่ม id ทั้งหมด

     กลุ่ม Class

    rule ที่ถูกจัดให้อยู่ในกลุ่มนี้จะต้องมี class selector เป็น key selector

    .list-item { }
    #latest-news .list-item { }
    div ul li.list-item { }
    ul > .list-item:hover { }

    จากโค้ดด้านบน จะได้ว่า rules ทั้ง 4 แบบ ถูกจัดให้อยู่ในกลุ่ม class ทั้งหมด

     กลุ่ม Tag

    ถ้า key selector ของ rule นั้นไม่ใช่ทั้ง id selector และ class selector ให้ดูว่ามีการระบุ tag เอาไว้หรือไม่ ถ้ามี จะถูกจัดให้อยู่ในกลุ่ม tag

    a { }
    li > a { }
    #latest-news div[class*=”post”] { }
    ul#latest-news li.list-item a:hover { }

    จากโค้ดด้านบน จะได้ว่า rules ทั้ง 4 แบบ ถูกจัดให้อยู่ในกลุ่ม tag ทั้งหมด

     กลุ่ม Universal

    หาก rule นั้นไม่ตรงกับ 3 กลุ่มข้างต้นเลย จะถูกจัดให้อยู่ในกลุ่ม universal

    * { }
    [id*=”post”] { }
    .home [class*=”entry”] { }
    form > [type=”text”] { }

    จากโค้ดด้านบน จะได้ว่า rules ทั้ง 4 แบบ ถูกจัดให้อยู่ในกลุ่ม universal ทั้งหมด

     วิธีการอ่าน CSS Rules ของ Web Browsers

    ในการดูว่า CSS Rule นี้ จะถูก apply ให้กับ html elements ใดบ้าง web browsers จะต้องทำการ “match” โดยมันจะอ่าน selectors จากขวาไปซ้าย คือจะเริ่มจาก key selector ซึ่งอยู่ทางด้านขวาสุดก่อน web browsers จะดูว่ามี elements ใดที่ match กับ selector ตัวนี้บ้าง ถ้าไม่มีเลย ก็จะหยุดไป แต่ถ้ามี มันก็จะทำการเช็คต่อโดยการเลื่อนไปยัง selector ทางซ้ายมือทีละอันๆ แล้วดูว่า elements ที่ match มาก่อนหน้านี้นั้น ยังคง match กับ selector ตัวใหม่นี้อีกหรือไม่ ถ้ายังมีอีกก็จะเลื่อนไปยัง selector ตัวต่อไปทางซ้ายอีก มันจะทำเช่นนี้ต่อไปเรื่อยๆ จนกว่าจะครบทุกๆ selectors ใน rule นั้นๆ หรือจนกว่าจะไม่เจอ elements ใดๆ ที่ตรงกับ rule นั้นๆ เลย

    หน้าเว็บของเรานั้น ก็เปรียบเเสมือนห้องเรียนห้องหนึ่ง ที่มี html elements เป็นเหมือนเด็กนักเรียนที่นั่งอยู่ในห้อง ส่วนครูนั้นก็ไม่ใช่ใครที่ไหน มันคือ web browser นั่นเอง ในการเรียนการสอน ครูก็มักจะมีการเรียกเด็กบางคนขึ้นมาตอบคำถามบ้างเป็นธรรมดา คำถามคือ เขาจะมีวิธีการจำแนกเด็กอย่างไร?

    การเขียน css rules ก็เหมือนกับการกำหนดวิธีการจำแนกเด็กนักเรียนให้กับครู การใส่ id ให้กับ element เปรียบเหมือนการเขียนป้ายชื่อของเด็กนักเรียนคนนั้นแล้วเอามาห้อยคอ ทีนี้เวลาครูจะหา ด.ช. เอ สิ่งที่ครูต้องทำก็แค่มองหาเด็กที่มีป้ายชื่อห้อยคอก่อนว่ามีใครบ้าง พอเจอแล้วก็ดูต่อว่าป้ายนั้นเขียนไว้ว่า ด.ช. เอ ใช่หรือไม่ การหา element จาก id ของ web browsers นั้นจะใช้เวลาน้อยมาก เนื่องจาก id มีได้แค่ที่เดียวเท่านั้น

    การกำหนด class ให้กับ elements ต่างๆ จะเหมือนกับการแบ่งเด็กนักเรียนออกเป็นกลุ่มๆ หากเรากำหนด class ให้กับ elements แล้วล่ะก็ web browsers จะสามารถหาตัว elements เจอได้ง่ายเหมือนกับการที่ครูมองหาเฉพาะเด็กที่แต่งชุดลูกเสือที่มีอยู่ในห้องเรียน แค่มองปราดเดียวก็ดูออกแล้ว

    ส่วนการเขียน css rule โดยใช้ tag เป็น key selector นั้นจะเหมือนกับการมองสิ่งที่เด็กนักเรียน “เป็น” วิธีนี้ web browsers จะมองหาตัว elements เหมือนกับการที่ครูมองหาเฉพาะเด็กนักเรียนที่เป็นผู้ชาย มันอาจใช้เวลาเพิ่มขึ้นนิดหน่อย แต่ก็ไม่นานมากนัก

    และสุดท้ายคือการเขียน css rule ที่อยู่ในกลุ่ม universal วิธีนี้ก็เหมือนกับการที่ครูต้องการจะหาเด็กมาเข้าร่วมการประกวดร้องเพลงในโรงเรียน เขาไม่สามารถดูภายนอกแล้วรู้ได้ทันทีว่าใครร้องเพลงเพราะบ้าง เขาจำเป็นต้องไล่ดูไปทีละคนๆ เราจะเห็นว่าวิธีนี้นั้นมี candidates เยอะมาก

    ขั้นตอนการหา elements ของ web browsers นี้เองที่จะมีเรื่องของ performance เข้ามาเกี่ยวข้อง ยิ่ง rule นั้นซับซ้อนมากเท่าไร ยิ่งใช้เวลาในการ match มากขึ้นเท่านั้น จากการทดลองของ Steve Souders เขาได้เรียงลำดับประสิทธิภาพของ selectors ในแบบต่างๆ เอาไว้ดังนี้

    1. ID – #header
    2. Class – .post
    3. Tag – div
    4. Sibling – h1 + ph1 ~ p
    5. Child – ul > li
    6. Descendant – ul li
    7. Universal – *
    8. Attribute – [type="text"]
    9. Pseudo-classes, Pseudo-elements – a:hoverp::first-letter

    จากการจัดอันดับประสิทธิภาพของ selectors ด้านบน เราจะเห็นว่า selectors ในแต่ละแบบนั้น มีประสิทธิภาพที่ต่างกัน โดย id นั้นจะใช้เวลาในการ match น้อยที่สุด ส่วน pseudo-classes และ pseudo-elements จะใช้เวลาในการ match มากที่สุด และอย่าลืมว่า web browsers นั้นอ่าน selectors จากขวาไปซ้ายทีละตัวๆ ยิ่งเขียน selectors ยาวมากเท่าไร ประสิทธิภาพก็ยิ่งลดลงมากเท่านั้น

     เขียน Selectors อย่างไรให้มีประสิทธิภาพ ?

    หลังจากที่เราเข้าใจวิธีการอ่าน css rules ของ web browsers เราจึงได้รู้ว่าการเลือกใช้ selectors นั้นมีความสำคัญ ในการเขียน selectors ให้เรายึดหลักต่อไปนี้

      อย่าเขียน Selectors เกินความจำเป็น

    อย่างที่ทุกคนทราบกันดีว่า id นั้นมีได้เพียงที่เดียวในหนึ่งหน้า ฉะนั้นหากเราจะใช้ id selector แล้ว เราไม่ควรใส่อะไรเพิ่มเข้าไปอีก

    BAD

    div#latest-news { }
    .box#latest-news { }
    .sidebar #latest-news { }

    นี่เป็นตัวอย่างการใช้ id selector ที่แย่ ในตัวอย่างแรก web browsers ทั้งหลายจะมองหา elements ที่มี id ชื่อว่า “latest-news” ก่อน เมื่อเจอแล้วก็จะดูต่อว่า element นั้นเป็น div หรือไม่ ซึ่งจริงๆ แล้ว มันไม่จำเป็นต้องเช็คอีก เพราะ id นั้นมีได้เพียงที่เดียวเท่านั้น เช่นเดียวกับตัวอย่างที่ 2 ที่จะต้องเช็คต่อว่า element นั้นมี class “box” อยู่ด้วยหรือไม่ และในตัวอย่างที่ 3 ที่แย่สุดเลยก็ว่าได้ เนื่องจากมันต้องไปไล่เช็ค ancestors ทุกตัวของ element นี้ ว่ามีตัวที่มี class “sidebar” บ้างหรือไม่

    GOOD

    #latest-news{ }

    ในทำนองเดียวกัน เราก็ไม่จำเป็นต้องใส่อะไรหน้า class อีก เพราะมันจะทำให้เสียเวลาในการ match เพิ่มโดยไม่จำเป็น

    BAD

    p.red { }

    GOOD

    .red { }

    อย่างไรก็ตาม การใส่อะไรข้างหน้า class บางทีก็มีประโยชน์เหมือนกันในเรื่องของ semantic การใช้ p.red มีข้อดีตรงมันช่วยให้เรารู้ว่า css rule นี้มีไว้เพื่อทำให้ตัวอักษรใน paragraph เป็นสีแดง หรือบางทีเราอาจจะต้องการกำหนดสไตล์สำหรับ class “red” เฉพาะที่ p element เพียงอย่างเดียวเท่านั้น

     ลดการใช้ Descendant Selector

    การใช้ descendant selector นั้นทำให้ประสิทธิภาพลดลงอย่างมาก เราจึงควรหลีกเลี่ยง

    BAD

    ul#latest-news li a {  }      /* แย่มาก */
    ul#latest-news > li > a {  }  /* ดีขึ้น แต่ก็ยังแย่อยู่ดี */

    จากตัวอย่างนี้ web browsers จะมองหา key selector ซึ่งก็คือ a ก่อน แล้วค่อยเลื่อนต่อไปทางซ้ายมือ โดยดูว่า a นั้นเป็น descendant ของ li หรือไม่ ถ้าเป็นให้ดูต่อว่า li นั้นเป็น descendant ของ #latest-news หรือไม่ และถ้ายังเป็นอีกให้ดูว่า #latest-news นั้นเป็น ul หรือไม่ การเขียน selector แบบนี้ส่งผลเสียต่อ performance เป็นอย่างมาก

    GOOD

    .latest-news-link {  }

    วิธีแก้ง่ายๆ คือการเพิ่ม class “latest-news-link” ให้กับ a ทีนี้ web browsers ก็จะสามารถหา elements นั้นๆ เจอได้อย่างรวดเร็ว แต่การเขียนแบบนี้ก็มีข้อเสียตรงที่มันจะทำให้การ maintenance ลำบากขึ้น เพราะเราอาจดูไม่ออกว่า .latest-news-link นี้เป็น link ที่อยู่ใน ul#latest-news

     ลดการใช้ CSS Rules ที่อยู่ในกลุ่ม Universal

    จริงอยู่ที่ selectors บางแบบนั้น ช่วยอำนวยความสะดวกให้เราเป็นอย่างมาก แต่บางทีมันก็ต้องแลกกับ performance ที่เสียไปเช่นเดียวกัน

    BAD

    [type=”text”] { }           /* แย่มาก */
    [class~=”input-text”] { }   /* แย่มากๆ เพราะไม่จำเป็น */

    GOOD

    input[type=”text”] { }      /* ดีขึ้นมาก */
    .input-text { }             /* ดีที่สุด */

    จะเห็นว่า css rules 2 แบบแรกนั้น ถูกจัดให้อยู่ในกลุ่ม universal เพราะใน key selector ไม่มี id, class หรือ tag เลย ทำให้ web browsers จะต้องไปไล่เช็คกับ elements ทุกตัวในหน้านั้นๆ การเขียน css rules 2 แบบหลัง เป็นวิธีที่ดีกว่า

     มันจะช้าลงสักแค่ไหนกันเชียว ?

    เชื่อเหลือเกินว่าหลายๆ คนคงอยากจะรู้ว่าการเลือกใช้ selectors โดยไม่คำนึงถึง performance เลยนั้น มันจะทำให้เว็บช้าลงขนาดไหน คำตอบคือมันไม่ใช่แค่ช้าลงเพียงไม่กี่วินาที แต่มันช้าลงเพียงแค่ไม่กี่มิลลิวินาที อ่าว ? แล้วจะเอาเรื่องนี้มาเขียนบทความทำไม !!!

    เรื่อง performance ของ css selectors นี้อาจจะเห็นผลไม่ค่อยชัดนัก เนื่องจากความเร็วของการประมวลผลในสมัยนี้นั้นเรียกได้ว่าเร็วเอามากๆ สมมติว่าเราเลือกใช้ selectors โดยเน้นไปที่ performance เป็นหลัก เมื่อลอง render ดู เราพบว่ามันใช้เวลาเพียงแค่ 400ms แต่พอเราเลือกใช้ selectors แบบตามใจตัวเอง เมื่อลอง render ดูใหม่เราอาจจะพบว่ามันใช้เวลาเพิ่มเป็น 600ms จะเห็นว่าส่วนต่างขนาด 150% นั้น ฟังดูเยอะก็จริง แต่ผู้ใช้งานนั้น อาจจะสัมผัสความต่างเพียงแค่ 200ms นี้ไม่ได้

    อย่างไรก็ตาม การเลือกใช้ selectors โดยคำนึงถึง performance นี้ จะเห็นผลได้ชัดมากขึ้นหากในหน้านั้นๆ มี html elements และ css rules อยู่เป็นจำนวนมาก นอกจากนี้ หากเว็บของเราเป็นเว็บที่เน้นในเรื่องของ performance เป็นหลักแล้วล่ะก็ การคำนึงถึง performance ของ selectors คงจะเป็นเรื่องที่มองข้ามไม่ได้

    การเลือกใช้ selectors โดยคำนึงถึง performance ก็เหมือนกับจรรยาบรรณของ developers แม้สิ่งที่เราทำนั้นผู้ใช้งานส่วนใหญ่อาจจะสัมผัสไม่ได้ก็จริง แต่อย่างน้อยก็มีหนึ่งคนที่รู้คือตัวเรานั่นเอง การปล่อยงานที่ไร้คุณภาพออกไปนั้นถือเป็นการดูถูกตัวเอง นี่เป็นสิ่งที่ไม่ควรทำ

     ความพอดี

    การคำนึงถึง performance นั้นไม่ได้แปลว่าห้ามใช้ selectors นอกเหนือจาก id, class และ tag แต่อย่างใด แต่มันหมายถึงการเขียน selectors แบบคุ้มค่า ไม่ฟุ่มเฟือย selectors แบบอื่นๆ นั้นใช้ได้ แต่ควรใช้เมื่อจำเป็นจริงๆ เท่านั้น

    บางคนอาจจะสงสัยว่า หากเราต้องการเขียน css rules ให้ render หน้าเว็บได้เร็วสุดๆ เราก็ต้องกำหนด class ให้กับ html elements ทั้งหมดในหน้านั้นเลยงั้นหรือ ? คำตอบคือ “ไม่ใช่”

    จริงอยู่ที่การทำอย่างนั้น ดูเหมือนจะทำให้ web browsers หา elements ที่ต้องการได้เร็วขึ้น แต่การใส่ class มาก “เกินไป” นั้นก็มีข้อเสียอยู่เหมือนกัน

    หากใส่ class ให้ทุกๆ elements เลย ขนาดของโค้ด html จะต้องใหญ่ขึ้นอย่างแน่นอน ซึ่งส่งผลให้ปริมาณไฟล์ที่เราต้องดาวน์โหลดมานั้นมากขึ้นตามไปด้วย การดาวน์โหลดไฟล์ส่วนต่างที่เพิ่มขึ้นมานี้ อาจใช้เวลามากกว่าเวลาที่ลดลงไปจากผลของ performance ที่ดีขึ้นเสียอีก

    นอกจากนี้ การใส่ class ให้กับทุกๆ elements อาจไม่ได้ทำให้หน้าเว็บ render ได้เร็วอย่างที่เราคิด สมมติในห้องเรียนห้องหนึ่ง มีเด็กนักเรียนนั่งอยู่เต็มไปหมด ผู้ปกครองต้องการพบลูกของเขา จึงบอกลักษณะกับครูไปว่าเด็กคนนั้นใช้กระเป๋าหนังยี่ห้อ Jacob สิ่งที่ครูต้องทำคือมองหาเด็กที่ 1. มีกระเป๋าหนัง 2. กระเป๋าหนังนั้นมียี่ห้อ Jacob หากในห้องนั้นมีเด็กเพียงไม่กี่คนที่มีกระเป๋าหนัง ครูก็จะสามารถหาเด็กที่มีกระเป๋าหนังยี่ห้อ Jacob ได้อย่างง่ายดาย ในทางกลับกัน หากเด็กในห้องนั้นมีกระเป๋าหนังกันทุกคน เท่ากับว่าครูต้องไล่ดูยี่ห้อของกระเป๋าหนังไปทีละคนๆ จนครบทั้งห้อง บางคนอาจสงสัยว่าทำไมครูไม่ตะโกนถามเด็กๆ ล่ะว่า ใครมีกระเป๋าหนังยี่ห้อ Jacob บ้าง จะได้ไม่ต้องมาเสียเวลาหา คำตอบคือ html นั้นพูดไม่ได้

     บทสรุปการเลือกใช้ CSS Selectors

    การเลือกใช้ selectors โดยคำนึงถึง performance นั้นเป็นเรื่องที่ดี และควรทำ ถึงแม้ว่าจะเห็นผลไม่ค่อยชัดนักก็ตาม อย่างไรก็ดี เราควรคำนึงถึงความเหมาะสมด้วย หากการคำนึงถึง performance ของเรานั้นไปทำให้การพัฒนาลำบากขึ้นกว่าเดิม มันก็ไม่สมเหตุสมผลเท่าไรนัก

     

    แหล่งอ้างอิง

    http://www.siamhtml.com/css-selectors-performance/

  • สร้าง Barcode แบบง่ายๆ ด้วย Word

    ถ้าพูดถึงการสร้าง Barcode ในปัจจุบันก็จะมีมากมายหลายวิธี แล้วแต่เราจะเลือกใช้ แต่สำหรับ Blog นี้ผู้เขียนจะขอแนะนำการสร้าง Barcode แบบง่ายๆ ใช้เวลาไม่นาน โดยที่เราไม่ต้องเพิ่มโปรแกรมเสริม หรือใช้โปรแกรมอื่นๆ เข้ามาช่วยเลย ขอแค่มี Microsoft Word version 2013 หรือ 2016 ในเครื่อง … เท่านี้ก็เพียงพอแล้ว 🙂

     

    มาทำความรู้จัก ระบบบาร์โค้ด (Barcode System) กันหน่อย 

    ระบบบาร์โค้ด หมายถึงการใช้สัญลักษณ์บาร์โค้ดบ่งชี้ไปยังข้อมูลตัวเลขหรือตัวอักษร และประยุกต์ต่อยอด โดยการนำตัวเลขหรือตัวอักษรเหล่านั้นบ่งชี้ไปยังสิ่งต่างๆ เช่น สินค้า (Product), วันหมดอายุ (Expiration date), บุคคล (Person), URL Website เป็นต้น ซึ่งจะมี 2 ประเภทหลักคือ 1 Dimension และแบบ 2 Dimension

     

    *สำหรับคำสั่งในการสร้างบาร์โค้ด DISPLAYBARCODE ใน Blog นี้ที่เราจะพูดถึงนั้น จะรองรับบาร์โค้ดแบบต่างๆ ดังนี้ QR, CODE128, CODE39, JPPOST, EAN, JAN, UPC, ITF14, NW7, CASE

     

    ขั้นตอนที่ 1 : เปิดโปรแกรม Word ขึ้นมา

     

     

     

     

     

     

     

     

     

     

     

    ขั้นตอนที่ 2 : กดปุ่ม Ctrl + F9 จากนั้นเราก็จะเห็นวงเล็กปิดเปิดเพิ่มเข้ามาใน Word ของเรา

     

     

     

     

     

     

     

     

     

     

     

    ขั้นตอนที่ 3 : พิมพ์คำสั่งตาม DISPLAYBARCODE ลงไปในวงเล็บ ตัวอย่างคำสั่งเช่น

    DISPLAYBARCODE “https://sis.psu.ac.th” QR \q 3

     

     

     

     

     

     

     

     

    ขั้นตอนที่ 4 : จากนั้นคลิก Alt + F9 เพื่อดูผลลัพธ์ แท่น แท๊นนน เท่านี้ก็เสร็จเรียบร้อย

     

     

     

     

     

     

     

     

     

     

     

    *ขออธิบายความหมายของแต่ละส่วนในคำสั่งสักนิดนึง เพื่อให้ผู้ใช้ได้เข้าใจง่ายขึ้น สำหรับส่วนแรก

     

    DISPLAYBARCODE   — คือคำสั่งที่เราจะใช้

    “https://sis.psu.ac.th” — เป็นข้อมูลที่เราจะใส่ในบาร์โค้ด ให้ใส่ไว้ภายในเครื่องหมาย ” ”

    QR — เป็นคำสั่งที่ระบุว่าสร้างบาร์โค้ดแบบ QR หากต้องการแบบอื่นเช่น CODE128 ก็เปลี่ยนได้

    โดยให้อิงตามรหัสบาร์โค้ดที่รองรับ

    \q 3  — เป็นการกำหนด Error correction level สำหรับใน QR code เท่านั้น

    หมายเหตุ : ระดับการแก้ไขข้อผิดพลาดของข้อมูล (Error Correction Level) คือ ความสามารถในการกู้คืนข้อมูลที่เสียหาย สามารถกำหนดได้ 4 ระดับ ดังนี้ L=7%, M=15%, Q=25%, H=30% ซึ่งการกำหนดในระดับที่สูงขึ้นจะมีผลทำให้ขนาดของ QR Code เพิ่มขึ้น

     

    เป็นยังไงกันบ้างเอ่ย ง่ายๆ ไม่กี่ขั้นตอนเองใช่มั้ย สำหรับ Blog นี้ผู้เขียนก็จะนำเสนอแบบสั้นๆ ง่ายๆ แต่หากผู้ใช้ท่านไหนต้องการศึกษาแบบละเอียด อย่างลึกซึ้งในส่วนอื่นๆเพิ่มเติมก็สามารถศึกษาเพิ่มเติมหรือดู syntax ได้ที่ MSDN.MICORSOFT

    เจอกันใหม่รอบ TOR หน้าเน้อผู้อ่านทุกคน แฮ่ …

    ขอขอบคุณแหล่งข้อมูลอ้างอิง

    • https://msdn.microsoft.com/en-us/library/hh745901%28v=office.12%29.aspx?f=255&MSPPError=-2147217396
    • https://www.scandit.com/types-barcodes-choosing-right-barcode/