วิศวกรรมซอฟต์แวร์

ถาม - ตอบสำหรับมืออาชีพนักวิชาการและนักเรียนที่ทำงานในวงจรการพัฒนาระบบ

24
ทำไมโปรแกรมเมอร์บางคนถึงเกลียดการเป็นส่วนหนึ่งของการพัฒนา UI? [ปิด]
โปรแกรมเมอร์จำนวนมากที่ฉันพบเจอมักจะพูดว่า "เขาไม่ใช่คน UI" ความจริงก็คือการพัฒนาในปัจจุบันไม่ว่าจะเป็นเว็บ, Windows, Linux, OSX หรือการพัฒนารูปแบบอื่น ๆ ในปัจจุบันประกอบด้วยซอฟต์แวร์ที่มี UI ที่ดูดี ทำไมนักพัฒนาหลายคนถึงไม่รู้สึกว่า UI ทำงาน?

12
ภาษาการเขียนโปรแกรมใดที่สร้างบั๊กที่หายากได้น้อยที่สุด? [ปิด]
ในความเห็นของคุณว่าภาษาใดที่อนุญาตให้โปรแกรมเมอร์โดยเฉลี่ยให้คุณสมบัติการส่งออกที่มีข้อบกพร่องที่ยากต่อการค้นหาน้อยที่สุด? แน่นอนว่าเป็นคำถามที่กว้างมากและฉันสนใจคำตอบและภูมิปัญญาที่กว้างและกว้างมาก โดยส่วนตัวฉันพบว่าฉันใช้เวลาน้อยมากในการค้นหาข้อผิดพลาดที่แปลกประหลาดในโปรแกรม Java และ C # ในขณะที่รหัส C ++ มีชุดข้อผิดพลาดที่เกิดซ้ำและ Python / คล้ายคลึงกันมีชุดของตัวเองของข้อผิดพลาดทั่วไปและโง่ ๆ ในภาษาอื่น ๆ นอกจากนี้ฉันคิดว่ามันยากที่จะพิจารณาภาษาที่ใช้งานได้ในเรื่องนี้เพราะฉันไม่เคยเห็นโปรแกรมขนาดใหญ่และซับซ้อนที่เขียนด้วยรหัสการทำงานทั้งหมด โปรดป้อนข้อมูลของคุณ แก้ไข: การชี้แจงข้อผิดพลาดที่หายากโดยพลการอย่างสมบูรณ์: ใช้เวลามากกว่า 15 นาทีในการสร้างซ้ำหรือมากกว่า 1 ชั่วโมงเพื่อค้นหาสาเหตุและการแก้ไข ยกโทษให้ฉันหากนี่เป็นสิ่งที่ซ้ำกัน แต่ฉันไม่พบสิ่งใดในหัวข้อเฉพาะนี้

22
คุณเขียน 'clean code' หรือไม่ [ปิด]
ฉันได้เห็นโปรแกรมเมอร์บางคน tweaking รหัสของพวกเขาซ้ำแล้วซ้ำอีกไม่เพียง แต่จะทำให้มัน 'ทำงานได้ดี' แต่ยังทำให้มันดูดี ' IMO 'รหัสสะอาด' เป็นคำชมที่ระบุว่ารหัสของคุณนั้นสง่างามเข้าใจและบำรุงรักษาได้อย่างสมบูรณ์แบบ และความแตกต่างนั้นเกิดขึ้นเมื่อคุณต้องเลือกระหว่างโค้ดที่น่าดึงดูดใจและน่าดู ดังนั้นจำนวนของคุณเขียน 'รหัสสะอาด' จริง ๆ ? เป็นการปฏิบัติที่ดีหรือไม่? ประโยชน์หรือข้อเสียอื่น ๆ ของสิ่งนี้คืออะไร

16
ทำไมความนิยมกับงูหลาม? [ปิด]
นอกเหนือจากการถูกรบกวนที่ช่องว่างในฐานะที่เป็นไวยากรณ์ฉันไม่ได้เกลียดฉันเพียงไม่ได้รับความหลงใหลกับงูหลาม ฉันขอขอบคุณบทกวีของ Perl และมีโปรแกรมบริการเว็บที่สวยงามในทุบตีและ korn และ gnuplotshebang ฉันเขียนเอกสารtroffและไม่สนใจ REXX ไม่พบว่ามีประโยชน์อีกหลายปีที่ผ่านมา แต่สิ่งที่มีขนาดใหญ่เกี่ยวกับงูหลาม ? ฉันเห็นรายการงานและผู้สมัครหลายคนพร้อมสิ่งนี้เป็นรางวัล & ถ้วยรางวัลสำหรับประวัติย่อของพวกเขา ฉันเดาในความเป็นจริงฉันพยายามที่จะขายตัวเองในเรื่องนี้ฉันไม่สามารถหาเหตุผลได้
54 python  perl  bash 

