İki döngüde yap

Dec 30 2022
Bilgisayar Bilimleri geçmişinden gelen biri olarak, 'verimlilik' kelimesinin zaten beynimin bir yerinde bir yerde olduğundan şüpheleniyorum. İçinden geçtiğim tüm o ağaçlar, büyük O'lar ve omega'lar, daha verimli bir yaklaşım benimsememe yardım etmek için oradaydılar.
Kararlı Difüzyon istemi: düz renklere ve rastgele dağılmış dikdörtgenlere sahip iki döngüden oluşan minimalist çizgi film

Bilgisayar Bilimleri geçmişinden gelen biri olarak, 'verimlilik' kelimesinin zaten beynimin bir yerinde bir yerde olduğundan şüpheleniyorum. İçinden geçtiğim tüm o ağaçlar, büyük O'lar ve omega'lar, daha verimli bir yaklaşım benimsememe yardım etmek için oradaydılar. Ve evet - bazen yardımcı oluyorlar ve onlarla çözebildiğim CP sorularıyla biraz gurur duyuyorum. Yine de kendinizi benim gibi ürün mühendisliği alanında bulursanız, ürün mühendisliğinde verimlilik kavramının üniversitede öğrendiğimiz kavram olmadığı konusundaki görüşlerimi paylaşabilirsiniz. Ben bu ayrılıkla barıştım. Ne de olsa ilkokul müdürüm uzay mühendisliği diplomasıyla mezun oldu ve bunu en iyi şekilde değerlendirdi.

Verimliliği özleyen iş mantığı kodunda yazdığım dikkate değer kalıplardan biri, her şeyi tek bir döngüde yapma modelidir. Zaman zaman diğer mühendislerden de, genellikle kariyerlerinin başlarında yaptıkları katkılardan dolayı tökezledim.

İşte bir kod parçası, bir grup öğrencinin birkaç dönem boyunca ortalama notlarını hesaplar ve ardından anahtar olarak öğrenci kimliklerini içeren bir karma harita döndürür:

avgFinalGradesByStudent := make(map[studentID]float)
for _, student := range students {
  totalFinalGrades := 0.0
  for _, semester := range semesters {
    studentGrade := gradesRepository.getByStudentID(student.ID, semester) // fetch from db
    totalFinalGrades = totalFinalGrades + studentGrade.FinalGrade
  }
  avgFinalGradesByStudent[student.ID] := totalFinalGrades / len(semesters)
}

return avgFinalGradesByStudent

studentGrades := make(map[studentID][]float)
for _, student := range students {
  for _, semester := range semesters {
    semesterGrade := gradesRepository.getByStudentID(student.ID, semester) // fetch from db
    studentGrades[student.ID] = append(studentGrades[student.ID], semesterGrade)
  }
}

avgFinalGradesByStudent := make(map[studentID]int)
for _, student := range students {
  totalFinalGrades := 0
  for _, grade := range studentGrades[studentID] {
    totalFinalGrades += grade
  }
  avgFinalGradesByStudent[student.ID] := totalFinalGrades / len(semesters)
}

return avgFinalGradesByStudent

İlk olarak, kodun verileri getiren kısmı ile hesaplama yapan kodun kısmı arasında net bir ayrımımız var. Basit bir özütleme yöntemi yeniden düzenlemesiyle, ana işlevimiz şu anda basitçe şöyle görünebilir:

studentGrades := getStudentGradesForAllSemesters(students, semesters)
avgFinalGradesByStudent := calculateAverageFinalGrades(studentGrades)

return avgFinalGradesByStudent

// arrange
studentGrades := map[studentID][]int { 1: []int {97, 86, 51}, 2: []int {60, 85, 95} } 
// act
result := calculateAverageFinalGrades(studentGrades)
// assert
assert.Equal(78,result[1])
assert.Equal(80, result[2])

avgFinalGradesByStudent := make(map[studentID]float)
// container for the final results
topThreeGradesByStudent := make(map[studentID][]int)
for _, student := range students {
  totalFinalGrades := 0.0
  var topThreeGrades []int
  for _, semester := range semesters {
    studentGrade := gradesRepository.getByStudentID(student.ID, semester) // fetch from db
    totalFinalGrades = totalFinalGrades + studentGrade.FinalGrade
    // some code to figure out if this grade is the top three grades or not 
    // and add/remove from topThreeGrades
    // ...
  }
  avgFinalGradesByStudent[student.ID] := totalFinalGrades / len(semesters)
  topThreeGradesByStudent[student.ID] := topThreeGrades
}

return avgFinalGradesByStudent, topThreeGradesByStudent

studentGrades := getStudentGradesForAllSemesters(students, semesters)
avgFinalGradesByStudent := calculateAverageFinalGrades(studentGrades)
topThreeGradesByStudent := getTopThreeGradesByStudent(studentGrades)

return avgFinalGradesByStudent, topThreeGradesByStudent

Diğer bir artısı da, kodumun okunması kolay olduğunda çok daha önemli optimizasyonları fark etme olasılığımın daha yüksek olduğunu fark etmem. Örneğin, yukarıdaki örnekte, öğrenci notlarını sorgulayan kısmı isteği gruplandırarak yeniden düzenlemek daha kolay hale gelir. getStudentGradesForAllSemestersEtkilenen iş mantığının başka bölümlerinin olacağından endişe etmeden yeniden düzenlemeye ihtiyacımız var!

Yukarıdaki nedenlerden dolayı, ikisini bir arada yapabildiğiniz halde iki döngü yapmanızı tavsiye ederim. Yani, önemsiz verimlilikler yerine mantıksal ayrımı tercih edin. Benim gibi benzer bir ürün mühendisliği alanındaysanız, mantıksal olarak genişletilmesi kolay bir kodunuz olması işinizi kolaylaştıracaktır!

Size kalmış - daha önce bu tür hepsi bir arada for döngüleriyle karşılaştınız mı? Belki de gerçekten iyi buluyordunuz? Hadi tartışalım :)