ข้ามไปยังเนื้อหา

ปรัชญาการออกแบบของ NextPDF

Spec: ISO/IEC 25010 Spec: ISO 32000-2 Evidence: Design principle

หน้านี้ระบุหลักการที่ใช้เป็นเกณฑ์สำหรับทุกการตัดสินใจของ API ใน NextPDF หลักการเหล่านี้มีจำนวนน้อยโดยตั้งใจ เพราะหลักการที่จำไม่ได้ย่อมนำไปใช้ไม่ได้เมื่ออยู่ภายใต้ความกดดัน

หน้านี้เป็นหน้าที่ควรอ่านเป็นอันดับแรก หน้า Insider_ อื่นๆ แสดงให้เห็นว่าหลักการเหล่านี้ทำงานอย่างไรในจุดที่เจาะจง หน้านี้ตั้งชื่อให้หลักการเหล่านั้น เพื่อให้เข้าใจหน้าที่เหลือได้ง่ายขึ้น

PDF มีประวัติยาวนานพอที่จะมีจุดยืนของตัวเอง และเข้มงวดพอที่จะลงโทษการคาดเดา ลายเซ็นครอบคลุมไบต์เฉพาะช่วงที่ครอบคลุมไว้อย่างแม่นยำ ฟอนต์มีสองสถานะคือถูกฝังไว้หรือไม่ได้ฝังไว้ โปรไฟล์สำหรับการเก็บถาวรมีผลลัพธ์เพียงสองแบบคือผ่านหรือไม่ผ่านการตรวจสอบในอีกหลายเดือนถัดมา ต่อหน้าผู้ที่ต้องการหลักฐาน

เมื่ออินพุตคลุมเครือ ไลบรารีมีทางเลือกว่าจะคาดเดาแล้วปล่อยผ่านเงียบๆ หรือจะหยุดและแจ้งให้ทราบ ตัวเลือกแรกดูเป็นมิตรกว่าในการสาธิต แต่ก็อาจทำให้ต้องเสียค่าใช้จ่ายจากเหตุการณ์ในระบบจริงโดยไม่มีร่องรอยว่าอะไรผิดพลาด NextPDF เลือกตัวเลือกที่สอง NextPDF ยอมรับความประทับใจแรกที่ดูเป็นมิตรน้อยกว่า เพื่อแลกกับผลลัพธ์ที่ปกป้องได้ มาตรฐานคุณภาพซอฟต์แวร์เรียกการแลกเปลี่ยนนี้โดยตรงว่า พฤติกรรม fail-safe คือความสามารถของผลิตภัณฑ์ในการย้อนกลับสู่สถานะปลอดภัยเมื่อเกิดความล้มเหลว แทนที่จะทำงานต่อในสถานะที่ไม่นิยาม ( Spec: ISO/IEC 25010, §3 )

NextPDF สร้างขึ้นบนหลักการห้าข้อ เรียงตามลำดับความสำคัญดังนี้

  1. การระบุชัดเจนเหนือกว่าการอนุมานโดยปริยาย หากเจตนาเป็นเรื่องสำคัญ ต้องระบุออกมา เอนจินจะไม่อนุมานระดับลายเซ็น โหมดเอาต์พุต หรือเป้าหมายความสอดคล้องจากบริบท
  2. ล้มเหลวเร็ว ล้มเหลวให้ดัง ล้มเหลวแต่เนิ่นๆ อินพุตที่ไม่ถูกต้องจะถูกปฏิเสธก่อนที่จะเขียนไบต์ใดๆ ลงไป พร้อมข้อความที่ระบุสาเหตุ
  3. ข้อผิดพลาดคือพื้นผิวของ API ความล้มเหลวมีความเฉพาะเจาะจง มีชนิดที่กำหนด และมีบริบทแบบมีโครงสร้างติดมาด้วย — เป็นสิ่งที่ออกแบบไว้ ไม่ใช่เกิดขึ้นโดยบังเอิญ
  4. ขอบเขตถูกระบุไว้ ไม่ใช่ปล่อยให้ค้นพบเอง ทุกข้อกล่าวอ้างจะระบุขอบเขตสิ้นสุดของตน “จำเป็นแต่ไม่เพียงพอ” เป็นวลีที่ NextPDF ระบุไว้โดยเจตนา
  5. ไม่มีสิ่งใดเสื่อมลงอย่างเงียบๆ เอนจินจะไม่คืนค่าผลงานที่ถูกต้องเพียงครึ่งเดียวซึ่งดูเหมือนเสร็จสมบูรณ์

