Осадки

Примерно год назад, когда я впервые обращался на работу, у меня было интервью в компании, и они поставили перед собой следующую проблему, перед которой мне предшествовала бомба.

Через год я действительно придумал решение проблемы, и я не мог быть счастливее. Тем не менее, мне бы хотелось, чтобы некоторые критические замечания касались дизайна моего решения или других отзывов о: стиле, методах ООП и т. Д.

  

Заявление о проблемах

     

Группа фермеров имеет некоторые данные о возвышении, и мы собираемся помочь   они понимают, как выпадает ливень над их сельскохозяйственными угодьями.

     

Мы представляем землю как двумерный массив высот и   используйте следующую модель, основанную на идее, что вода течет под гору:

     

Если у четырех соседних ячеек клетки есть более высокие высоты, мы вызываем   эта ячейка раковина; вода собирается в раковинах.

     

В противном случае вода будет поступать в соседнюю ячейку с самым низким   высота над уровнем моря. Если ячейка не является приемником, вы можете предположить, что она имеет уникальный   самый низкий сосед и что этот сосед будет ниже ячейки.

     

Клетки, которые стекают в одну и ту же раковину - прямо или косвенно -   сказал, что он является частью того же бассейна.

     

Ваша задача - разбить карту на бассейны. В частности,   учитывая карту высот, ваш код должен разбить карту на   бассейнов и вывести размеры бассейнов в порядке убывания.

     

Предположим, что карты высот являются квадратными. Вход начнется с строки   с одним целым числом, S, высотой (и шириной) карты. Следующий S   каждая строка содержит строку карты, каждая из которых имеет S целых чисел -   возвышения S-ячеек в строке. У некоторых фермеров небольшая земля   таких как приведенные ниже примеры, в то время как некоторые из них имеют более крупные графики.   Однако ни в коем случае фермер не имеет участка земли размером более S =   5000.

     

Ваш код должен выводить список размеров бассейна, разделенный пробелами, в   в порядке убывания. (Промежуточные пробелы игнорируются.)

     

Ниже приведены несколько примеров:

     
 -----------------------------------------
Input:                 Output: 
 3                      7 2
 1 5 2 
 2 4 7 
 3 6 9 

The basins, labeled with A’s and B’s, are: 
 A A B 
 A A B 
 A A A 
-----------------------------------------
Input:                  Output: 
 1                       1
 10 

There is only one basin in this case. 
The basin, labeled with A’s is: 
 A
-----------------------------------------
Input:                  Output:            
 5                       11 7 7
 1 0 2 5 8 
 2 3 4 7 9 
 3 5 7 8 9 
 1 2 5 4 3 
 3 3 5 2 1 

The basins, labeled with A’s, B’s, and C’s, are: 
 A A A A A 
 A A A A A 
 B B A C C 
 B B B C C 
 B B C C C 
-----------------------------------------
Input:                  Output: 
 4                       7 5 4
 0 2 1 3                
 2 1 0 4 
 3 3 3 3 
 5 5 2 1 

The basins, labeled with A’s, B’s, and C’s, are: 
 A A B B 
 A B B B 
 A B B C 
 A C C C
-----------------------------------------

Мое решение, написанное на Perl, выглядит следующим образом:

Cell (моделирует отдельные ячейки в матрице):

 {
  package Cell; 
  use List::MoreUtils qw(all);

  # models 4 nearest neighbors to position i,j forall i,j
  my $neighbors = [ [ 0, -1], # left
                    [-1,  0], # top
                    [ 0,  1], # right
                    [+1,  0], # bottom
                  ];
  sub new { 
    my ($class, %attrs) = @_; 
    $attrs{is_sink} ||= 0;

    bless \%attrs, $class;
  }  

  # accessor/setter methods
  sub elevation { 
    return shift->{elevation};
  }

  sub x {
    return shift->{x};
  }

  sub y {
    return shift->{y};
  }

  sub is_sink {
    return shift->{is_sink};
  }

  sub set_sink {
    shift->{is_sink} = 1;
  }

  sub xy {
    my $self = shift;
    return [$self->x, $self->y];
  }

  # string representation of a Cell
  sub to_s { 
    my ($self) = @_;
    return "(" . $self->x . "," . $self->y . ") = " . $self->elevation;
  }

  # returns the neighbors that flow into this Cell
  sub get_flowing_neighbors {
    my ($self, $rainfall) = @_;

    # the neighbors of this cell flow into it 
    # iff this cell's elevation is less than their neighbors
    # AND the neighboring cell has no other neighbors 
    # (that are not this cell) that have a lower (or equal) elevation 
    return  grep {  
              $self->elevation < $_->elevation
              && all { $self->elevation <= $_->elevation } $_->get_neighbors($rainfall)
            } $self->get_neighbors($rainfall);
  }

  # returns the neighbors of this Cell
  sub get_neighbors { 
    my ($self, $rainfall) = @_;

    my ($rows, $cols) = ($rainfall->rows, $rainfall->cols);
    my ($x, $y)       = ($self->x, $self->y);
    my @adjs;

  NEIGHBORS:
    for my $neighbor ( @$neighbors ) {
      my ($xmod, $ymod) = ($x + $neighbor->[0], $y + $neighbor->[1]);

      # x and y must be in the bounds of the matrix
      next NEIGHBORS 
        if $xmod > $rows - 1 || $ymod > $cols - 1 || $xmod < 0 || $ymod < 0;

      push @adjs,
        $rainfall->cell($xmod, $ymod);
    }

    return @adjs;
  }

  1;
} # end Cell 

