การใช้“ ใหม่” ในตัวสร้างไม่ดีเสมอหรือไม่


37

ฉันได้อ่านว่าการใช้ "ใหม่" ในคอนสตรัคเตอร์ (สำหรับวัตถุอื่นที่ไม่ใช่วัตถุที่มีค่าอย่างง่าย) นั้นเป็นวิธีที่ไม่ดีเนื่องจากทำให้การทดสอบหน่วยเป็นไปไม่ได้ เนื่องจากฉันไม่ได้มีประสบการณ์จริงในการทดสอบหน่วยฉันพยายามรวบรวมกฎที่ฉันจะเรียนรู้ก่อน นอกจากนี้นี่เป็นกฎที่ใช้ได้โดยทั่วไปไม่ว่าจะใช้ภาษาใด


9
มันไม่ทำให้การทดสอบเป็นไปไม่ได้ มันทำให้การบำรุงรักษาและทดสอบรหัสของคุณยากขึ้น มีการอ่านใหม่คือกาวตัวอย่างเช่น
David Arno

38
"เสมอ" ไม่ถูกต้องเสมอ :) มีแนวปฏิบัติที่ดี แต่มีข้อยกเว้นมากมาย
พอล

63
นี่คือภาษาอะไร? newหมายถึงสิ่งต่าง ๆ ในภาษาต่าง ๆ
user2357112

13
คำถามนี้ขึ้นอยู่กับภาษาใช่มั้ย ไม่ใช่ทุกภาษาที่มีnewคำสำคัญ คุณถามภาษาอะไร
ไบรอัน Oakley

7
กฎโง่ ล้มเหลวในการใช้การฉีดพึ่งพาเมื่อคุณควรมีน้อยมากที่จะทำกับคำหลัก "ใหม่" แทนที่จะบอกว่า "การใช้ใหม่เป็นปัญหาถ้าคุณใช้เพื่อหยุดการพึ่งพาการกลับกัน" เพียงแค่พูดว่า "อย่าทำลายการพึ่งพาอาศัยกัน"
Matt Timmermans

คำตอบ:


36

มีข้อยกเว้นอยู่เสมอและฉันมีปัญหากับคำว่า "always" ในชื่อ แต่ใช่แนวทางนี้โดยทั่วไปใช้ได้และใช้กับตัวสร้างนอกเช่นกัน

การใช้สิ่งใหม่ใน Constructor นั้นเป็นการละเมิด D ใน SOLID (หลักการผกผันของการพึ่งพาอาศัยกัน) มันทำให้โค้ดของคุณยากที่จะทดสอบเพราะการทดสอบหน่วยนั้นเกี่ยวกับการแยก มันยากที่จะแยกชั้นเรียนหากมีการอ้างอิงที่เป็นรูปธรรม

มันไม่ได้เป็นเพียงเกี่ยวกับการทดสอบหน่วยว่า ถ้าฉันต้องการชี้ที่เก็บไปยังฐานข้อมูลที่แตกต่างกันสองรายการพร้อมกัน? ความสามารถในการส่งผ่านในบริบทของฉันเองทำให้ฉันสามารถยกตัวอย่างคลังเก็บสองแห่งที่ชี้ไปยังสถานที่ต่างกัน

การไม่ใช้สิ่งใหม่ในตัวสร้างทำให้โค้ดของคุณมีความยืดหยุ่นมากขึ้น นอกจากนี้ยังใช้กับภาษาที่อาจใช้โครงสร้างอื่นนอกเหนือจากnewการเริ่มต้นวัตถุ

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

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

ยิ่งคลาสมีการอ้างอิงมากเท่าไหร่ก็ยิ่งต้องระวังไม่ให้โทรออกnewจากภายใน


12
ฉันไม่เห็นคุณค่าใด ๆ ในกฎนี้ มีกฎและแนวทางในการหลีกเลี่ยงการแต่งงานกันในรหัส กฎนี้ดูเหมือนว่าจะจัดการกับปัญหาเดียวกันแน่นอนยกเว้นว่ามัน จำกัด มากเกินไปอย่างไม่น่าเชื่อในขณะที่ไม่ให้คุณค่าเพิ่มเติมใด ๆ แก่เรา ดังนั้นประเด็นคืออะไร ทำไมจะสร้างวัตถุส่วนหัวจำลองสำหรับการใช้งาน LinkedList ของฉันแทนที่จะจัดการกับกรณีพิเศษทั้งหมดที่มาจากการhead = nullปรับปรุงโค้ด เหตุใดการปล่อยให้คอลเล็กชันรวมเป็นโมฆะและสร้างตามความต้องการจะดีกว่าการทำในตัวสร้าง
Voo

