Alternatives Interview für eine Position als Softwareentwickler

Vor dem Hintergrund der Diskussionen, die hier auf Habré über algorithmische Rätsel und Interviews in Yandex donnerten, erinnerte ich mich daran, wie einer meiner Freunde, der für ein ziemlich großes (nicht russisches) Unternehmen arbeitet, mir einmal ein Problem aus den von ihnen durchgeführten Interviews angeboten hatte. Jetzt hat sich das Problem geändert (sie haben ein cooleres Beispiel für den Code gefunden), daher veröffentliche ich mit seiner Erlaubnis die alte Version hier.





Ein Kandidat, der zum Entwickler kam, bekam keine algorithmischen Probleme, wurde nicht durch die Wildnis der Sprache getrieben, sondern erhielt einfach einen Code zur Überprüfung. Code aus einem echten Projekt, das einmal versucht hat, einen grünen Junior einzufrieren. Zum Glück bemerkten sie es rechtzeitig.





Es wurde vorgeschlagen, Folgendes zu tun:





  1. Untersuchen Sie den Code und raten Sie auf den Punkt, was er tut. (Alles ist im Projekt ziemlich gut dokumentiert, aber Bibliotheken von Drittanbietern mit Dokumentation und Kommentaren haben manchmal Probleme, und Entwickler müssen verstehen, was dort vor sich geht.)





  2. Führen Sie eine Codeüberprüfung durch, weisen Sie auf verdächtige und schlechte Stellen hin und schlagen Sie vor, wie diese verbessert oder wiederholt werden können. Sie können Fragen stellen und googeln, was Sie wollen.





Der Code ist in C ++, obwohl die meisten Fehler auch von Entwicklern in anderen Sprachen gefunden werden können. Der Code war ungefähr so:





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. Wertvoller Hinweis von @snizovtsev : "... Sie können dieses Synchronisationsprimitiv nicht für eine solche Aufgabe verwenden. Im Falle einer Zeitüberschreitung wird das Entsperren zweimal aufgerufen. Das heißt, der Code ist auf Algorithmenebene falsch und Sie benötigen alles in eine Bedingungsvariable umschreiben "





Die Antworten und Kommentare des Kandidaten ermöglichten es uns, einen Eindruck von seinem Kenntnisstand über moderne C ++ - Standards und bewährte Verfahren, dem Verständnis für Asynchronität und Multithreading, der Sorgfalt bei der Überprüfung und der Fähigkeit, den Code in seinem zu "debuggen", zu bekommen Kopf. Nun, und setzen Sie Themen für weitere Gespräche von Herz zu Herz.








All Articles