Rainfall (моделирует всю матрицу и операции по ней):

 {
  package Rainfall; 

  sub new { 
    my ($class, %attrs) = @_; 

    # initialize all elements of the matrix to cells O(n)
    for my $i ( 0 .. @{ $attrs{field} } - 1) {
      for my $j ( 0 .. @{ $attrs{field}->[$i] } - 1 ) { 
        $attrs{field}->[$i]->[$j] =
          Cell->new(  x => $i, 
                      y => $j, 
                      elevation => $attrs{field}->[$i]->[$j],
          );
      }
    }

    bless \%attrs, $class;
  }  

  # accessor methods
  sub field { 
    my $self = shift;
    return $self->{field};
  }

  sub cell {
    my ($self, $i, $j) = @_;

    return $self->field->[$i]->[$j];
  }

  sub rows {
    my $self = shift;
    return $self->{rows};
  }

  sub cols {
    my $self = shift;
    return $self->{cols};
  }

  # determines if a given Cell is a sink
  sub is_sink { 
    my ($self, $cell) = @_;

    my $min       = $cell->elevation;
    my @neighbors = $cell->get_neighbors($self);

    for my $neighbor ( @neighbors ) {
      $min = ($min, $neighbor->elevation)[$min > $neighbor->elevation];
    }

    # found a sink, mark it
    if( $min == $cell->elevation ) {
      $cell->set_sink;
      return 1;
    }

    return 0;
  } 

  # returns a list of all Sinks in the matrix
  # O(N * M) where N = # of rows and M = # of cols
  sub find_sinks {
    my ($self) = @_; 

    my @sinks; 
    for my $row ( 0 .. $self->rows - 1 ) {
      for my $cell ( @{ $self->field->[$row] } ) { 
        push @sinks, $cell
          if $self->is_sink($cell);
      }
    }

    return @sinks;
  }

  # given an Array of Sinks, find the Basins in this field
  # O(n)
  sub find_basins_from_sinks {
    my ($self, @sinks) = @_;

    my %basin;
    my $basin_marker = 'A';

    # determine how many cells eventually flow into this one
    for my $sink ( @sinks ) { 
      $basin{$basin_marker++} = $self->basin_size($sink);
    } 

    return %basin;
  }

  # recursively find the number of Cells in the Basin 
  # attached to the given Cell
  sub basin_size { 
    my ($self, $cell) = @_;

    my $size = 1;
    for my $neighbor ( $cell->get_flowing_neighbors($self) ) {
      $size += $self->basin_size($neighbor);
    }

    return $size;
  }

  1;
} # end Rainfall