22
คุณไม่มีจุด ใช่โมดูลการคงอยู่เป็นสิ่งที่โมดูลระดับสูงกว่าไม่ควรพึ่งพา แต่ "ไม่เคยใช้ใหม่" ไม่ได้ติดตามจาก "สิ่งที่ควรฉีดและไม่ได้เชื่อมต่อโดยตรง" หากคุณนำสำเนาของการพัฒนาซอฟต์แวร์ Agile ที่เชื่อถือได้มาร์ตินกำลังพูดถึงโมดูลที่ไม่ใช่คลาสเดี่ยว: "โมดูลระดับสูงจัดการกับนโยบายระดับสูงของแอปพลิเคชันโดยทั่วไปนโยบายเหล่านี้สนใจรายละเอียดเล็กน้อยที่นำมาใช้ พวกเขา."
Voo

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

18
ฉันลงคะแนนเพราะเป็นซุปฉวัดเฉวียนมากมายและไม่พูดคุยกันมากนักเกี่ยวกับการพิจารณาในทางปฏิบัติ มีบางอย่างเกี่ยวกับ repo ถึงสอง DBs แต่โดยสุจริตนั่นไม่ใช่ตัวอย่างในโลกแห่งความจริง
jpmc26

5
@ jpmc26, BJoBnh โดยไม่ต้องไปถ้าฉันเอาผิดคำตอบนี้หรือไม่จุดจะแสดงอย่างชัดเจน หากคุณคิดว่า "หลักการผกผันของการพึ่งพา" "การอ้างอิงที่เป็นรูปธรรม" หรือ "การกำหนดค่าเริ่มต้นวัตถุ" เป็นเพียงแค่ buzzwords ดังนั้นจริงๆแล้วคุณก็ไม่รู้ว่ามันหมายถึงอะไร นั่นไม่ใช่ความผิดของคำตอบ
R. Schmitz

50

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

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


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

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


4
+1 นี่ถูกต้องแล้ว คุณต้องระบุพฤติกรรมที่ตั้งใจของชั้นเรียนและกำหนดว่าต้องมีการเปิดเผยรายละเอียดการนำไปปฏิบัติใดและไม่ควรทำอะไร มีเกมสัญชาตญาณที่ละเอียดอ่อนที่คุณต้องเล่นโดยพิจารณาว่า "ความรับผิดชอบ" ของชั้นเรียนเป็นอย่างไร
jpmc26

27

ผู้ทำงานร่วมกันทุกคนไม่น่าสนใจพอที่จะทดสอบหน่วยแยกกันคุณสามารถ (ทางอ้อม) ทดสอบพวกเขาผ่านคลาสการโฮสต์ / การสร้างอินสแตนซ์ สิ่งนี้อาจไม่สอดคล้องกับความคิดของคนบางคนที่ต้องการทดสอบในแต่ละชั้นเรียนวิธีการสาธารณะอื่น ๆ โดยเฉพาะอย่างยิ่งเมื่อทำการทดสอบหลัง เมื่อใช้ TDD คุณสามารถสร้างโครงสร้างใหม่ 'ผู้ทำงานร่วมกัน' นี้เพื่อแยกชั้นเรียนที่ผ่านการทดสอบจากกระบวนการแรกของคุณแล้ว


14
Not all collaborators are interesting enough to unit-test separatelyในตอนท้ายของเรื่อง :-), กรณีนี้เป็นไปได้และไม่มีใครกล้าพูดถึง @Joppe ฉันขอแนะนำให้คุณทำอย่างละเอียดคำตอบเล็กน้อย ตัวอย่างเช่นคุณสามารถเพิ่มตัวอย่างของคลาสที่เป็นเพียงรายละเอียดการใช้งาน (ไม่เหมาะสำหรับการแทนที่) และวิธีการแยกสามารถแยกหลังถ้าเราเห็นว่าจำเป็น
Laiv

@ แบบจำลองโดเมนของ Laiv นั้นเป็นรูปธรรมไม่ใช่แบบนามธรรมคุณไม่ต้องไปสนใจวัตถุที่ซ้อนกันที่นั่น วัตถุที่มีค่าอย่างง่าย / วัตถุที่ซับซ้อนที่ไม่มีเหตุผลอย่างอื่นก็เป็นตัวเลือก
Joppe

