Entrevista alternativa para uma posição de desenvolvedor de software

Contra o pano de fundo de discussões estrondosas aqui em Habré sobre quebra-cabeças algorítmicos e entrevistas em Yandex, me lembrei de como um de meus amigos, que trabalha para uma empresa bastante grande (não russa), certa vez me ofereceu um problema com as entrevistas que eles realizam. Agora o problema mudou (eles encontraram um exemplo mais legal do código), então com a permissão dele, eu publico a versão antiga aqui.





Um candidato que chegava à posição de desenvolvedor não recebia problemas de algoritmos, não era conduzido pelos confins da linguagem, mas simplesmente recebia um código para revisão. Código de um projeto real que uma vez tentou congelar um jovem verde. Felizmente, eles perceberam a tempo.





Foi sugerido fazer o seguinte:





  1. Examine o código e adivinhe em poucas palavras o que ele faz. (tudo está muito bem documentado no projeto, mas as bibliotecas de terceiros com documentação e comentários às vezes têm problemas, e os desenvolvedores precisam entender o que está acontecendo lá)





  2. Faça uma revisão do código, aponte lugares suspeitos e ruins e sugira como eles podem ser melhorados ou refeitos. Você pode fazer qualquer pergunta e google o que quiser.





O código está em C ++, embora a maioria dos bugs possam ser encontrados até mesmo por desenvolvedores em outras linguagens. O código era mais ou menos assim:





class SomeBusServiceClient {
public:
  SomeBusServiceClient();
  virtual ~SomeBusServiceClient();
  bool CallAsync(const std::string &uri, const std::string &param,
                 const misc::BusServiceClient::ResponseCB &callback);
  bool CallSync(const std::string &uri, const std::string &param,
                const misc::BusServiceClient::ResponseCB &callback);

private:
  misc::BusServiceClient ss_client_;

  static const int kSleepMs = 100;
  static const int kSleepCountMax = 50;
};

class SpecificUrlFetcher : public UrlFetcher {
public:
  SpecificUrlFetcher();
  virtual ~SpecificUrlFetcher();

  SomeData FetchData(const URL &url, const UrlFetcher::ResponseCB &callback);

private:
  bool SsResponse_returnValue{false};
  char SsResponse_url[1024];

  void SsResponseCallback(const std::string &response);

  SomeServiceClient *ss_client_;
};

// ...

static const char ss_getlocalfile_uri[] = "bus://url_replace_service";

namespace net {

pthread_mutex_t g_url_change_callback_lock = PTHREAD_MUTEX_INITIALIZER;

SomeBusServiceClient::SomeBusServiceClient()
    : ss_client_(misc::BusServiceClient::PrivateBus) {}

SomeBusServiceClient::~SomeBusServiceClient() {}

bool SomeBusServiceClient::CallAsync(
    const std::string &uri, const std::string &param,
    const misc::BusServiceClient::ResponseCB &callback) {
  bool bRet;
  bRet = ss_client_.callASync(uri, param, callback);
  return bRet;
}

bool SomeBusServiceClient::CallSync(
    const std::string &uri, const std::string &param,
    const misc::BusServiceClient::ResponseCB &callback) {
  boold bRet bRet = false;
  int counter;

  pthread_mutex_lock(&g_url_change_callback_lock);
  ss_client_.callASync(uri, param, callback);

  counter = 0;
  for (;;) {
    int r = pthread_mutex_trylock(&g_url_change_callback_lock);
    if (r == 0) {
      bRet = true;
      pthread_mutex_unlock(&g_url_change_callback_lock);
    } else if (r == EBUSY) {
      usleep(kSleepMs);
      counter++;
      if (counter >= kSleepCountMax) {
        pthread_mutex_unlock(&g_url_change_callback_lock);
        break;
      } else
        continue;
    }
    break;
  }
  return bRet;
}

/**************************************************************************/

SpecificUrlFetcher::SpecificUrlFetcher() {}
SpecificUrlFetcher::~SpecificUrlFetcher() {}

void SpecificUrlFetcher::SsResponseCallback(const std::string &response) {
  std::unique_ptr<lib::Value> value(lib::JSONReader::Read(response));
  if (!value.get() || !value->is_dict()) {
    pthread_mutex_unlock(&g_url_change_callback_lock);
    return;
  }

  lib::DictionaryValue *response_data =
      static_cast<lib::DictionaryValue *>(value.get());
  bool returnValue;
  if (!response_data->GetBoolean("returnValue", &returnValue) || !returnValue) {
    pthread_mutex_unlock(&g_url_change_callback_lock);
    return;
  }

  std::string url;
  if (!response_data->GetString("url", &url)) {
    pthread_mutex_unlock(&g_url_change_callback_lock);
    return;
  }
  SsResponse_returnValue = true;

  size_t array_sz = arraysize(SsResponse_url);
  strncpy(SsResponse_url, url.c_str(), array_sz);
  SsResponse_url[array_sz - 1] = 0;

  pthread_mutex_unlock(&g_url_change_callback_lock);
}

SomeData SpecificUrlFetcher::FetchData(const URL &url,
                                       const UrlFetcher::ResponseCB &callback) {
  lib::DictionaryValue dictionary;
  std::string ss_request_payload;

  misc::BusServiceClient::ResponseCB response_cb =
      lib::Bind(&SpecificUrlFetcher::SsResponseCallback, this);

  SomeBusServiceClient *ss_client_ = new SomeBusServiceClient();

  dictionary.SetString("url", url.to_string());
  lib::JSONWriter::Write(dictionary, &ss_request_payload);

  SsResponse_returnValue = false;
  SsResponse_url[0] = 0x00;

  ss_client_->CallSync(ss_getlocalfile_uri, ss_request_payload, response_cb);
  URL new_url;
  if (SsResponse_returnValue) {
    new_url = URL::from_string(SsResponse_url);
  }

  delete ss_client_;
  return UrlFetcher::FetchData(new_url, callback);
}

} // namespace net
      
      



, , .





, .
  1. - UrlFetcher, , -- - - URL'. , - - , URL, URL, . Decorator.





  2. :





    1. ss_getlocalfile_uri - . ? .





    2. , . .





    3. , SsResponse_returnValue





    -:





    4. pthread-, std::thread, .





    5. - strncpy(); std::string - .





    6. ss_client_ . std::unique_ptr.





    7. usleep() - std::this_thread::sleep()





    :





    8. SomeBusServiceClient::CallSync kSleepMs kSleepCountMax, . .





    :





    9. message bus . . , message bus, - , kSleepCountMax*kSleepMs, , - ( callASync - id ?). - , , URL, .





    9. FetchData , new_url , .





    10. FetchUrl, , . , , -- WTF? ? , ?





    11. ( FetchUrl ), SsResponseCallback . , , . pthread undefined behavior.





    12. Nota valiosa de @snizovtsev : "... você não pode usar este primitivo de sincronização para tal tarefa. Em caso de tempo limite, o desbloqueio será chamado 2 vezes. Ou seja, o código está incorreto no nível do algoritmo e você precisa reescrever tudo para uma variável de condição "





As respostas e comentários do candidato nos permitiram ter uma ideia de seu nível de conhecimento dos padrões modernos de C ++ e boas práticas, compreensão de assincronia e multithreading, meticulosidade na revisão e capacidade de "depurar" o código em seu cabeça. Bem, e estabeleça tópicos para conversas futuras de coração a coração.








All Articles