Единичные тесты, которые проверяют результаты в соответствии с приведенными выше примерами:

 { # Tests
  use Test::More tests => 4; 

  { # 3x3 field 
    my $r = Rainfall->new( rows  => 3,
                           cols  => 3,
                           field => [ [1, 5, 2], 
                                      [2, 4, 7], 
                                      [3, 6, 9] ]);

    my @sinks = $r->find_sinks;
    my %basin = $r->find_basins_from_sinks(@sinks);

    is_deeply( 
        [sort { $b <=> $a } values %basin],
        [7, 2],
        'Correctly divided 3x3 field into 2 basins'
    );
  }

  { # 1x1 field
    my $r = Rainfall->new( rows  => 1,
                           cols  => 1,
                           field => [ [1] ]);

    my @sinks = $r->find_sinks;
    my %basin = $r->find_basins_from_sinks(@sinks);

    is_deeply( 
        [sort { $b <=> $a } values %basin],
        [1],
        'Correctly divided 1v1 field into 1 basin'
    );
  }

  { # 5x5 field
    my $r = Rainfall->new( rows  => 5,
                           cols  => 5,
                           field => [ [1, 0, 2, 5, 8],
                                      [2, 3, 4, 7, 9],
                                      [3, 5, 7, 8, 9],
                                      [1, 2, 5, 4, 3],
                                      [3, 3, 5, 2, 1] ]);

    my @sinks = $r->find_sinks;
    my %basin = $r->find_basins_from_sinks(@sinks);

    is_deeply( 
        [sort { $b <=> $a } values %basin],
        [11, 7, 7],
        'Correctly divided 5v5 field into 3 basins'
    );
  }

  { # Test 4x4 field
    my $r = Rainfall->new( rows  => 4,
                           cols  => 4,
                           field => [ [0, 2, 1, 3],
                                      [2, 1, 0, 4],
                                      [3, 3, 3, 3],
                                      [5, 5, 2, 1] ]);

    my @sinks = $r->find_sinks;
    my %basin = $r->find_basins_from_sinks(@sinks);

    is_deeply( 
        [sort { $b <=> $a } values %basin],
        [7, 5, 4],
        'Correctly divided 4v4 field into 3 basins'
    );
  }
}

Основной алгоритм выполняет поиск по каждому элементу в матрице и определяет, является ли этот элемент раковиной (что означает, что в него входят все его соседи).

 sinks = []
for i in matrix: # rows
   for j in matrix[i]: # columns
      if matrix[i][j] is a sink:
         sinks.add( matrix[i][j] )

Из описания проблемы вы можете сказать, что в раковине будет один Basin, поэтому после того, как у вас есть приемники, вам нужно найти Basin s. Чтобы найти Basin s, вы начинаете с Sink s и выполняете поиск вовне, добавляя элементы в таз, если они) втекают в раковину или B), в поток, который течет в раковину. Вы перестаете искать внешний вид, когда больше нет путей потока.

 def find_basins_from_sinks(sinks):
   basins = {} # map
   marker = 'A'

   for sink in sinks:
      basins[marker++] = basin_size(sink)

def basin_size(cell):
   size = 1
   for neighbor in cell.neighbors:
      size += basin_size(neighbor)
34 голоса | спросил Hunter McMillen 3 Jpm1000000pmFri, 03 Jan 2014 18:26:53 +040014 2014, 18:26:53

4 ответа


21

Это очень красивый код, и похоже, что он работает. Моя критика относится к следующим темам:

  • Обсуждения о стиле, названии, используемых инструментах и ​​т. д. Я предполагаю, что вы сознательно остановились на определенном стиле, но некоторые аспекты поражают меня настолько необычно, что я хотел бы поговорить о них.
  • Я тоже, как и overengineer. Но есть некоторые части дизайна, которые, по моему мнению, могут быть улучшены.