4
+1 แน่นอน หากมีการตั้งค่าภาษาเพื่อให้คุณต้องโทรnew File()ไปทำสิ่งใดก็ตามที่เกี่ยวข้องกับไฟล์คุณไม่จำเป็นต้องห้ามการโทรนั้น คุณจะทำอย่างไรเขียนการทดสอบการถดถอยกับFileโมดูลของ stdlib ไม่น่าเป็นไปได้ บนมืออื่น ๆ เรียกnewในตนเองคิดค้นระดับเป็นที่น่าสงสัยมากขึ้น
Kilian Foth

7
@KilianFoth: หน่วยขอให้โชคดีในการทดสอบอะไรที่โดยตรงโทรnew File()แม้ว่า
Phoshi

1
นั่นคือการคาดเดา เราสามารถค้นหากรณีที่มันไม่สมเหตุสมผลกรณีที่มันไม่มีประโยชน์และกรณีที่มันสมเหตุสมผลและเป็นประโยชน์ มันเป็นเรื่องของความต้องการและความชอบ
Laiv

13

เนื่องจากฉันไม่ได้มีประสบการณ์จริงในการทดสอบหน่วยฉันพยายามรวบรวมกฎที่ฉันจะเรียนรู้ก่อน

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

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

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


สำหรับคำถามที่แท้จริงของคุณฉันมักจะชอบวิธีการพอร์ตและอะแดปเตอร์ที่เราสร้างความแตกต่างระหว่าง "ตรรกะหลัก" และ "บริการ" (นี่คล้ายกับการแยกความแตกต่างระหว่างฟังก์ชั่นบริสุทธิ์และขั้นตอนที่มีประสิทธิภาพ)

ตรรกะหลักคือทั้งหมดที่เกี่ยวกับการคำนวณสิ่งต่าง ๆ "ภายใน" แอปพลิเคชันตามโดเมนปัญหา มันอาจจะมีการเรียนเช่นUser, Document, Order, Invoiceฯลฯ ที่ดีมันจะมีการเรียนหลักเรียกnewสำหรับการเรียนหลักอื่น ๆ ตั้งแต่ที่พวกเขากำลัง "ภายใน" รายละเอียดการปฏิบัติ ตัวอย่างเช่นการสร้างOrderอาจสร้างInvoiceและDocumentรายละเอียดสิ่งที่สั่งซื้อ ไม่จำเป็นต้องเยาะเย้ยสิ่งเหล่านี้ในระหว่างการทดสอบเพราะสิ่งเหล่านี้เป็นสิ่งที่เราต้องการทดสอบจริง!

พอร์ตและอะแดปเตอร์เป็นวิธีการที่ตรรกะหลักมีปฏิสัมพันธ์กับโลกภายนอก นี่คือสิ่งที่ชอบDatabase, ConfigFile, EmailSenderฯลฯ มีชีวิตอยู่ สิ่งเหล่านี้คือสิ่งที่ทำให้การทดสอบนั้นยากดังนั้นจึงแนะนำให้สร้างสิ่งเหล่านี้นอกตรรกะหลักและส่งผ่านตามที่ต้องการ (ไม่ว่าจะด้วยการฉีดพึ่งพาหรือเป็นวิธีการโต้แย้ง ฯลฯ )

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

พอร์ตและอะแดปเตอร์สามารถทดสอบแยกกันโดยใช้ mocks สำหรับฐานข้อมูลระบบไฟล์และอื่น ๆ โดยไม่ต้องใส่ใจกับตรรกะทางธุรกิจ เราสามารถส่งผ่านค่าตัวอย่างและตรวจสอบว่าพวกเขากำลังถูกเก็บ / อ่าน / ส่ง / ฯลฯ อย่างเหมาะสม.


6

ให้ฉันตอบคำถามโดยรวบรวมสิ่งที่ฉันคิดว่าเป็นประเด็นสำคัญที่นี่ ฉันจะอ้างอิงผู้ใช้บางคนเพื่อความกะทัดรัด

มีข้อยกเว้นอยู่เสมอ แต่ใช่กฎนี้โดยทั่วไปจะใช้ได้และใช้กับตัวสร้างภายนอกเช่นกัน

การใช้สิ่งใหม่ในนวกรรมิกละเมิดDในSOLID (การพึ่งพาการผกผันของหลักการ) มันทำให้โค้ดของคุณยากที่จะทดสอบเพราะการทดสอบหน่วยนั้นเกี่ยวกับการแยก มันยากที่จะแยกชั้นเรียนหากมีการอ้างอิงที่เป็นรูปธรรม