1
มิกซ์อินหรือลักษณะนิสัยดีกว่าการรับมรดกหลายแบบธรรมดาอย่างไร
C ++ มีการสืบทอดหลายแบบธรรมดาการออกแบบหลายภาษานั้นห้ามมิให้มีอันตราย แต่ภาษาบางภาษาเช่น Ruby และ PHP ใช้ไวยากรณ์แปลก ๆ เพื่อทำสิ่งเดียวกันและเรียกว่า mixins หรือลักษณะ ฉันได้ยินมาหลายครั้งแล้วว่ามิกซ์อิน / คุณลักษณะนั้นยากต่อการทารุณมากกว่าการถ่ายทอดทางพันธุกรรมที่หลากหลาย อะไรที่ทำให้พวกเขามีอันตรายน้อยลง? มีบางสิ่งที่เป็นไปไม่ได้สำหรับ mixins / traits แต่เป็นไปได้ด้วย C ++ - กำหนดลักษณะการสืบทอดหลาย ๆ แบบ? เป็นไปได้ที่จะพบปัญหาเพชรกับพวกเขาหรือไม่? ดูเหมือนว่าเราใช้มรดกหลายอย่าง แต่เพียงแค่แก้ตัวว่ามันเป็นส่วนผสม / คุณลักษณะเพื่อให้เราสามารถใช้มันได้

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

11
วิธีปฏิบัติที่คล่องตัว: การตรวจสอบโค้ด - การตรวจสอบล้มเหลวหรือแจ้งปัญหา
ในตอนท้ายของการวิ่ง 2 สัปดาห์และงานหนึ่งมีการตรวจสอบโค้ดในการตรวจสอบเราค้นพบฟังก์ชั่นที่ใช้งานได้ แต่อ่านได้ค่อนข้างนานและมีโค้ดไม่กี่กลิ่น งาน refactor ง่าย มิฉะนั้นงานที่เหมาะกับความหมายของการทำ เรามีสองทางเลือก การตรวจสอบรหัสล้มเหลวเพื่อให้ตั๋วไม่ได้ปิดในการวิ่งครั้งนี้และเราได้รับความนิยมอย่างมากเนื่องจากเราไม่สามารถผ่านตั๋วได้ refactor เป็นงานชิ้นเล็ก ๆ และจะทำในการวิ่งครั้งต่อไป (หรือแม้กระทั่งก่อนที่มันจะเริ่ม) เป็นเรื่องเล็กจุดครึ่ง คำถามของฉันคือ: มีปัญหาหรือข้อพิจารณาใด ๆ เกี่ยวกับการเพิ่มตั๋วจากด้านหลังของการตรวจทานแทนที่จะล้มเหลวหรือไม่? แหล่งข้อมูลที่ฉันสามารถค้นหาและอ่านบทวิจารณ์โค้ดรายละเอียดได้ 100% หรือไม่มีอะไรปกติ แต่ฉันพบว่าโดยปกติแล้วจะไม่เหมือนจริง

4
ประโยชน์ในการพัฒนาของการใช้ Docker เป็นโมฆะเมื่อใช้ Java เมื่อเปรียบเทียบกับภาษาอื่น ๆ ใกล้กับระบบปฏิบัติการ Unix หรือไม่?
ฉันมีเพื่อนที่พูดว่า: นักเทียบท่าเป็นที่น่าอัศจรรย์ คุณสามารถใช้มันเพื่อทำซ้ำการผลิตและนิสัยใจคอของมันทั้งหมดในเครื่องท้องถิ่นของคุณ จากนั้นคุณสามารถปรับใช้อินสแตนซ์ที่ตรงผ่านทุกขั้นตอนการทำงานการแสดงละครซุปเปอร์รวดเร็ว ตอนนี้สิ่งนี้จะเป็นจริงถ้านักพัฒนาเขียน Ruby, PHP หรือGo - ที่ซึ่งมีการเชื่อมโยงแบบไบนารีทิศทางไปยังระบบปฏิบัติการ แต่เมื่อใช้Java - มีเลเยอร์เสมือนระหว่างระบบปฏิบัติการและภาษาอยู่แล้วทำให้การดำเนินงานสอดคล้องกันโดยไม่คำนึงถึงระบบปฏิบัติการพื้นฐาน ในกรณีนี้ประโยชน์ของการรัน Docker สำหรับนักพัฒนาในท้องถิ่นเพื่อทำซ้ำสภาพแวดล้อมการผลิตจะถูกทำให้ไร้ผล (เทียบกับ Ruby, PHP หรือ Go) ฉันเปิดให้มีการอภิปรายเกี่ยวกับเรื่องนี้และกระตือรือร้นที่จะได้ยินมุมมองที่ไม่เห็นด้วย (มีหลักฐาน) ประโยชน์ในการพัฒนาของการใช้ Docker เป็นโมฆะเมื่อใช้ Java เมื่อเปรียบเทียบกับภาษาอื่น ๆ ใกล้กับระบบปฏิบัติการ Unix หรือไม่?
53 java  deployment  jvm  docker 

