“ ตัวแปรควรอยู่ในขอบเขตที่เล็กที่สุดเท่าที่จะเป็นไปได้” หรือไม่รวมถึง“ ตัวแปรที่ไม่ควรมีอยู่หากเป็นไปได้”?


32

ตามคำตอบที่ยอมรับได้ใน " เหตุผลที่ต้องการตัวแปรท้องถิ่นมากกว่าตัวแปรอินสแตนซ์? " ตัวแปรควรอยู่ในขอบเขตที่เล็กที่สุดเท่าที่จะเป็นไปได้
ลดความซับซ้อนของปัญหาในการตีความของฉันซึ่งหมายความว่าเราควรปรับโครงสร้างโค้ดประเภทนี้อีกครั้ง:

public class Main {
    private A a;
    private B b;

    public ABResult getResult() {
        getA();
        getB();
        return ABFactory.mix(a, b);
    }

    private getA() {
      a = SomeFactory.getA();
    }

    private getB() {
      b = SomeFactory.getB();
    }
}

เป็นอะไรเช่นนี้:

public class Main {
    public ABResult getResult() {
        A a = getA();
        B b = getB();
        return ABFactory.mix(a, b);
    }

    private getA() {
      return SomeFactory.getA();
    }

    private getB() {
      return SomeFactory.getB();
    }
}

แต่ตามตัวแปร "จิตวิญญาณ" ของ "ควรอยู่ในขอบเขตที่เล็กที่สุดเท่าที่จะทำได้" ไม่ใช่ "ไม่เคยมีตัวแปร" มีขอบเขตที่เล็กกว่า "มีตัวแปร" ดังนั้นฉันคิดว่าเวอร์ชันด้านบนควรได้รับการปรับโครงสร้างใหม่:

public class Main {
    public ABResult getResult() {
        return ABFactory.mix(getA(), getB());
    }

    private getA() {
      return SomeFactory.getA();
    }

    private getB() {
      return SomeFactory.getB();
    }
}

ดังนั้นมันจึงgetResult()ไม่มีตัวแปรในตัวเลย มันเป็นเรื่องจริงเหรอ?


72
การสร้างตัวแปรที่ชัดเจนมาพร้อมกับประโยชน์ของการตั้งชื่อพวกเขา การแนะนำตัวแปรบางตัวสามารถเปลี่ยนวิธีทึบแสงให้กลายเป็นตัวแปรที่อ่านได้อย่างรวดเร็ว
Jared Goguen

11
สุจริตตัวอย่างในแง่ของชื่อตัวแปร a และ b มีการวางแผนเกินไปที่จะแสดงให้เห็นถึงคุณค่าของตัวแปรท้องถิ่น โชคดีที่คุณได้รับคำตอบที่ดีอยู่แล้ว
Doc Brown

3
ในตัวอย่างที่สองของคุณตัวแปรของคุณไม่ได้จริงๆตัวแปร พวกเขาเป็นค่าคงที่ในพื้นที่ได้อย่างมีประสิทธิภาพเพราะคุณไม่ได้แก้ไข คอมไพเลอร์ Java จะปฏิบัติต่อพวกเขาเหมือนกันหากคุณกำหนดไว้เป็นครั้งสุดท้ายเนื่องจากอยู่ในขอบเขตท้องถิ่นและคอมไพเลอร์รู้ว่าจะเกิดอะไรขึ้นกับพวกเขา เป็นเรื่องของสไตล์และความคิดเห็นหากคุณควรใช้finalคำหลักจริงหรือไม่
ไฮด์

2
@JaredGoguen การสร้างตัวแปรที่ชัดเจนมาพร้อมกับภาระในการตั้งชื่อพวกเขาและประโยชน์ของความสามารถในการตั้งชื่อพวกเขา
Bergi

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

คำตอบ:


110

ไม่มีสาเหตุหลายประการ:

  1. ตัวแปรที่มีชื่อที่มีความหมายสามารถทำให้เข้าใจรหัสได้ง่ายขึ้น
  2. การแบ่งสูตรที่ซับซ้อนออกเป็นขั้นตอนเล็ก ๆ จะทำให้การอ่านรหัสง่ายขึ้น
  3. แคช
  4. ถือการอ้างอิงไปยังวัตถุเพื่อให้สามารถใช้มากกว่าหนึ่งครั้ง

และอื่น ๆ


22
นอกจากนี้ยังควรกล่าวถึง: มูลค่าจะถูกเก็บไว้ในหน่วยความจำโดยไม่คำนึงถึงดังนั้นจึงสิ้นสุดด้วยขอบเขตเดียวกันอย่างไรก็ตาม อาจตั้งชื่อด้วย (สำหรับเหตุผลที่ Robert กล่าวถึงข้างต้น)!
อาจจะ_Factor

