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

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

8
ใช้ระบบพิมพ์ที่“ แข็งแกร่ง” ในโลกแห่งความเป็นจริงพูดสำหรับเว็บแอปขนาดใหญ่หรือไม่?
ฉันรู้ว่านี่เป็นคำถามที่กว้างขวางคลุมเครือและเป็นไปได้ทางปรัชญา ในขอบเขตที่คำหลักที่สำคัญที่สุดในคำถาม - "ความเชื่อ" ระบบการพิมพ์ - ตัวเองเป็นป่วยกำหนด ดังนั้นให้ฉันพยายามอธิบายสิ่งที่ฉันหมายถึง บริบทโดยรวมของคำถาม เราได้สร้างเว็บแอปขนาดใหญ่ขึ้นใน Ruby on Rails และโดยทั่วไปเรามีความสุขกับกองซ้อนของเรา เมื่อเราต้องการเราสามารถจัดส่งสิ่งต่าง ๆ ได้อย่างรวดเร็วจริง ๆ - สิ่งที่ใช้งานได้ 90% ของคดี "ธุรกิจ" โดยไม่ต้องกังวลเรื่องขอบคดีมากถึง 10% ในทางกลับกันด้วยความช่วยเหลือในการใช้โค้ดรีวิวและทดสอบครอบคลุมเราจะช้าและพิจารณาและตรวจสอบให้แน่ใจว่าเราครอบคลุมฐานทั้งหมด - อีกครั้งเฉพาะในสถานการณ์ที่สมควรได้รับการตรวจสอบข้อเท็จจริงและความปลอดภัยอย่างใกล้ชิด อย่างไรก็ตามเมื่อทีมเติบโตขึ้นฉันเริ่มรู้สึกไม่สบายใจกับการขาด "ตาข่ายนิรภัย" ที่ถูกอบเข้าไปในกองของเรา เราเพิ่งเริ่มทำการพัฒนา Android พื้นเมืองบน Java และฉันก็นึกถึงความปลอดภัยที่จัดเตรียมโดยภาษาที่รวบรวม / คงที่ / พิมพ์ดีดอย่างยิ่ง ตัวแปรที่สะกดผิดประเภทข้อมูลที่ไม่ถูกต้องการเรียกใช้ฟังก์ชันที่ไม่ถูกต้องและโฮสต์ของข้อผิดพลาดเล็กน้อยที่ IDE ของคุณติดอยู่เอง ทั้งหมดเป็นเพราะ IDE สามารถเชื่อมต่อกับคอมไพเลอร์และตรวจสอบบางแง่มุมของโปรแกรม "ความถูกต้อง" ต้องการเปลี่ยนลายเซ็นฟังก์ชั่นหรือไม่? ง่าย. คอมไพเลอร์ …

1
คำศัพท์สำหรับฟังก์ชั่น JavaScript ที่ไม่ระบุชื่อเรียกว่าอะไรทันที
ฉันกำลังเขียนคู่มือสไตล์ JavaScript สำหรับทีมของฉันเพื่อให้เราสามารถจัดระเบียบและมีส่วนร่วมในเอกสารของเราได้ง่ายขึ้น แต่ฉันได้เจอปัญหาเล็ก ๆ น้อย ๆ ซึ่งเป็นที่ที่คำถามของฉันใช้ ... ฉันควรจะเรียกใช้ฟังก์ชัน JavaScript แบบไม่ระบุชื่อที่เรียกว่าอะไรในทันที ฉันรู้ว่าฉันสามารถเรียกมันว่า "ฟังก์ชั่นที่ไม่ระบุชื่อ" ได้ แต่ฉันอยากจะเน้นความจริงที่ว่ามันถูกเรียกใช้ทันที นี่คือตัวอย่าง: var MyVariable = (function(data){ return "another value" })("some value"); console.log(MyVariable); // "another value"

6
สร้างวัตถุใหม่หรือรีเซ็ตคุณสมบัติทั้งหมดหรือไม่
public class MyClass { public object Prop1 { get; set; } public object Prop2 { get; set; } public object Prop3 { get; set; } } สมมติว่าผมมีวัตถุmyObjectของMyClassและฉันต้องการที่จะตั้งค่าคุณสมบัติของมันก็จะดีกว่าการสร้างวัตถุใหม่หรือมอบหมายแต่ละคุณสมบัติ? สมมติว่าฉันไม่มีการใช้เพิ่มเติมใด ๆ กับอินสแตนซ์เก่า myObject = new MyClass(); หรือ myObject.Prop1 = null; myObject.Prop2 = null; myObject.Prop3 = null;

