Группировка связанных переменных и операций?
В Code Complete, глава 10, рекомендуется сгруппировать связанные операторы, и приведен следующий пример:
void SummarizeData(...) {
...
GetOldData( oldData, &numOldData );
GetNewData( newData, &numNewData );
totalOldData = Sum( oldData, numOldData );
totalNewData = Sum( newData, numNewData );
PrintOldDataSummary( oldData, totalOldData, numOldData );
PrintNewDataSummary( newData, totalNewData, numNewData );
SaveOldDataSummary( totalOldData, numOldData );
SaveNewDataSummary( totalNewData, numNewData );
...
}
Утверждается, что такая группировка и одновременная обработка - это плохой дизайн, а вместо этого дает нечто более разделенное:
void SummarizeData(...) {
GetOldData( oldData, &numOldData );
totalOldData = Sum( oldData, numOldData );
PrintOldDataSummary( oldData, totalOldData, numOldData );
SaveOldDataSummary( totalOldData, numOldData );
...
GetNewData( newData, &numNewData );
totalNewData = Sum( newData, numNewData );
PrintNewDataSummary( newData, totalNewData, numNewData );
SaveNewDataSummary( totalNewData, numNewData );
...
}
Я согласен, что второй подход легче читать и понимать, и он предлагает более чистый код, по крайней мере, с моей точки зрения. Итак, мой вопрос: есть ли недостатки у второго подхода? Например, одна возможная проблема, о которой я мог подумать, связана с временными соединениями с базами данных и такими:
void SummarizeData(...) {
...
externalDataStore.open();
externalDataStore.save(oldData, numOldData);
externalDataStore.save(newData, numNewData);
externalDataStore.close();
...
}
Этот первый подход завершит обе операции сохранения в одном цикле открытия / закрытия. Однако со вторым подходом...
void SummarizeData(...) {
...
externalDataStore.open();
externalDataStore.save(oldData, numOldData);
externalDataStore.close();
...
externalDataStore.open();
externalDataStore.save(newData, numNewData);
externalDataStore.close();
...
}
Вы должны открывать и закрывать соединение для каждой операции. Это кажется расточительным, но я понятия не имею, как это влияет на производительность на практике.
Извините за излишне длинный вопрос...
2 ответа
Я еще не добрался до главы 10, посвященной завершению кода (еще несколько вечеров должны это сделать!), Но я думаю, что здесь главное состоит в том, чтобы сгруппировать строки кода логичным и легко читаемым способом, не затрагивая функциональность программы., Другими словами, вычистите его и переставьте как можно больше, но остановитесь, как только оно начнет влиять на поведение.
В вашем примере мы должны помнить, что "Преждевременная оптимизация - корень всего зла", но я думаю, что мы все еще можем с уверенностью предположить, что вам не следует закрывать соединение, если вы собираетесь открыть его снова сразу же, поскольку эти два действия буквально отменяют друг друга. Как правило, любые соединения должны открываться только непосредственно перед тем, как они вам понадобятся в первый раз, и закрываться сразу после последнего использования, для простоты.
Мне было скучно, поэтому я попытался провести тест скорости в Python с использованием Sqlite (который, как я понимаю, не лучший способ сделать это).
Во-первых, базовый тест из 50000 итераций, открывающий и закрывающий соединение после каждой итерации.
#!/usr/bin/env python
import sqlite3
class Creature(object):
legs = 0
eyes = 'monocular'
kind = ''
conn = sqlite3.connect(':memory:')
c = conn.cursor()
c.execute('''create table testtable
(date text, legs text, eyes text, kind text)''')
conn.commit()
c.close()
for i in range(50000):
c = conn.cursor()
creature1 = Creature()
creature1.legs = 5
creature1.eyes = 'monocular'
creature1.kind = 'mungy'
c.execute('insert into testtable values (?,?,?,?)', ('today', str(creature1.legs), creature1.eyes, creature1.kind))
creature2 = Creature()
creature2.legs = 3
creature2.eyes = 'binocular'
creature2.kind = 'thingy'
c.execute('insert into testtable values (?,?,?,?)', ('today', str(creature2.legs), creature2.eyes, creature2.kind))
creature3 = Creature()
creature3.legs = 3
creature3.eyes = 'monocular'
creature3.kind = 'pungy'
c.execute('insert into testtable values (?,?,?,?)', ('today', str(creature3.legs), creature3.eyes, creature3.kind))
conn.commit()
c.close()
И сейчас 50000 итераций, но без закрытия соединения.
#!/usr/bin/env python
import sqlite3
class Creature(object):
legs = 0
eyes = 'monocular'
kind = ''
conn = sqlite3.connect(':memory:')
c = conn.cursor()
c.execute('''create table testtable
(date text, legs text, eyes text, kind text)''')
conn.commit()
c.close()
c = conn.cursor()
for i in range(50000):
creature1 = Creature()
creature1.legs = 5
creature1.eyes = 'monocular'
creature1.kind = 'mungy'
creature2 = Creature()
creature2.legs = 3
creature2.eyes = 'binocular'
creature2.kind = 'thingy'
creature3 = Creature()
creature3.legs = 3
creature3.eyes = 'monocular'
creature3.kind = 'pungy'
c.execute('insert into testtable values (?,?,?,?)', ('today', str(creature1.legs), creature1.eyes, creature1.kind))
c.execute('insert into testtable values (?,?,?,?)', ('today', str(creature2.legs), creature2.eyes, creature2.kind))
c.execute('insert into testtable values (?,?,?,?)', ('today', str(creature3.legs), creature3.eyes, creature3.kind))
conn.commit()
c.close()
Результаты, достижения?
First method: Average 2.264s
Second method: Average 2.157s
Таким образом, это имеет значение, хотя и незначительное.
И там у вас есть это.
Определенно согласен с тем, что сказал Стефан.