Entretien alternatif pour un poste de développeur logiciel

Dans le contexte des discussions tonnantes ici sur Habré à propos d'énigmes algorithmiques et d'entretiens à Yandex, je me suis souvenu comment un de mes amis, qui travaille pour une assez grande entreprise (non russe), m'a un jour posé un problème à partir des entretiens qu'ils mènent. Maintenant, le problème a changé (ils ont trouvé un exemple plus cool du code), donc avec sa permission, je publie l'ancienne version ici.





Un candidat qui est arrivé au poste de développeur n'a pas eu de problèmes algorithmiques, n'a pas été conduit à travers les déserts du langage, mais a simplement reçu un code pour examen. Code d'un vrai projet qui a déjà essayé de geler un junior vert. Heureusement, ils l'ont remarqué à temps.





Il a été suggéré de faire ce qui suit:





  1. Examinez le code et devinez en un mot ce qu'il fait. (tout est assez bien documenté dans le projet, mais les bibliothèques tierces avec de la documentation et des commentaires ont parfois des problèmes, et les développeurs doivent comprendre ce qui se passe là-bas)





  2. Réalisez une révision du code, indiquez les endroits suspects et les mauvais endroits et suggérez comment ils peuvent être améliorés ou refaits. Vous pouvez poser toutes les questions et rechercher sur Google tout ce que vous voulez.





Le code est en C ++, bien que la plupart des bogues puissent être trouvés même par des développeurs dans d'autres langages. Le code était quelque chose comme ça:





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. Note précieuse de @snizovtsev : "... vous ne pouvez pas utiliser cette primitive de synchronisation pour une telle tâche. En cas d'expiration du délai, le déverrouillage sera appelé 2 fois. Autrement dit, le code est incorrect au niveau de l'algorithme et vous avez besoin pour tout réécrire dans une variable de condition "





Les réponses et commentaires du candidat nous ont permis de se faire une idée de son niveau de connaissance des standards et des bonnes pratiques C ++ modernes, de la compréhension de l'asynchronie et du multithreading, de la minutie dans la revue et de sa capacité à "déboguer" le code dans son diriger. Eh bien, et définissez des sujets pour la poursuite de la conversation cœur à cœur.








All Articles