4
โอเปอเรเตอร์ที่มีเงื่อนไขแบบใหม่ของ C # 6.0 นั้นผิดกฎหมายหรือไม่?
กฎหมายของ Demeterกล่าวต่อไปนี้: แต่ละหน่วยควรมีความรู้ที่ จำกัด เฉพาะเกี่ยวกับหน่วยอื่น ๆ : เฉพาะหน่วย "อย่างใกล้ชิด" ที่เกี่ยวข้องกับหน่วยปัจจุบัน แต่ละหน่วยควรคุยกับเพื่อนเท่านั้น อย่าคุยกับคนแปลกหน้า พูดคุยกับเพื่อนของคุณทันที C # 6.0 แนะนำผู้ประกอบการใหม่ที่เรียกว่าผู้ประกอบการ null เงื่อนไข IMHO ทำให้การเข้ารหัสง่ายขึ้นและปรับปรุงความสามารถในการอ่าน แต่มันยังทำให้ง่ายต่อการเขียนรหัสคู่มากขึ้นเนื่องจากง่ายต่อการเลื่อนดูฟิลด์คลาสและตรวจสอบค่าว่าง (เช่นvar x = A?.B?.C?.D?.E?.F?) ถูกต้องหรือไม่หากระบุว่าผู้ประกอบการรายใหม่นี้ขัดต่อกฎหมายของ Demeter

3
ฝึกการควบคุมเวอร์ชันสำหรับเขียนซ้ำ
เราพัฒนาผลิตภัณฑ์ (ต้นแบบ) P_OLD ในภาษา X และตอนนี้เรากำลังเขียนมันใหม่ตั้งแต่ต้นเป็น P_NEW ในภาษา Y เนื่องจาก P_NEW และ P_OLD เป็นผลิตภัณฑ์เดียวกัน: P_NEW ควรเป็นเพียง brach ของ P_OLD เก่าหรือควรเป็นที่เก็บของมันเอง? เป็นวิธีปกติในการจัดการการเปลี่ยนแปลงครั้งใหญ่ในมุมมองการควบคุมเวอร์ชันอะไร

10
การใช้ตัวแปรพอยน์เตอร์เป็นค่าใช้จ่ายในหน่วยความจำใช่หรือไม่
ในภาษาอย่าง C และ C ++ ในขณะที่ใช้พอยน์เตอร์กับตัวแปรเราต้องการที่ตั้งหน่วยความจำอีกหนึ่งแห่งเพื่อเก็บที่อยู่นั้น ดังนั้นนี่ไม่ใช่ค่าใช้จ่ายหน่วยความจำ? สิ่งนี้ได้รับการชดเชยอย่างไร? พอยน์เตอร์ใช้ในเวลาที่แอปพลิเคชันหน่วยความจำเหลือน้อยหรือไม่?
29 c++  c  pointers 

2
เหตุใดจึงเป็นการยากที่จะสร้างโปรแกรมรุ่น 64 บิต
ในการเขียนโปรแกรมช่วงเวลาสั้น ๆ ของฉันมันเป็นเรื่องที่ไม่สำคัญที่จะรวบรวม C ++, Java และอื่น ๆ ของฉันสำหรับเครื่อง 32 หรือ 64 บิตตราบใดที่ฉันมีแหล่งข้อมูลเต็มรูปแบบสำหรับโปรแกรม แต่ซอฟต์แวร์จำนวนมากไม่ออก 64 บิต ที่น่ารำคาญที่สุดคือยังไม่มีเอ็นจิ้น Unity รุ่น 64 บิต อะไรทำให้มันยากที่จะรวบรวมบางโปรแกรมสำหรับเครื่อง 64 บิต?