สิ่งที่เหลือทั้งหมด — fluent builder, disposable document, การกำหนดชนิดแบบเข้มงวด — ล้วนสืบเนื่องจากหลักการเหล่านี้

หลักการเหล่านี้ไม่ใช่คำขวัญ แต่ปรากฏเป็นรูปธรรมในโค้ดต้นฉบับ และเสริมกันและกัน

ตารางด้านล่างจับคู่หลักการแต่ละข้อกับจุดที่เห็นได้ในเอนจิน และต้นทุนที่จะเกิดขึ้นหากไม่มีหลักการนั้น

หลักการปรากฏใน NextPDF อย่างไรต้นทุนของการทำตรงกันข้าม
การระบุชัดเจนเหนือกว่าการอนุมานโดยปริยายsetSignature(certInfo:, level:) รับระดับ PAdES เป็นอาร์กิวเมนต์แบบมีชื่อที่จำเป็นต้องระบุ — ไม่มีระดับ “auto”เอกสารที่ลงนามด้วยโปรไฟล์ซึ่งไม่ได้กำหนดข้อผูกพันไว้ และมาถูกค้นพบในขั้นตอนตรวจสอบความถูกต้อง
ล้มเหลวเร็ว ล้มเหลวให้ดังsave() ปฏิเสธเส้นทางที่เป็น stream-wrapper หรือมี null-byte ก่อนการเรนเดอร์ การเรียก setSignature() ตามด้วย save() จะโยนข้อยกเว้นแทนที่จะสร้างไฟล์ที่ไม่ได้ลงนามการเขียนไฟล์ผ่าน path-traversal หรือ PDF ที่ “ไม่ได้ลงนามแต่เชื่อว่าลงนามแล้ว” ในคลังเอกสาร
ข้อผิดพลาดคือพื้นผิวของ APIข้อยกเว้นฐานเชิงนามธรรมหนึ่งตัว พร้อมคลาสย่อยที่มีชนิดเฉพาะเจาะจง โดยแต่ละตัวเปิดเผย getContext() แบบมีโครงสร้างสำหรับล็อกและ APMstack trace ทั่วไปและเวลาทั้งบ่ายที่เสียไปกับการคาดเดา
ขอบเขตถูกระบุไว้การตรวจสอบความสอดคล้องภายในกระบวนการจะคืนค่าผลการตรวจพบ และระบุเป็นถ้อยคำว่าคำตัดสินสุดท้ายเป็นหน้าที่ของผู้ตรวจสอบอิสระข้อสรุปแบบ “ไม่มีข้อยกเว้น ดังนั้นต้องสอดคล้องแน่นอน” ที่ผู้ตรวจสอบพิสูจน์ว่าไม่จริง
ไม่มีสิ่งใดเสื่อมลงอย่างเงียบๆเส้นทางการประทับเวลาแบบเก็บถาวรจะปฏิเสธที่จะคืนค่าโปรไฟล์ที่เขียนเพียงครึ่งเดียว แทนที่จะสร้างโปรไฟล์ที่ขาด dictionary ที่จำเป็นโปรไฟล์การตรวจสอบระยะยาวที่จริงๆ แล้วไม่ใช่โปรไฟล์ดังกล่าว แต่ไม่มีใครรู้

เมื่ออ่านหลักการเหล่านี้รวมกัน จุดยืนหนึ่งเดียวจะปรากฏชัด นั่นคือ เอนจินยอมตอบว่า “ไม่ได้” อย่างซื่อตรง มากกว่าจะตอบว่า “อาจจะ” อย่างมั่นใจ นี่ไม่ใช่การมองโลกในแง่ร้าย แต่เป็นการตระหนักว่า PDF มักใช้เป็นเอกสารทางกฎหมาย และเอกสารทางกฎหมายที่ผิดพลาดเลวร้ายยิ่งกว่าเอกสารที่ไม่เคยถูกสร้างขึ้นเลย