5
@Maybe_Factor แนวทางไม่ได้อยู่ที่นั่นเพราะเหตุผลด้านประสิทธิภาพ มันเกี่ยวกับความง่ายในการดูแลรักษาโค้ด แต่นั่นก็หมายความว่าคนในท้องถิ่นที่มีความหมายดีกว่าการแสดงออกอันยิ่งใหญ่เพียงครั้งเดียวเว้นแต่ว่าคุณจะเขียนฟังก์ชั่นที่มีชื่อและออกแบบมาอย่างดี (เช่นไม่มีเหตุผลที่จะทำvar taxIndex = getTaxIndex();)
Luaan

16
ล้วนเป็นปัจจัยสำคัญ ดูผมวิธีที่มัน: ความกะทัดรัดเป็นเป้าหมาย; ความคมชัดเป็นอีก; ความทนทานเป็นอีก ประสิทธิภาพเป็นอีก; และอื่น ๆ สิ่งเหล่านี้ไม่ได้เป็นเป้าหมายที่แน่นอนและบางครั้งก็ขัดแย้งกัน ดังนั้นงานของเราคือหาวิธีที่จะทำให้เป้าหมายเหล่านั้นสมดุล
gidds

8
คอมไพเลอร์จะดูแล 3 & 4
หยุดการทำร้ายโมนิก้า

9
หมายเลข 4 อาจมีความสำคัญต่อความถูกต้อง หากค่าของการเรียกใช้ฟังก์ชันสามารถเปลี่ยน (เช่นnow()) ลบตัวแปรและเรียกวิธีการมากกว่าหนึ่งครั้งสามารถทำให้เกิดข้อบกพร่อง สิ่งนี้สามารถสร้างสถานการณ์ที่บอบบางและยากต่อการแก้ไข มันอาจดูชัดเจน แต่ถ้าคุณอยู่ในภารกิจการเปลี่ยนโครงสร้างคนตาบอดเพื่อลบตัวแปรมันง่ายที่จะจบลงด้วยการแนะนำข้อบกพร่อง
JimmyJames

16

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

ฉันไม่เห็นประโยชน์ของตัวแปรaและbในตัวอย่างของคุณดังนั้นฉันจะเขียนเวอร์ชันที่ไม่มีตัวแปร ในทางกลับกันฟังก์ชั่นนั้นง่ายมากในตอนแรกฉันไม่คิดว่ามันสำคัญมาก

มันจะกลายเป็นปัญหามากขึ้นฟังก์ชั่นอีกต่อไปได้รับและตัวแปรเพิ่มเติมอยู่ในขอบเขต

ตัวอย่างเช่นถ้าคุณมี

    a=getA();
    b=getB();
    m = ABFactory.mix(a,b);

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

แน่นอนในกรณีที่ตัวแปรเป็นสิ่งที่จำเป็น (เช่นการจัดเก็บผลชั่วคราว) หรือในกรณีที่ตัวแปรไม่ปรับปรุงการอ่านรหัสที่แล้วมันควรจะเก็บไว้


2
แน่นอนโดยวิธีการที่ใช้เวลานานจนจำนวนคนในท้องถิ่นมีขนาดใหญ่เกินไปที่จะบำรุงรักษาได้ง่ายคุณอาจต้องการทำลายมัน
Luaan

4
เกี่ยวกับประโยชน์ของตัวแปร "ภายนอก" เช่นvar result = getResult(...); return result;เป็นที่คุณสามารถใส่เบรกพอยต์ในreturnและเรียนรู้สิ่งที่แน่นอนresultคือ
Joker_vD

5
@Joker_vD: ผู้ดีบักที่สมควรใช้ชื่อควรสามารถให้คุณทำสิ่งนั้นได้ทั้งหมด (ดูผลลัพธ์ของการเรียกใช้ฟังก์ชันโดยไม่เก็บไว้ในตัวแปรโลคัล + ตั้งค่าเบรกพอยต์เมื่อออกจากฟังก์ชัน)
Christian Hackl

2
@ChristianHackl debugges น้อยมากให้คุณทำโดยไม่ต้องตั้งค่านาฬิกาที่ซับซ้อนที่อาจต้องใช้เวลาในการเพิ่ม (และถ้าฟังก์ชั่นที่มีผลข้างเคียงอาจทำลายทุกอย่าง) ฉันจะใช้กับรุ่นตัวแปรสำหรับการแก้จุดบกพร่องทุกวันในสัปดาห์
Gabe Sechan

1
@ChristianHackl และสร้างต่อไปแม้ว่าผู้ดีบักเกอร์จะไม่ปล่อยให้คุณทำตามค่าเริ่มต้นเพราะ debugger ได้รับการออกแบบมาอย่างน่ากลัวคุณสามารถแก้ไขรหัสท้องถิ่นบนเครื่องของคุณเพื่อจัดเก็บผลและตรวจสอบได้ในตัวดีบัก . ยังคงมีเหตุผลที่จะเก็บค่าในตัวแปรไม่เพียงวัตถุประสงค์ที่
The Great Duck