6
คุณสามารถใช้การเขียนโปรแกรม "เชิงวัตถุ" โดยไม่มีคำหลักชั้น?
สมมติว่าเราต้องการให้มี "บัญชี" ที่เป็นนามธรรมในธนาคาร นี่คือวิธีหนึ่งโดยใช้functionวัตถุใน Python: def account(): """Return a dispatch dictionary representing a bank account. >>> a = account() >>> a['deposit'](100) 100 >>> a['withdraw'](90) 10 >>> a['withdraw'](90) 'Insufficient funds' >>> a['balance'] 10 """ def withdraw(amount): if amount > dispatch['balance']: return 'Insufficient funds' dispatch['balance'] -= amount return dispatch['balance'] def deposit(amount): dispatch['balance'] …

7
มีรูปแบบอัลกอริทึมในการปกป้องเนื้อหาใด ๆ ในเว็บเพื่อให้แน่ใจว่าฉันเป็นคนแรกที่สร้างมันขึ้นมาหรือไม่?
ไม่กี่ปีที่ผ่านมามีแฮ็กเกอร์คนนี้ (จำไม่ได้ว่าเขาเป็นใคร) ที่เปิดเผยช่องโหว่อย่างเต็มรูปแบบในระบบที่กำหนด แต่เพื่อให้แน่ใจว่าไม่มีใครให้เครดิตเขาเลยสร้างคีย์ PGP ขึ้นมา สิ่งที่ฉันเข้าใจในเวลานั้นคือเขาสร้างกุญแจเพื่อให้แน่ใจว่าเขาเป็นผู้ค้นพบ แต่ไม่เปิดเผยว่าเขาเป็นใครเพียงสร้างกลไกเพื่อให้สามารถพิสูจน์ได้ว่าเขาเป็นผู้สร้างการเปิดเผย . ตกลง. ฉันเข้าใจว่าอัลกอริทึมและการเข้ารหัสทำงานอย่างไร แต่ฉันยังไม่เข้าใจว่าคุณสามารถสร้างคีย์เพื่อปกป้องเนื้อหาที่เปิดเผยในเว็บเพื่อพิสูจน์ว่าคุณเป็นคนแรกที่สร้างมันขึ้นมา! มันเป็นเพียงคำพูด! เป็นไปได้จริงเหรอ? สิ่งที่ควรเป็นกระบวนการเพื่อให้แน่ใจว่าคุณสามารถพิสูจน์ได้ประจักษ์? ฉันเข้าใจถูกต้องหรือไม่ฉันอาจพลาดบางสิ่งเกี่ยวกับกรณีนี้ ฉันหวังว่าคำถามนี้มีความเฉพาะเพียงพอโดยทั่วไปเป็นเพียงวิธีการปกป้องเนื้อหาที่คุณสร้างขึ้นในเว็บ (ย่อหน้ารหัสคำ ฯลฯ ) และให้แน่ใจว่าคุณเป็นคนแรกที่สร้างขึ้นภายใน บริบทที่กำหนด ด้วยความรู้ของฉันฉันไม่เห็นว่าเป็นไปได้ แต่ฉันรู้สึกทึ่งถ้ามีวิธีการปฏิบัติที่จะทำ มีอะไรบ้าง

6
ข้อเสียเปรียบสำหรับการอนุมานประเภทคืออะไร
ดูเหมือนว่าภาษาการเขียนโปรแกรมใหม่ทั้งหมดหรืออย่างน้อยก็เป็นภาษาที่ได้รับความนิยมอย่างมาก แม้จาวาสคริปต์ก็มีประเภทและการอนุมานประเภทแม้ว่าการใช้งานที่หลากหลาย (Acscript, typescript ฯลฯ ) มันดูดีสำหรับฉัน แต่ฉันสงสัยว่ามีการแลกเปลี่ยนหรือทำไมสมมติว่า Java หรือภาษาดีเก่าไม่มีการอนุมานประเภท เมื่อประกาศตัวแปรในGoโดยไม่ระบุประเภทของมัน (ใช้ var โดยไม่มี type หรือ: = ไวยากรณ์) ชนิดของตัวแปรจะถูกอนุมานจากค่าทางด้านขวามือ Dอนุญาตให้เขียนแฟรกเมนต์โค้ดขนาดใหญ่โดยไม่ระบุชนิดซ้ำซ้อนเช่นเดียวกับภาษาไดนามิก ในทางกลับกันการอนุมานแบบคงที่จะอนุมานประเภทและคุณสมบัติของรหัสอื่น ๆ ที่ให้สิ่งที่ดีที่สุดทั้งในโลกที่คงที่และแบบไดนามิก เอ็นจิ้นการอนุมานประเภทในRustค่อนข้างฉลาด มันทำมากกว่าดูประเภทของค่า r ในระหว่างการเริ่มต้น นอกจากนี้ยังมีลักษณะการใช้ตัวแปรหลังจากนั้นอนุมานชนิดของมัน Swiftใช้การอนุมานประเภทเพื่อกำหนดประเภทที่เหมาะสม การอนุมานประเภทช่วยให้ผู้รวบรวมสามารถอนุมานประเภทของนิพจน์เฉพาะโดยอัตโนมัติเมื่อคอมไพล์โค้ดของคุณเพียงแค่ตรวจสอบค่าที่คุณให้ไว้