Cell

  • Стиль Я был удивлен, увидев, что вы все сделали свой ООП. Где Moo /Mouse /Moose? Каковы ваши причины не использовать ни одного из них? Там есть допустимые причины, такие как меньшие зависимости, но они становятся редкими.

  • Стиль Отступы с двумя пробелами очень дискуссионны. Я (наряду с perlstyle ) рекомендую 4 столбца.

  • Стиль Я заметил, что вы используете { package Foo; ... }.

    • Рекомендуется размещать разные классы в разных файлах, поэтому это необязательно.
    • В версии 5.1 или более поздней версии (IIRC) есть форма package Foo { ... }, которая лучше читается. Если вы не нацелились на более старые перлы, вы можете использовать их вместо этого.
  • Стиль У вас есть ссылка на массив $neighbors. Это нормально, если в качестве решения личного стиля вы предпочитаете ссылки на нескалярные переменные. Это, похоже, не так, и единственное использование этих переменных - это @$neighbors.

  • Примечание Избегайте подпрограмм, называемых y, когда это возможно, поскольку это также оператор транслитерации. Конечно, это не проблема, когда используется только как метод.

  • Дизайн Метод is_sink просто возвращает значение состояния. Было бы лучше, если бы (лениво?) Искать соседей, чтобы увидеть, является ли это раковиной. В настоящее время это реализовано в запутанном названии Rainfall::is_sink, который, возможно, тормозит инкапсуляцию. Нет никакой веской причины сделать это за пределами класса Cell.

  • Стиль Метод xy не используется нигде. Он также возвращает arrayref, что затрудняет использование значений. Было бы больше Perlish возвращать плоский список, чтобы мы могли сделать my ($x, $y) = $cell->xy. Но поскольку у нас уже есть аксессоры, мы могли бы также удалить этот метод.

  • Стиль to_s поражает меня как имя Ruby-ish. В Perl нет соглашения об именовании метода toString. Тем не менее, можно переопределить оператор строкования, который, вероятно, лучше сделать:

    use overload '""' => sub { ... };
    
  • Дизайн . Некоторые из ваших методов требуют, чтобы экземпляр Rainfall был передан. Поскольку каждая ячейка принадлежит определенной сетке, возможно, было бы лучше сохранить сетки в каждой ячейке. Чтобы избежать циклических ссылок, вы должны использовать Scalar::Util::weaken использовать слабые ссылки. Или, если вы переключились на объектную систему: has grid => (weak => 1).

  • Стиль grep не всегда является лучшим решением:

    grep {  
      $self->elevation < $_->elevation
      && all { $self->elevation <= $_->elevation } $_->get_neighbors($rainfall)
    } $self->get_neighbors($rainfall);
    

    Что этот код выражает: Выберите всех соседей, которые выше меня, и где я самый низкий сосед . Но его довольно трудно читать, поскольку $_ привязан ко многим различным значениям. Никогда содержит несколько значений $_. Простым решением было бы добавить метод lowest_neighbor. Тогда:

    grep { !$_->is_sink && $self == $_->lowest_neighbor } $self->get_neighbors;
    

    В противном случае использование явных циклов может улучшить читаемость:

    my @flowing_neighbors;
    for my $neighbor ($self->get_neighbors) {
        next if not $self->elevation < $neighbor->elevation;
        next if not all { $self->elevation <= $_->elevation } $neighbor->get_neighbors;
        push @flowing_neighbors, $neighbor;
    }
    return @flowing_neighbors;
    
  • Стиль Использование @adjs в качестве аббревиатуры для @adjacents является ненужной обфускацией.

  • Чтобы выполнить проверку границ, было бы проще выполнить вместо

    next NEIGHBORS 
      if $xmod > $rows - 1 || $ymod > $cols - 1 || $xmod < 0 || $ymod < 0;
    

    next NEIGHBORS if not 0 <= $xmod && $xmod < $rows;
    next NEIGHBORS if not 0 <= $ymod && $xmod < $cols;
    

    Печально, что Perl не поддерживает цепочки сравнения операторов, но это лучший способ показать, что переменная находится в определенном диапазоне. Сравните также спецификации диапазона в цикле for:

    for (my $i = 0; $i < 10; $i++) {...} # 0..9
    

Rainfall

  • Дизайн . Вы создаете сетку объектов ячейки. Возможно, было бы более интересно использовать Flyweight Pattern , так как каждая ячейка содержит только очень небольшое состояние (будь то раковина, которую можно проверить довольно дешево).

  • Дизайн Чтобы найти все приемники, вы смотрите на каждую ячейку в сетке. Если мы забудем на мгновение, что вы хотели написать объектно-ориентированный код, мы могли бы рассмотреть этот алгоритм:

    create a set of all cells.
    while the set contains elements:
      pick one element from the set.
      until the element is a sink:
        element = element->lowest_neighbor
      calculate the size of the basin,
      remove each member of the basin from the cells-set
    

    В то время как можно построить патологический случай, когда это как цикл через все ячейки, это, как правило, будет находить следующий снимок намного быстрее.

    В Perl набор ячеек может быть реализован как хэш, который отображает координаты в объект ячейки.

  • Дизайн basin_size имеет no бизнес, находящийся в Rainfall. Это метод для Cell. Индикатор: вы ничего не используете из экземпляра Rainfall $self. Ergo это должен быть статический метод или обычная подпрограмма. Вы всегда передаете Cell в качестве первого аргумента, поэтому скорее всего это должен быть метод в экземпляре Cell.

  • Конструкция у вашего конструктора есть как аргумент rows, так и cols, который всегда один и тот же за defintion . Достаточно одного размера, так как будет выводить эту информацию из самой сетки!

  • Стиль вы выполняете нулевую проверку на входе (например, чтобы убедиться, что на самом деле имеет запрошенный размер, что на самом деле есть все требуемые параметры или что неизвестные параметры не использовались). Я часто использую

    my $thing = delete $args{thing} // die q("thing" required);
    

    , за которым следует die "Unknown arguments @{[sort keys %args]}" if keys %args проверяются. Альтернативой является использование объектной системы и указание атрибута с

    has thing => (required => 1);
    