11

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

ตัวแปรคลาสที่กำหนดขอบเขต (อินสแตนซ์หรือสแตติก) มีเส้นทางการไหลของการควบคุมที่เป็นไปได้อย่างมีนัยสำคัญมากกว่าตัวแปรที่มีการกำหนดขอบเขตแบบโลคัลเนื่องจากสามารถเปลี่ยนแปลงโดยวิธีการซึ่งสามารถเรียกได้ในลำดับใด ๆ จำนวนครั้งใด ๆ .

ลองมาดูgetResultวิธีการเริ่มต้นของคุณ:

public ABResult getResult() {
    getA();
    getB();
    return ABFactory.mix(this.a, this.b);
}

ตอนนี้ชื่อgetAและgetBอาจแนะนำว่าพวกเขาจะกำหนดให้this.aและthis.bเราไม่สามารถรู้ได้อย่างแน่นอนgetResultจากเพียงแค่มองที่ ดังนั้นจึงเป็นไปได้ที่ค่าthis.aและthis.bค่าที่ส่งเข้ามาในmixเมธอดแทนที่จะมาจากสถานะของthisวัตถุจากก่อนหน้าgetResultนี้ถูกเรียกใช้ซึ่งไม่สามารถคาดการณ์ได้เนื่องจากลูกค้าควบคุมวิธีและวิธีการที่เรียกว่า

ในโค้ดที่ได้รับการแก้ไขด้วยโลคอลaและbตัวแปรเป็นที่ชัดเจนว่ามีการควบคุมโฟลว์ (ยกเว้นข้อยกเว้น) หนึ่งชุดจากการกำหนดตัวแปรแต่ละตัวให้กับการใช้งานเนื่องจากตัวแปรจะถูกประกาศก่อนที่จะถูกใช้

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

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

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


2

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