หน้านี้เป็นข้อความแบบ Evidence: Design principle กล่าวคือ หลักการเหล่านี้เป็นการตัดสินใจในการออกแบบโดยเจตนา สนับสนุนด้วยเหตุผลมากกว่าผลการวัด ในกรณีที่หลักการหนึ่งมีชื่อเรียกในสาขาความรู้ภายนอก หน้านี้จะอ้างอิงชื่อนั้น เพื่อให้เหตุผลไม่เป็นเพียงความเห็นภายในองค์กรเท่านั้น

  • จุดยืนที่ว่า “ปฏิเสธแทนที่จะทำงานต่อในสถานะที่ไม่นิยาม” คือคุณสมบัติด้านคุณภาพแบบ fail-safe ใน Spec: ISO/IEC 25010 §3 — ผลิตภัณฑ์ที่พาตัวเองกลับสู่สภาวะปลอดภัยเมื่อเกิดความล้มเหลว Fault tolerance ซึ่งอยู่ในตระกูลเดียวกัน คือระดับที่ระบบยังคงทำงานตามที่ตั้งใจไว้แม้จะเกิดข้อบกพร่อง NextPDF มุ่งความพยายามนั้นไปที่การตรวจจับและหยุดการทำงาน ไม่ใช่การปกปิดข้อบกพร่อง
  • จุดยืนที่ว่า “ระบุขอบเขตก่อนการนำมาใช้” คือ appropriateness recognizability ( Spec: ISO/IEC 25010, §3.26 ) หรือความสามารถในการตัดสินความเหมาะสมจากเอกสารประกอบและความประทับใจแรก
  • เหตุผลเฉพาะของ PDF ที่ทำให้ทั้งหมดนี้สำคัญคือ Spec: ISO 32000-2, §12.8 นั่นคือ byte range ของลายเซ็นปกป้องไบต์เฉพาะช่วงที่ครอบคลุมไว้อย่างแม่นยำและไม่เกินกว่านั้น ดังนั้นเอนจินที่ “หวังดี” แต่เขียนทับหรือคาดเดารอบๆ เอกสารที่ลงนามแล้วจึงไม่ได้ช่วยเหลืออะไรเลย

หลักการแต่ละข้อได้รับการสาธิตผ่านโค้ดต้นฉบับของเอนจินจริงในหน้าของแต่ละหลักการ — An API that refuses to guess และ Errors as a feature เป็นหน้าที่นำเสนอหลักฐานแบบ Evidence: Code-backed หน้านี้คือ “เพราะอะไร” ส่วนหน้าเหล่านั้น คือ “อะไร”

หลักการเหล่านี้มองเห็นได้ในโค้ดการใช้งานทั่วไปเพียงไม่กี่บรรทัด การเรียกใช้ลายเซ็นระบุเจตนาอย่างชัดเจน เอนจินจะปฏิเสธแต่เนิ่นๆ แทนที่จะสร้างสิ่งที่ทำให้เข้าใจผิด

<?php
declare(strict_types=1);
use NextPDF\Core\Document;
use NextPDF\Exception\NotImplementedException;
use NextPDF\Security\Signature\CertificateInfo;
use NextPDF\Security\Signature\SignatureLevel;
$document = Document::createStandalone();
$document->setTitle('Service Agreement 2026-0042');
$document->addPage();
$document->setFont('helvetica', '', 12);
$document->cell(0, 10, 'This agreement is configured for a PAdES signature.', newLine: true);
// Explicit beats implicit: the PAdES level is a required, named argument.
// There is no inferred or "auto" level.
$document->setSignature(
certInfo: new CertificateInfo(
certificate: $certificatePem,
privateKey: $privateKeyPem,
),
level: SignatureLevel::PAdES_B_B,
);
try {
// Fail fast, no silent degradation: rather than emit an UNSIGNED file
// that the caller believes setSignature() signed, the high-level path
// refuses and names the supported route.
$document->save('/srv/output/agreement.pdf');
} catch (NotImplementedException $e) {
// The message identifies the feature and the follow-up, not a stack
// trace: "... is not implemented in this release. <actionable follow-up>"
error_log($e->getMessage());
}

ประเด็นไม่ได้อยู่ที่กลไกของลายเซ็น หลักการสามข้อสังเกตได้ในโค้ดสั้นๆ ชิ้นเดียว นั่นคือ เจตนาถูกระบุ (level:) ความล้มเหลวเกิดขึ้นแต่เนิ่นๆ พร้อมระบุสาเหตุ และเอนจินปฏิเสธที่จะสร้างเอกสารที่จะโกหกเกี่ยวกับสถานะของตัวเอง

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

การตีความผิดอย่างที่สองคือ “การมีจุดยืน” หมายถึง “ไม่ยืดหยุ่น” ซึ่งไม่เป็นเช่นนั้น เอนจินมีจุดยืนเกี่ยวกับ ความถูกต้องและเจตนา ไม่ใช่เกี่ยวกับเอกสารของคุณ คุณยังคงควบคุมเค้าโครง เนื้อหา ฟอนต์ และโครงสร้างได้อย่างสมบูรณ์ จุดยืนเหล่านี้หมายถึงการไม่คาดเดาแทนคุณในจุดที่การคาดเดาไม่ปลอดภัย