Испытания

Это выглядит очень хорошо, комментариев здесь нет. Тем не менее, существует огромное количество дубликатов кода между тестами, которые могли быть удалены с помощью одного цикла.

Заключение

Это очень хороший код, который показывает работу опытного, осторожного программиста. Алгоритм в порядке. Дизайн немного запутан, что указывает наво-первых, дизайн-более поздний подход (это нормально, поскольку его можно легко реорганизовать).

ответил amon 3 Jpm1000000pmFri, 03 Jan 2014 20:33:09 +040014 2014, 20:33:09
19

Тот факт, что это был вопрос интервью, меняет взгляд на код. Интервьюер почти наверняка искал один ответ: «структура данных на основе объединения» или «структура данных непересекающихся множеств». Вас судили по тому, произнесли ли вы эти волшебные слова в течение первых нескольких секунд, могли бы придумать что-то подобное самостоятельно, могли бы придумать что-то подобное с руководством интервьюера или вообще не иметь.

Ваше решение может использовать либо абстрактную терминологию (например, Member и DisjointSet), либо терминологию, специфичную для домена (Cell и Basin). Поэтому в вашем моделировании отсутствует класс Basin. По-моему, использование терминологии, относящейся к домену, было бы лучше. Я также предпочел бы переименовать Rainfall в Topography, так как проблема заключается в анализе топографической карты.

Вот контур решения:

  1. Каждый Cell отслеживает, к какому Basin принадлежит; каждый Cell изначально предполагает, что он находится в своем собственном Basin. Каждый Basin имеет sink или самый низкий Cell, который действует как «представительский элемент» в Basin, а также количество членов. Topography отслеживает все Basin s.
  2. Для каждого Basin найдите самый нижний из соседей раковины. Если самый низкий не является членом этого Basin, перенесите его ячейки в Basin и сообщите Topography, что более высокий бассейн нет дольше.
  3. Повторите шаг 2, пока не потребуются дальнейшие действия.
  4. Topography перечисляет Basin s и их количество.
ответил 200_success 3 Jpm1000000pmFri, 03 Jan 2014 22:12:58 +040014 2014, 22:12:58
13

Есть несколько вещей, которые я вижу здесь, которые, по моему мнению, могут быть разными.

Мне не нравится, что логика определения, является ли ячейка раковиной, - это как Rainfall, так и Cell. Фактически, оба класса имеют метод, называемый is_sink ...

Мое предпочтение было бы переместить логику на Ячейку, которая уже знает, как вычислить ее соседи .... а затем класс Rainfall может просто вызвать:

push @sinks, $cell
      if $cell->is_sink($self);

Это указывает на большую проблему, однако, что повторное количество кода повторяется (вычисление соседей и т. д.). Мое предложение состоит в том, что после создания каждой ячейки должен быть начальный проход поля. Этот проход inialization должен получить каждую ячейку для вычисления и сохранения списка соседей, а также вычислить, является ли ячейка раковиной. Помещение его в конструктор класса Rainfall кажется правильной идеей, но, поскольку инициализация также может записывать приемники, для конструктора это довольно много. Я нахожусь на заборе. Верхняя сторона заключается в том, что это ускорит выполнение. Рассмотрим конструктор RainFall:

  sub new { 
    my ($class, %attrs) = @_; 

    # initialize all elements of the matrix to cells O(n)
    for my $i ( 0 .. @{ $attrs{field} } - 1) {
      for my $j ( 0 .. @{ $attrs{field}->[$i] } - 1 ) { 
        $attrs{field}->[$i]->[$j] =
          Cell->new(  x => $i, 
                      y => $j, 
                      elevation => $attrs{field}->[$i]->[$j],
          );
      }
    }

    my @sinks;
    for my $i ( 0 .. @{ $attrs{field} } - 1) {
      for my $j ( 0 .. @{ $attrs{field}->[$i] } - 1 ) { 
        my $cell = $attrs{field}->[$i]->[$j];
        $cell.initialize($self);
        push @sinks if $cell->is_sink;
      }
    }
    $attrs{sinks} = @sinks;

    bless \%attrs, $class;
  }  