-TheCatWhisperer-

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

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

มีข้อยกเว้นหลักสูตรที่ชั้นเป็นค่าเปลี่ยนรูป วัตถุรายละเอียดการดำเนินการอื่น ๆที่พวกเขาควรจะคู่แน่น

- David Arno-

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

ยิ่งกว่านั้นถ้าลัทธิSOLIDของเราทำให้เราแยกชั้นเรียนเหล่านี้เราอาจละเมิดหลักการที่ดีอีกข้อหนึ่ง ที่เรียกว่ากฎหมายของ Demeter ซึ่งในทางกลับกันฉันคิดว่ามันสำคัญมากสำหรับมุมมองการออกแบบ

ดังนั้นคำตอบที่น่าจะเป็นปกติคือขึ้นอยู่กับ การใช้คอนnewสตรัคเตอร์ภายในอาจเป็นวิธีปฏิบัติที่ไม่ดี แต่ไม่เป็นระบบเสมอไป

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


1: เป้าหมายหลักของ SOLID คือไม่ให้รหัสของเราทดสอบได้มากขึ้น มันจะทำให้รหัสของเราทนต่อการเปลี่ยนแปลงมากขึ้น มีความยืดหยุ่นและเป็นผลให้ทดสอบได้ง่ายขึ้น

หมายเหตุ: David Arno, TheWhisperCat ฉันหวังว่าคุณจะไม่รังเกียจที่ฉันยกมาให้คุณ


3

เป็นตัวอย่างง่าย ๆ พิจารณา pseudocode ต่อไปนี้

class Foo {
  private:
     class Bar {}
     class Baz inherits Bar {}
     Bar myBar
  public:
     Foo(bool useBaz) { if (useBaz) myBar = new Baz else myBar = new Bar; }
}

เนื่องจากnewเป็นรายละเอียดการดำเนินบริสุทธิ์Fooและทั้งสองFoo::BarและFoo::Bazเป็นส่วนหนึ่งของFooเมื่อหน่วยทดสอบของมีจุดในส่วนของเยาะเย้ยไม่มีFoo Fooคุณจะเยาะเย้ยส่วนนอก เมื่อหน่วยทดสอบFooFoo


-3

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

แก้ไข: สำหรับ downvoters - นี่คือลิงค์ไปยังหนังสือการพัฒนาซอฟต์แวร์การตั้งค่าสถานะ 'ใหม่' เป็นกลิ่นรหัสที่เป็นไปได้: https://books.google.com/books?id=18SuDgAAQBAJ&lpg=PT169&dq=new%20keyword%20code คำที่ 20code% 20smell&pg=PT169 # v = onepage & q = ใหม่% 20keyword% 20code% 20smell & F = false


15
Yes, using 'new' in your non-root classes is a code smell. It means you are locking the class into using a specific implementation, and will not be able to substitute another.เหตุใดจึงเป็นปัญหา ไม่ใช่ทุก ๆ การพึ่งพาอาศัยกันในต้นไม้ที่พึ่งต้องเปิดเพื่อทดแทน
Laiv

4
@Paul: การใช้งานเริ่มต้นหมายความว่าคุณใช้การอ้างอิงที่ถูกผูกไว้อย่างแน่นหนากับคลาสคอนกรีตที่ระบุเป็นค่าเริ่มต้น แต่นั่นไม่ได้ทำให้มันเรียกว่า "กลิ่นรหัส"
Robert Harvey

8
@EzoelaVacca: ฉันจะระมัดระวังเกี่ยวกับการใช้คำว่า "code ดมกลิ่น" ในบริบทใด ๆ มันเหมือนกับบอกว่า "สาธารณรัฐ" หรือ "ประชาธิปัตย์" คำเหล่านั้นแปลว่าอะไร? ทันทีที่คุณให้อะไรบางอย่างกับป้ายกำกับคุณจะหยุดคิดถึงปัญหาที่แท้จริงและหยุดการเรียนรู้
Robert Harvey

4
"ยืดหยุ่นมากกว่า" ไม่ใช่ "ดีกว่า" โดยอัตโนมัติ
whatsisname

4
@EzoelaVacca: การใช้newคำหลักไม่ใช่วิธีปฏิบัติที่ไม่ดีและไม่เคยเป็นเช่นนั้น มันเป็นวิธีที่คุณใช้เครื่องมือที่สำคัญ คุณไม่ได้ใช้ค้อนขนาดใหญ่เช่นค้อนค้อนที่ใคร ๆ จะพอเพียง
Robert Harvey
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.