(reduce (fn [map string] (assoc map string (inc (map string 0))) 

หรือบาง LINQ:

var query2 = mydb.MyEntity.Select(x => x.SomeProp).AsEnumerable().Where(x => x == "Prop");

หรือNode.js:

 return visionFetchLabels(storageUri)
    .then(any(isCat))
    .then(notifySlack(secrets.slackWebhook, `A cat was posted: ${storageUri}`))
    .then(logSuccess, logError)
    .then(callback)

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

อย่างไรก็ตามความแตกต่างระหว่างตัวอย่างแรกและอีกสองเป็นคำสั่งโดยนัยของการดำเนินงาน สิ่งนี้อาจไม่เหมือนกับคำสั่งที่คำนวณจริง แต่เป็นลำดับที่ผู้อ่านควรพิจารณา สำหรับสองสองนี้จากซ้ายไปขวา สำหรับตัวอย่างเสียงกระเพื่อม / Clojure มันเหมือนขวาไปซ้าย คุณควรระวังการเขียนโค้ดที่ไม่ได้อยู่ใน "ทิศทางเริ่มต้น" สำหรับภาษาของคุณและควรใช้นิพจน์ "มิดออก" ที่ผสมผสานทั้งสองอย่างแน่นอน

ตัวดำเนินการไพพ์ของ F # |>มีประโยชน์ส่วนหนึ่งเพราะช่วยให้คุณสามารถเขียนสิ่งที่ซ้ายไปขวาที่มิฉะนั้นจะต้องเป็นจากขวาไปซ้าย


2
ฉันใช้เพื่อขีดเส้นใต้เป็นชื่อตัวแปรของฉันในการแสดงออกง่าย LINQ หรือ lambdas myCollection.Select(_ => _.SomeProp).Where(_ => _.Size > 4);
เกรแฮม

ไม่แน่ใจว่านี่เป็นคำตอบของคำถาม OP ในระดับน้อยที่สุด ...
AC

1
ทำไมต้องลงคะแนน ดูเหมือนจะเป็นคำตอบที่ดีสำหรับฉันแม้ว่าจะไม่ได้ตอบคำถามโดยตรง แต่ก็ยังเป็นข้อมูลที่มีประโยชน์
reggaeguitar

1

ฉันจะบอกว่าไม่เพราะคุณควรอ่าน "ขอบเขตที่เล็กที่สุดเท่าที่จะเป็นไปได้" เป็น "ในขอบเขตที่มีอยู่หรือรายการที่มีเหตุผลที่จะเพิ่ม" มิฉะนั้นจะเป็นการบอกเป็นนัยว่าคุณควรสร้างขอบเขตเทียม (เช่น{}บล็อกแบบไม่มีค่าใช้จ่ายในภาษา C-like) เพียงเพื่อให้แน่ใจว่าขอบเขตของตัวแปรจะไม่ขยายเกินกว่าการใช้งานที่ตั้งใจไว้ครั้งสุดท้ายและโดยทั่วไปแล้วจะขมวดคิ้ว เหตุผลที่ดีสำหรับขอบเขตที่จะมีอยู่อย่างอิสระ


2
ปัญหาหนึ่งในการกำหนดขอบเขตในหลายภาษาคือมันเป็นเรื่องธรรมดามากที่จะมีตัวแปรบางตัวที่การใช้งานล่าสุดอยู่ในการคำนวณค่าเริ่มต้นของตัวแปรอื่น ๆ หากภาษามีโครงสร้างอย่างชัดเจนเพื่อวัตถุประสงค์ในการกำหนดขอบเขตซึ่งอนุญาตให้ค่าที่คำนวณโดยใช้ตัวแปรขอบเขตภายในที่จะใช้ในการเริ่มต้นของขอบเขตนอกขอบเขตนั้นขอบเขตดังกล่าวอาจมีประโยชน์มากกว่าขอบเขตที่เข้มงวดหลายภาษาที่ต้องการ
supercat

1

พิจารณาฟังก์ชั่น ( เมธอด ) มันไม่มีการแบ่งรหัสในภารกิจย่อยที่เล็กที่สุดเท่าที่จะเป็นไปได้

มันเป็นข้อ จำกัด ในการขยับที่มีการแบ่งงานตรรกะออกเป็นชิ้นส่วนสิ้นเปลือง

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

boolean automatic = true;
importFile(file, automatic);

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


1

อะไรที่ขาดหายไปเนื่องจากเหตุผลของ NO คือการดีบั๊ก / การอ่านข้อมูล รหัสควรได้รับการปรับให้เหมาะสมและชื่อที่ชัดเจนและรัดกุมช่วยได้มากเช่นลองนึกภาพ 3 วิธีถ้า

if (frobnicate(x) && (get_age(x) > 2000 || calculate_duration(x) < 100 )

บรรทัดนี้สั้น แต่อ่านยากแล้ว เพิ่มพารามิเตอร์อีกสองสามและถ้าครอบคลุมหลายบรรทัด

can_be_frobnicated = frobnicate(x)
is_short_lived_or_ancient = get_age(x) > 2000 || calculate_duration(x) < 100
if (can_be_frobnicated || is_short_lived_or_ancient )

ฉันพบว่าวิธีนี้ง่ายต่อการอ่านและสื่อสารความหมาย - ดังนั้นฉันจึงไม่มีปัญหากับตัวแปรกลาง

อีกตัวอย่างหนึ่งคือภาษาเช่น R โดยที่บรรทัดสุดท้ายจะเป็นค่าส่งคืนโดยอัตโนมัติ:

some_func <- function(x) {
    compute(x)
}

สิ่งนี้เป็นอันตรายหรือไม่จำเป็นต้องส่งคืนสิ่งตอบแทนหรือไม่ ชัดเจนยิ่งขึ้น:

some_func <- function(x) {
   rv <- compute(x)
   return(rv)
}

และเช่นเคยนี่คือการเรียกใช้วิจารณญาณ - กำจัดตัวแปรตัวกลางหากพวกเขาไม่ปรับปรุงการอ่านมิฉะนั้นจะคงไว้หรือแนะนำพวกเขา

อีกจุดหนึ่งที่สามารถ debuggability ได้: หากผลลัพธ์ของคนกลางนั้นเป็นที่น่าสนใจก็ควรที่จะแนะนำคนกลางเช่นในตัวอย่าง R ด้านบน ความถี่นี้เรียกได้ว่าเป็นเรื่องยากที่จะจินตนาการและระวังสิ่งที่คุณตรวจสอบ - ตัวแปรการดีบักที่มากเกินไปทำให้เกิดความสับสน - อีกครั้งการเรียกการตัดสินใจ


0

อ้างถึงเพียงชื่อของคุณ: แน่นอนถ้าตัวแปรไม่จำเป็นก็ควรจะถูกลบ

แต่“ ไม่จำเป็น” ไม่ได้หมายความว่าสามารถเขียนโปรแกรมที่เทียบเท่าได้โดยไม่ต้องใช้ตัวแปรมิฉะนั้นเราจะได้รับการบอกว่าเราควรเขียนทุกอย่างในรูปแบบไบนารี่

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

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

การอ่านรหัสนั้นสำคัญกว่าทุกอย่างยกเว้นการทำงานอย่างถูกต้อง (รวมถึงเกณฑ์ประสิทธิภาพที่ยอมรับได้ซึ่งมักจะ“ เร็วที่สุดเท่าที่จะทำได้”)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.