Метод инициализации на Ячейке будет вычислять и хранить массив соседей. Это значительно сократит количество раз, которое нужно рассчитать.

Если у вас есть одноразовая инициализация, Cell-> is_sink не может снова принимать параметры.

Помимо реструктуризации is_sink и сохранения массива соседей, у меня есть выбор для некоторых из ваших условий цикла ... у вас часто есть код:

for my $row ( 0 .. $self->rows - 1 ) {
    ..

Вам лучше использовать оператор last-index, а не скалярный:

 for my $row ( 0 .. $#{$self->rows} ) {

Аналогично тому, как:

for my $i ( 0 .. @{ $attrs{field} } - 1) {

Должно быть:

for my $i ( 0 .. $#{ $attrs{field} }) {

один последний nit-pick, почему вычитание при> = отлично работает:

next NEIGHBORS 
    if $xmod > $rows - 1 || $ymod > $cols - 1 || $xmod < 0 || $ymod < 0;    

Это может быть легко:

next NEIGHBORS 
    if $xmod >= $rows || $ymod >= $cols || $xmod < 0 || $ymod < 0;

Хотя, опять же, неясно, что $ rows и $ columns здесь массивы, и я бы предпочел:

next NEIGHBORS 
    if $xmod > $#{$rows} || $ymod > $#{$cols} || $xmod < 0 || $ymod < 0;
ответил rolfl 3 Jpm1000000pmFri, 03 Jan 2014 19:57:57 +040014 2014, 19:57:57
3

Я вижу следующие три строки:

my $self = shift;
my ($self) = @_;
my ($self, $rainfall) = @_;

Как правило, лучше выбрать один стиль и придерживаться его. Может иметь смысл смешивать первую и третью строки в одной и той же программе, но первые две строки не должны сосуществовать. Я бы использовал вторую и третью версии, но если вам нравится первый, вы можете использовать с ним следующее:

my $self = shift;
my $rainfall = shift;

Это несколько дольше, но делает код непротиворечивым.

Perl имеет много способов сделать что-то (TIMTOWTDI). Это по-прежнему полезно, хотя вы можете выбрать один из способов сделать это в любой заданной программе (BSCINABTE).

Аналогично, в следующем коде:

sub x {
  return shift->{x};
}

Стоит подумать о том, что происходит:

sub x {
  my $self = shift @_;

  return $self->{x};
}

Надеюсь, вы знаете, что первый - это сокращение для последнего, но подумайте о следующем человеке, поддерживающем ваш код. Что, если это первый раз, когда человек использует Perl. Люди в этой ситуации увидят ваш код и подумают, что shift - это какое-то особое имя переменной в классах Perl (как только они поймут, что он не определен в классе). Как такой человек может добраться оттуда до последней версии?

shift - это встроенная функция Perl, которая по умолчанию соответствует переменной @_. В этом контексте @_ устанавливается в аргументы функции x с объектом в качестве первого аргумента. Встроенный shift принимает массив как первый аргумент, удаляет первую запись и возвращает эту запись. Затем вы разыгрываете результат с помощью оператора -> и извлекаете значение для ключа x с помощью хеш-поиска (поскольку классы обычно строятся на хэшах в Perl).

Кроме того, x кажется запутанным именем для функции. Я бы нашел get_x или даже get_x_coordinate, чтобы его было легче читать и понимать.

Если бы я был тем, кто оценивал ваш код интервью, я бы дал баллы за написание чистого, последовательного, читаемого кода. Часто стоит потратить немного дополнительного времени, чтобы сделать код симпатичным. Большая часть моего рабочего времени проводится с сохранением существующего кода, а не с написанием нового кода. Очень важно правильно писать исходный код. Мне все равно, что быстро. Самая важная часть заключается в том, что мне должно быть легко отлаживать и изменять. Вот где большую часть времени идет. Если вы сохраняете пятнадцать минут написания кода, но я провожу пятнадцать часов, пытаясь заставить его работать, то это не хороший компромисс.

Как всегда, другие рецензенты могут отличаться. Тот факт, что они просили вас написать существенный код с крайним сроком, может быть признаком того, что у них разные приоритеты, чем у меня.

ответил Brythan 18 +04002014-10-18T09:54:39+04:00312014bEurope/MoscowSat, 18 Oct 2014 09:54:39 +0400 2014, 09:54:39

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132