Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
В этом-то и заключается вся сложность: твое представление о “достойном” и “красивом” коде полностью основано на личном многолетнем опыте. Попробуй теперь передать это представление в сжатые сроки человеку с совсем другим опытом или даже вовсе без него.
if (obj && obj.s) {
// do something
}
public static final double INFINITY = 1000000000.0d;
Стоит ли ради этого портить весь код, вставляя ненужные if/else вместо тернарного оператора?
Зачем было уходить от однострочной мешанины,
Не знаю, что понимается под «мешаниной», но когда в экранах было 24 строчки, программы с однострочными конструкциями читались гораздо легче, чем многострочные
a=b; b=c; c=d; if (a==5) d = 7;
Что касается отладки, то, вероятно, код, нацеленный на наиболее эффективную отладку, должен обладать своими особенностями — не обязательно совпадающими с «лаконичностью», «читабельностью» или «эффективностью».
if (a==5)
doSomething;
if (a==5) doSomething;
Насчёт того, что тернарный оператор сложнее — не понял. Он слегка другой, чем if/else — потому что является выражением, а не двумя отдельными операторами.
И тем не менее,
a=b; b=c; c=d; if (a==5) d = 7;
дурной тон.
var t=a; a=b; b=t;Выражение вида
if (a==5)
doSomething;
позволяет ставить BP и читается лучше, чем
if (a==5) doSomething;
Тернарный оператор может возвращать lvalue,
4.2. Техника 2. Используем break, continue, return или throw, чтобы избавиться от блока else.
Если писать код маленькими функциями (как и советует Макконел)
>Ну а нужны комментарии в случаях, когда написать код хорошо по тем или иным причинам не представляется возможным.
Вы ни разу не видели хороший код со сложной предметной областью?
Collection<String> lowercaseStrings = somestrings.stream()
.map( StringUtils::lowerCase ).collect(Collectors.toList());
procedure proc1() {
init();
do1();
}
procedure proc2() {
init();
do2();
}
proc1();
proc2();
запишем:
init();
do1();
do2();
procedure proc1() {
init();
do1();
}
Есть некое действие proc1(), которое заключается в init() и do1(). А завтра оно может заключаться уже в do1() и doSomethingElse(), но по смыслу это всё равно будет proc1().
proc1, а может быть, это действие do1, а proc1 создана только для удобства инициализации (потому что все всегда забывали). А еще зависит от того, насколько связаны вызовы proc1 и proc2proc1 создана только для удобства инициализации (потому что все всегда забывали)Значит это проблема на уровне архитектуры. И использование попеременно и на усмотрение автора то do1, то proc1 только добавят путаницы в коде.
procedure proc1(obj) {
if (!is_valid(obj)) return;
obj.call1();
}
… Не смотря на то, что иногда такая стратегия может быть оправдана (особенно, если proc1() и proc2() экспортируются в качестве API), во многих случаях это просто засорение кода.
find_defects();
if (defects_found()) {
…
}
В данном примере функциональщина ни при чём, это базовые принципы разработки ПО.
Лучше использовать исключения.
type DefectInspectionResult =
| None
| Acceptable of defects : seq<Defect>
| Unacceptable of acceptable : seq<Defect> * unacceptable : seq<Defect>
out (который геморроен), либо просто использовать поля класса, в котором уже происходит обработка. Собственно, если у нас на один процесс обработки создается один экземпляр класса, никаких фундаментальных проблем с этим не будет. Здравствуй, рефакторинг Method Object.Если обнаружение дефектов — это нормальная ветка сценария, то исключения бросать нельзя. В алгоритме выше дело обстоит именно так, поэтому забудьте про исключения.Точно, это меня переклинило, и я отчего-то решил, что find_defects() должен работать как check_defects(), а забыв о семантике слова find.
А принцип «явное лучше неявного» одинаково хорошо работает и в ООП, и в ФП, и совет про возвращение значения из функции вместо установки поля класса — как раз из этой серии.
procedure negotiate_with_client() {
check_cost();
if (!client_agree()) {
pay_for_wash();
return;
}
find_defects();
if (defects_found()) {
say_about_defects();
if (!client_agree()) {
pay_for_wash_and_dyagnosis();
return;
}
}
create_request();
take_money();
}
listen_client();
if (!is_clean()) {
wash();
}
negotiate_with_client();
bye();
function negotiate_with_client() {
if (!is_clean()) {
wash();
add_washing_to_rendered_services();
}
check_cost();
if (!client_agree())
return false;
find_defects();
add_diagnostic_to_rendered_services();
if (defects_found()) {
say_about_defects();
if (!client_agree())
return false;
}
return true;
}
listen_client();
if (negotiate_with_client()) {
create_request();
take_money();
}
else
{
pay_for(rendered_services);
}
bye();
Если для вас всё иначе — можете выразить почему именно так.
def add(x, y):
print "x is {0} and y is {1}".format(x, y)
return x + y
def add(x, y):
print "x is {0} and y is {1}".format(x, y)
return x + y
def sum(x, y)
x + y
end
var a = 5
{
fmt.Println("a:", a)
}
var a = 5
{
fmt.Println(«a:», a)
}
// function foo
void foo()
{
}
void boo()
// function boo
{
}
Что такое красивый код, и как его писать?