3
ระบบประเภททั่วไปที่ดี
เป็นที่ยอมรับกันโดยทั่วไปว่า Java generics ล้มเหลวในบางวิธีที่สำคัญ การรวมกันของ wildcard และขอบเขตทำให้รหัสบางอย่างไม่สามารถอ่านได้อย่างจริงจัง อย่างไรก็ตามเมื่อฉันดูภาษาอื่น ๆ ฉันก็ดูเหมือนจะไม่พบระบบแบบทั่วไปที่โปรแกรมเมอร์มีความสุข ถ้าเราทำสิ่งต่อไปนี้เป็นเป้าหมายการออกแบบของระบบประเภท: สร้างการประกาศประเภทที่อ่านง่ายเสมอ ง่ายต่อการเรียนรู้ (ไม่จำเป็นต้องปัดเรื่องความแปรปรวนร่วมความแปรปรวน ฯลฯ ) เพิ่มจำนวนข้อผิดพลาดในการคอมไพล์ให้สูงสุด มีภาษาใดบ้างที่ทำให้ถูกต้อง? ถ้าฉัน google สิ่งเดียวที่ฉันเห็นคือการร้องเรียนเกี่ยวกับวิธีที่ระบบประเภทดูดในภาษา X. ความซับซ้อนแบบนี้มีอยู่ในการพิมพ์ทั่วไปหรือไม่? เราควรยอมแพ้ในการพยายามตรวจสอบความปลอดภัย 100% ณ เวลารวบรวมหรือไม่? คำถามหลักของฉันคือภาษาใดที่ "เข้าใจถูกต้อง" ที่สุดด้วยความเคารพต่อเป้าหมายทั้งสามนี้ ฉันรู้ว่ามันเป็นแบบอัตนัย แต่จนถึงตอนนี้ฉันไม่สามารถหาภาษาใดภาษาหนึ่งได้ที่โปรแกรมเมอร์ไม่ใช่ทุกคนยอมรับว่าระบบประเภททั่วไปนั้นเป็นระเบียบ ภาคผนวก: ดังที่กล่าวไว้การรวมกันของการพิมพ์ย่อย / การสืบทอดและข้อมูลทั่วไปเป็นสิ่งที่สร้างความซับซ้อนดังนั้นฉันจึงกำลังมองหาภาษาที่ผสมผสานทั้งสองอย่างและหลีกเลี่ยงการระเบิดของความซับซ้อน