หน้านี้ระบุเจตนาในการออกแบบ หน้านี้ไม่ใช่ข้อกำหนดด้านพฤติกรรมในตัวเอง หลักการเหล่านี้อธิบายวิธีการตัดสินใจ ไม่ใช่การรับประกันเกี่ยวกับเมท็อดใดเมท็อดหนึ่ง สัญญาที่แม่นยำของแต่ละเมท็อดอยู่ในเอกสารอ้างอิงและในหน้า Insider_ ของแต่ละเมท็อด พร้อมระดับหลักฐานของหน้านั้นๆ

หลักการเหล่านี้ก็ไม่ใช่กฎฟิสิกส์ที่ตายตัวเช่นกัน หลักการเหล่านี้เป็นลำดับความสำคัญ ซึ่งนำไปใช้โดยอาศัยวิจารณญาณ ในกรณีที่หลักการสองข้อขัดแย้งกัน (การปฏิเสธที่เข้มงวดกว่ากับค่าเริ่มต้นที่ผ่อนปรนกว่า) ลำดับความสำคัญข้างต้นคือตัวชี้ขาด โมดูลเฉพาะยังคงอาจระบุข้อยกเว้นที่มีเหตุผลไว้ในเอกสารได้ เมื่อเป็นเช่นนั้น ข้อยกเว้นดังกล่าวจะถูกบันทึกไว้ ไม่ใช่ถูกสันนิษฐานเอา

ท้ายที่สุด “หลักการออกแบบ” คือระดับหลักฐานในหน้านี้โดยเจตนา หน้านี้โต้แย้งด้วยเหตุผล หน้านี้ไม่ได้วัดประสิทธิภาพเชิงเปรียบเทียบ ข้อกล่าวอ้างที่ต้องใช้ตัวเลข การทดสอบ หรือข้อกำหนดมาสนับสนุนจะปรากฏในหน้าที่รับผิดชอบหลักฐานนั้น ไม่ใช่ในหน้านี้

  • An API that refuses to guess — หลักการเรื่องเจตนาที่ระบุชัดเจนและการล้มเหลวเร็ว ซึ่งแสดงให้เห็นกับ API จริง
  • Errors as a feature — ลำดับชั้นของข้อยกเว้นแบบมีชนิดกำหนดในฐานะพื้นผิวที่ออกแบบไว้
  • The PHP 8.4 foundations — คุณสมบัติของภาษาที่ทำให้สามารถบังคับใช้หลักการเหล่านี้ได้จริงแทนที่จะได้แต่หวัง
  • หลักการออกแบบ (ระดับหลักฐาน) — หน้าที่ข้อกล่าวอ้างเป็นการตัดสินใจในการออกแบบโดยเจตนา ซึ่งโต้แย้งจากเจตนาและมาตรฐานที่รองรับ มากกว่าจะวัดด้วยการทดสอบเชิงเปรียบเทียบหรือการทดสอบรายกรณี
  • Fail-safe — คุณสมบัติด้านคุณภาพซอฟต์แวร์ กล่าวคือ เมื่อเกิดความล้มเหลว ผลิตภัณฑ์จะย้อนกลับสู่สถานะปลอดภัยแทนที่จะทำงานต่อในสถานะที่ไม่นิยาม และเป็นเหตุผลที่ NextPDF เลือกปฏิเสธแทนที่จะคาดเดา
  • Fail fast — การปฏิเสธอินพุตที่ไม่ถูกต้องตั้งแต่จุดที่เร็วที่สุดเท่าที่จะเป็นไปได้ พร้อมสาเหตุที่ชัดเจน แทนที่จะดำเนินการต่อแล้วล้มเหลวอย่างคลุมเครือในภายหลัง
  • PAdES — PDF Advanced Electronic Signatures ซึ่งเป็นตระกูลโปรไฟล์ของ ETSI สำหรับการลงนามเอกสาร PDF (B-B, B-T, B-LT, B-LTA) มีการขยายความไว้ที่นี่เมื่อใช้ครั้งแรก ส่วนรายละเอียดเชิงลึกครอบคลุมอยู่ในหน้าว่าด้วยการลงนาม
  • จำเป็นแต่ไม่เพียงพอ — ถ้อยคำที่ใช้โดยเจตนาเมื่อการตรวจสอบภายในกระบวนการเป็นสัญญาณที่แท้จริงแต่ไม่ใช่คำตัดสินความสอดคล้อง คำตัดสินอย่างเป็นทางการเป็นหน้าที่ของผู้ตรวจสอบอิสระ