7
มันเป็นการปฏิบัติที่ไม่ถูกต้องหรือไม่ที่จะไม่ลบไฟล์ซ้ำซ้อนทันทีจาก VCS แต่ให้ทำเครื่องหมายว่า "จะถูกลบ" ด้วยความคิดเห็นก่อน?
ฉันต้องการทราบว่าวิธีจัดการกับไฟล์ต้นฉบับที่ต้องลบออกจากการควบคุมเวอร์ชันอาจถือได้ว่าเป็นการปฏิบัติที่ไม่ดีหรือไม่ ฉันต้องการอธิบายให้คุณตามตัวอย่าง: เมื่อเร็ว ๆ นี้ฉันโกรธมากเพราะฉันต้องคัดแยกคลาส Java ในโปรแกรมที่มีรหัสตายโดยทั่วไป แต่มันไม่มีเอกสารและไม่ได้แสดงความคิดเห็นในคลาส Java เหล่านั้น แน่นอนว่าพวกเขาต้องถูกลบ แต่ก่อนที่ฉันจะลบสิ่งที่ซ้ำซ้อนฉันมี - บางคนอาจพูดว่าแปลก - นิสัย: ฉันจะไม่ลบไฟล์ที่ซ้ำซ้อนดังกล่าวทันทีผ่านทาง SVN-> ลบ (แทนที่ด้วยคำสั่งลบของระบบควบคุมเวอร์ชันที่คุณเลือก) แต่ให้ใส่ความคิดเห็นในไฟล์เหล่านั้นแทน (ฉันอ้างอิงทั้งที่หัวและท้ายกระดาษ) ว่าพวกเขากำลังจะไป ถูกลบ + ชื่อของฉัน + วันที่และ - ที่สำคัญกว่า - ทำไมพวกเขาถึงถูกลบ (ในกรณีของฉันเพราะพวกเขาตายรหัสสับสน) จากนั้นฉันบันทึกและส่งไปยังการควบคุมเวอร์ชัน ครั้งต่อไปเมื่อฉันต้องคอมมิต / เช็คอินบางอย่างในโปรเจ็กต์ถึง version control ฉันกด SVN-> Delete จากนั้นพวกมันก็จะถูกลบใน Version Control - ซึ่งแน่นอนว่ายังคงสามารถเรียกคืนผ่านการแก้ไขได้ ทำไมต้องทำเช่นนี้แทนที่จะลบออกทันที เหตุผลของฉันคือฉันต้องการมีเครื่องหมายอย่างชัดเจนอย่างน้อยที่สุดในการแก้ไขครั้งล่าสุดซึ่งมีไฟล์ที่ซ้ำซ้อนเหล่านั้นอยู่ทำไมพวกเขาจึงสมควรถูกลบ หากฉันลบทันทีพวกเขาจะถูกลบ …