7
มันโอเคที่จะใช้ข้อยกเว้นเป็นเครื่องมือในการ "จับ" ข้อผิดพลาดก่อนหรือไม่?
ฉันใช้ข้อยกเว้นเพื่อตรวจสอบปัญหาก่อน ตัวอย่างเช่น: public int getAverageAge(Person p1, Person p2){ if(p1 == null || p2 == null) throw new IllegalArgumentException("One or more of input persons is null"). return (p1.getAge() + p2.getAge()) / 2; } โปรแกรมของฉันไม่ควรผ่านnullในฟังก์ชั่นนี้ ฉันไม่เคยตั้งใจที่จะ อย่างไรก็ตามในขณะที่เราทุกคนรู้ว่าสิ่งที่ไม่ได้ตั้งใจเกิดขึ้นในการเขียนโปรแกรม การโยนข้อยกเว้นหากปัญหานี้เกิดขึ้นช่วยให้ฉันสามารถตรวจสอบและแก้ไขได้ก่อนที่จะทำให้เกิดปัญหามากขึ้นในที่อื่น ๆ ในโปรแกรม ข้อยกเว้นหยุดโปรแกรมและบอกฉันว่า "มีสิ่งไม่ดีเกิดขึ้นที่นี่แก้ไขได้" แทนที่จะเป็นการnullเคลื่อนไหวรอบ ๆ โปรแกรมทำให้เกิดปัญหาที่อื่น ตอนนี้คุณพูดถูกในกรณีนี้มันอาจnullจะทำให้เกิดNullPointerExceptionในทันทีดังนั้นมันอาจไม่ใช่ตัวอย่างที่ดีที่สุด แต่ให้พิจารณาวิธีการเช่นนี้ตัวอย่างเช่น: public void registerPerson(Person person){ persons.add(person); …

3
มีข้อได้เปรียบที่แท้จริงสำหรับภาษาไดนามิกหรือไม่ [ปิด]
ก่อนอื่นฉันอยากจะบอกว่า Java เป็นภาษาเดียวที่ฉันเคยใช้ดังนั้นโปรดขอโทษด้วยที่ฉันไม่รู้เรื่องนี้ ภาษาที่พิมพ์แบบไดนามิกช่วยให้คุณสามารถใส่ค่าใด ๆ ในตัวแปรใด ๆ ตัวอย่างเช่นคุณสามารถเขียนฟังก์ชันต่อไปนี้ (psuedocode): void makeItBark(dog){ dog.bark(); } และคุณสามารถผ่านเข้าไปได้ทุกสิ่ง ตราบใดที่ค่ามีbark()วิธีการรหัสจะทำงาน มิฉะนั้นข้อผิดพลาดรันไทม์หรือสิ่งที่คล้ายกันจะถูกโยน (โปรดแก้ไขฉันหากฉันทำผิดในเรื่องนี้) ดูเหมือนจะทำให้คุณมีความยืดหยุ่น อย่างไรก็ตามฉันได้อ่านเกี่ยวกับภาษาไดนามิกและสิ่งที่คนพูดคือเมื่อออกแบบหรือเขียนโค้ดในภาษาไดนามิกคุณคิดเกี่ยวกับประเภทและนำมาพิจารณาเช่นเดียวกับที่คุณพิมพ์ด้วยภาษาแบบคงที่ ตัวอย่างเช่นเมื่อเขียนmakeItBark()ฟังก์ชันคุณตั้งใจให้ยอมรับเฉพาะสิ่งที่เห่าและคุณยังต้องตรวจสอบให้แน่ใจว่าคุณส่งสิ่งเหล่านี้ลงไปเท่านั้น ข้อแตกต่างคือตอนนี้คอมไพเลอร์จะไม่บอกคุณเมื่อคุณทำผิด แน่นอนว่ามีข้อดีอย่างหนึ่งของวิธีนี้ซึ่งก็คือในภาษาคงที่เพื่อให้บรรลุ 'ฟังก์ชั่นนี้ยอมรับทุกสิ่งที่สามารถเห่า' คุณจะต้องใช้Barkerอินเทอร์เฟซที่ชัดเจน ถึงกระนั้นก็ดูเหมือนว่าจะได้เปรียบเล็กน้อย ฉันพลาดอะไรไปรึเปล่า? ฉันได้อะไรจากการใช้ภาษาที่พิมพ์แบบไดนามิก?

5
การเชื่อมต่ออย่างแน่นหนาระหว่าง Javascript, HTML และ CSS: วิธีการที่ทันสมัยกว่านี้ไหม?
เป็นเรื่องธรรมดามากที่จะเห็น Javascript ผูกกับตัวเลือกบางตัวเพื่อค้นหาองค์ประกอบจัดเก็บข้อมูลและฟังเหตุการณ์ เป็นเรื่องปกติที่จะเห็นตัวเลือกเดียวกันนี้ที่ใช้ในการจัดแต่งทรงผม jQuery (และเครื่องมือเลือก Sizzle) สนับสนุนและส่งเสริมสิ่งนี้โดยอ้างอิงองค์ประกอบที่มีไวยากรณ์ประเภท CSS ดังนั้นเทคนิคนี้จึงยากที่จะ 'ไม่เข้าใจ' (หรือ refactor) เมื่อสร้างโครงการ ฉันมาทำความเข้าใจว่านี่เป็นผลมาจากประวัติของการพัฒนา HTML และ Javascript และเบราว์เซอร์นั้นถูกสร้างขึ้นเพื่อใช้ / แยกวิเคราะห์อย่างมีประสิทธิภาพและแสดงการเชื่อมต่อแบบนี้ แต่เมื่อเว็บไซต์มีความซับซ้อนมากขึ้นความเป็นจริงนี้อาจทำให้เกิดความยุ่งยากในการจัดระเบียบและบำรุงรักษาเลเยอร์แยกเหล่านี้ คำถามของฉันคือ: สามารถและควรหลีกเลี่ยงในเว็บไซต์ทันสมัยหรือไม่ ถ้าฉันยังใหม่ต่อการพัฒนา Front-end และฉันต้องการเรียนรู้สิ่งที่ 'ถูกวิธี' มันคุ้มค่าที่จะเรียนรู้ที่จะแยกและหลีกเลี่ยงการพึ่งพาเช่นนั้นตั้งแต่เริ่มต้น? นี่หมายถึงการหลีกเลี่ยง jQuery ในความโปรดปรานของห้องสมุดที่ส่งเสริมโครงสร้างที่แยกออกจากกันมากขึ้นหรือไม่?
29 javascript  html  css  jquery 

15
ในยุคของการคำนวณที่ทันสมัยใน 'แอพทางธุรกิจทั่วไป' - เหตุใดประสิทธิภาพจึงมีความสำคัญ [ปิด]
นี่อาจเป็นคำถามแปลก ๆ สำหรับพวกคุณบางคน ฉันเป็นโปรแกรมเมอร์ Java มือสมัครเล่น ฉันได้พัฒนาเกมหลายเกมโปรแกรม AI ที่สร้างเพลงอีกโปรแกรมหนึ่งสำหรับการวาดภาพและอื่น ๆ ที่คล้ายคลึงกัน นี่เป็นการบอกคุณว่าฉันมีประสบการณ์ในการเขียนโปรแกรม แต่ไม่ใช่ในการพัฒนาแอปพลิเคชันทางธุรกิจอย่างมืออาชีพ ฉันเห็นจำนวนมากพูดคุยเกี่ยวกับเว็บไซต์นี้เกี่ยวกับประสิทธิภาพ ผู้คนมักถกเถียงกันว่าอัลกอริธึมที่มีประสิทธิภาพมากที่สุดใน C # คืออะไรเพื่อทำงานหรือทำไม Python จึงช้าและ Java เร็วขึ้นเป็นต้น สิ่งที่ฉันพยายามที่จะเข้าใจคือ: ทำไมเรื่องนี้? มีพื้นที่เฉพาะในการคำนวณที่ฉันเห็นว่าทำไมเรื่องประสิทธิภาพ: เกมที่มีการคำนวณนับหมื่นเกิดขึ้นทุกวินาทีในลูปการปรับปรุงอย่างต่อเนื่องหรือระบบระดับต่ำที่โปรแกรมอื่น ๆ ใช้เช่น OS และ VM เป็นต้น แต่สำหรับแอปทางธุรกิจระดับสูงตามปกติทั่วไปทำไมประสิทธิภาพถึงสำคัญ? ฉันเข้าใจได้ว่าทำไมมันถึงมีความสำคัญเมื่อหลายสิบปีก่อน คอมพิวเตอร์ช้าลงมากและมีหน่วยความจำน้อยกว่าดังนั้นคุณต้องคิดอย่างรอบคอบเกี่ยวกับสิ่งเหล่านี้ แต่วันนี้เรามีหน่วยความจำมากเพื่อให้อะไหล่และคอมพิวเตอร์เป็นอย่างรวดเร็ว: ไม่ได้จริง ๆว่าถ้าอัลกอริทึม Java โดยเฉพาะอย่างยิ่งคือ O (n ^ 2)? มันจะสร้างความแตกต่างให้กับผู้ใช้ปลายทางของแอพธุรกิจทั่วไปนี้หรือไม่? เมื่อคุณกดปุ่ม GUI ในแอพธุรกิจทั่วไปและเบื้องหลังมันเรียกใช้อัลกอริทึม O (n …

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