10
ทำไมภาษา OOP แบบคงที่ที่สำคัญจึงป้องกันการสืบทอดดั้งเดิม
ทำไมตกลงนี้และคาดว่าส่วนใหญ่: abstract type Shape { abstract number Area(); } concrete type Triangle : Shape { concrete number Area() { //... } } ... ขณะนี้ไม่เป็นไรและไม่มีใครบ่น: concrete type Name : string { } concrete type Index : int { } concrete type Quantity : int { } แรงจูงใจของฉันคือการเพิ่มการใช้ระบบประเภทเพื่อการตรวจสอบความถูกต้องเวลารวบรวม PS: ใช่ฉันได้อ่านเรื่องนี้แล้วการห่อเป็นงานที่ยุ่งเหยิง

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

9
การเปลี่ยนแปลงไม่ได้จะคุ้มค่ามากหรือไม่เมื่อไม่มีการเห็นพ้องด้วย?
ดูเหมือนว่าความปลอดภัยของเธรดมักถูกกล่าวถึงบ่อยครั้งว่าเป็นประโยชน์หลักของการใช้ประเภทที่ไม่เปลี่ยนรูปและโดยเฉพาะอย่างยิ่งคอลเลกชัน ฉันมีสถานการณ์ที่ฉันต้องการตรวจสอบให้แน่ใจว่าวิธีการจะไม่แก้ไขพจนานุกรมสตริง (ซึ่งไม่เปลี่ยนรูปใน C #) ฉันต้องการ จำกัด สิ่งต่าง ๆ ให้มากที่สุด อย่างไรก็ตามฉันไม่แน่ใจว่าการเพิ่มการพึ่งพาแพ็คเกจใหม่ (Microsoft Immutable Collections) นั้นคุ้มค่าหรือไม่ ประสิทธิภาพไม่ใช่ปัญหาใหญ่เช่นกัน ดังนั้นฉันเดาว่าคำถามของฉันคือการแนะนำให้สะสมอย่างไม่เปลี่ยนรูปแบบเมื่อไม่มีข้อกำหนดเรื่องประสิทธิภาพการทำงานที่หนักหน่วงและไม่มีปัญหาเรื่องความปลอดภัยของเธรดหรือไม่? พิจารณาความหมายที่มีค่า (ตามตัวอย่างของฉัน) อาจจะใช่หรือไม่ใช่ข้อกำหนดก็ได้เช่นกัน

14
เมื่อใดที่การทดสอบประเภทตกลง
การสมมติภาษาที่มีความปลอดภัยบางประเภท (เช่นไม่ใช่จาวาสคริปต์): ด้วยวิธีการที่ยอมรับได้SuperTypeเรารู้ว่าในกรณีส่วนใหญ่นั้นเราอาจถูกล่อลวงให้ทำการทดสอบประเภทเพื่อเลือกการกระทำ: public void DoSomethingTo(SuperType o) { if (o isa SubTypeA) { o.doSomethingA() } else { o.doSomethingB(); } } โดยปกติเราควรสร้างวิธีการ overridable เดียวSuperTypeและไม่ควรทำเช่นนี้เสมอ: public void DoSomethingTo(SuperType o) { o.doSomething(); } ... นั้นแต่ละประเภทย่อยจะได้รับการdoSomething()ดำเนินการของตัวเอง ส่วนที่เหลือของโปรแกรมของเรานั้นจะสามารถเหมาะสมไม่รู้ว่าใดก็ตามSuperTypeเป็นจริงหรือSubTypeASubTypeB ยอดเยี่ยม แต่เรายังคงได้รับis aการปฏิบัติเหมือนในภาษาส่วนใหญ่ถ้าไม่ใช่ทั้งหมด และนั่นแสดงให้เห็นถึงความต้องการที่อาจเกิดขึ้นสำหรับการทดสอบประเภทที่ชัดเจน ดังนั้นในสถานการณ์ใดบ้างถ้ามีควรเราหรือต้องเราดำเนินการทดสอบประเภทอย่างชัดเจน? ให้อภัยการขาดสติหรือขาดความคิดสร้างสรรค์ ฉันรู้ว่าฉันเคยทำมาก่อน แต่เมื่อนานมาแล้วฉันจำไม่ได้ว่าสิ่งที่ฉันทำดีหรือไม่! และในความทรงจำเมื่อเร็ว ๆ นี้ฉันไม่คิดว่าฉันจะต้องทดสอบประเภทนอกจาวาสคริปต์ของฉัน

9
ทำไมไม่เปิดเผยคีย์หลัก
ในการศึกษาของฉันฉันได้รับแจ้งว่าเป็นความคิดที่ไม่สมบูรณ์ที่จะเปิดเผยคีย์หลักที่แท้จริง (ไม่เพียง แต่คีย์ DB แต่ผู้เข้าถึงหลักทั้งหมด) ให้กับผู้ใช้ ฉันคิดเสมอว่าเป็นปัญหาด้านความปลอดภัย (เพราะผู้โจมตีสามารถพยายามอ่านสิ่งที่ไม่ใช่ของตนเอง) ตอนนี้ฉันต้องตรวจสอบว่าผู้ใช้ได้รับอนุญาตให้เข้าถึงหรือไม่มีเหตุผลอื่นอีกหรือไม่ นอกจากนี้เนื่องจากผู้ใช้ของฉันต้องเข้าถึงข้อมูลต่อไปฉันจะต้องมีรหัสสาธารณะสำหรับโลกภายนอกที่ใดที่หนึ่ง ตอนนี้รหัสสาธารณะมีปัญหาเช่นเดียวกับคีย์หลักใช่ไหม มีการร้องขอตัวอย่างเกี่ยวกับสาเหตุที่ทำเช่นนั้นดังนั้นนี่คือตัวอย่าง โปรดจำไว้ว่าคำถามนั้นมีความหมายเกี่ยวกับหลักการนั้นไม่เพียง แต่จะนำไปใช้ในตัวอย่างนี้เท่านั้น คำตอบที่กล่าวถึงสถานการณ์อื่น ๆ ยินดีต้อนรับอย่างชัดเจน แอปพลิเคชัน (เว็บมือถือ) ที่จัดการกิจกรรมมี UIs หลายตัวและอย่างน้อยหนึ่ง API อัตโนมัติสำหรับการสื่อสารระหว่างระบบ (eG แผนกบัญชีต้องการทราบว่าจะเรียกเก็บเงินจากลูกค้ามากน้อยเพียงใดจากสิ่งที่ทำ) แอปพลิเคชันมีลูกค้าหลายรายดังนั้นการแยกข้อมูลของพวกเขา (อย่างมีเหตุผลข้อมูลจะถูกเก็บไว้ในฐานข้อมูลเดียวกัน) เป็นสิ่งที่ต้องมีในระบบ คำขอแต่ละรายการจะถูกตรวจสอบความถูกต้องไม่ว่าจะเกิดอะไรขึ้น กิจกรรมนั้นละเอียดมากดังนั้นมันจึงอยู่รวมกันในวัตถุคอนเทนเนอร์บางตัวให้เรียกมันว่า "งาน" สาม usecases: ผู้ใช้ A ต้องการส่งผู้ใช้ B ไปยังงานบางอย่างดังนั้นเขาจึงส่งลิงก์ (HTTP) ให้เขาเพื่อให้กิจกรรมเสร็จสิ้นที่นั่น ผู้ใช้ B ต้องออกไปข้างนอกอาคารเพื่อเปิด Task บนอุปกรณ์มือถือ การบัญชีต้องการเรียกเก็บเงินจากลูกค้าสำหรับงาน แต่ใช้ระบบบัญชีบุคคลที่สามที่โหลดงาน / กิจกรรมโดยอัตโนมัติด้วยรหัสบางอย่างที่อ้างถึง …

5
ภาษาที่มีประเภทบางทีแทนที่จะเป็นค่าศูนย์จะจัดการกับเงื่อนไขของขอบได้อย่างไร
เอริค Lippert ทำให้เป็นจุดที่น่าสนใจมากในการอภิปรายของเขาว่าทำไม C # ใช้nullมากกว่าMaybe<T>ประเภท : ความสอดคล้องของระบบพิมพ์เป็นสิ่งสำคัญ เราจะรู้ได้หรือไม่ว่าการอ้างอิงที่ไม่เป็นโมฆะนั้นไม่เคยภายใต้สถานการณ์ใด ๆ สิ่งที่เกี่ยวกับในตัวสร้างของวัตถุที่มีเขตข้อมูลที่ไม่เป็นโมฆะประเภทการอ้างอิง? สิ่งที่เกี่ยวกับใน finalizer ของวัตถุดังกล่าวที่วัตถุจะเสร็จสมบูรณ์เพราะรหัสที่ควรจะกรอกในการอ้างอิงโยนข้อยกเว้น? ระบบการพิมพ์ที่อยู่กับคุณเกี่ยวกับการรับประกันเป็นสิ่งที่อันตราย นั่นเป็นสิ่งที่เปิดตา แนวคิดเกี่ยวข้องกับฉันและฉันได้เล่นกับคอมไพเลอร์และระบบพิมพ์ แต่ฉันไม่เคยคิดถึงเรื่องนั้น ภาษาที่มีประเภทอาจจะเป็นอย่างไรแทนที่จะเป็นกรณีที่จับขอบโมฆะเช่นการเริ่มต้นและการกู้คืนข้อผิดพลาดซึ่งในความเป็นจริงการอ้างอิงที่ไม่ใช่โมฆะรับประกันไม่จริงในสถานะที่ถูกต้อง?

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