ヤンデックスでのアルゴリズムパズルとインタビューについてここハブレで雷鳴の議論を背景に、あるかなり大きな(ロシア以外の)会社で働いている私の友人の一人が、彼らが行ったインタビューから私に問題を提供したことを思い出しました。今、問題は変わったので(彼らはコードのよりクールな例を見つけました)、彼の許可を得て、私はここに古いバージョンを公開します。
開発者の立場に来た候補者には、アルゴリズムの問題は与えられず、言語の荒野を駆け抜けることはなく、単にレビュー用のコードが与えられました。かつて1人のグリーンジュニアを凍結しようとした実際のプロジェクトのコード。幸いなことに、彼らは時間内にそれに気づきました。
次のことを行うことが提案されました。
コードを調べて、一言で言えばそれが何をするのかを推測します。(すべてがプロジェクトでかなりよく文書化されていますが、文書化とコメントのあるサードパーティのライブラリは時々問題を抱えており、開発者はそこで何が起こっているのかを理解する必要があります)
コードレビューを実施し、疑わしい場所と悪い場所を指摘し、それらを改善またはやり直す方法を提案します。あなたはどんな質問をしてもあなたが望むものは何でもグーグルすることができます。
コードはC ++ですが、バグのほとんどは他の言語の開発者でも見つけることができます。コードは次のようなものでした:
class SomeBusServiceClient {
public:
SomeBusServiceClient();
virtual ~SomeBusServiceClient();
bool CallAsync(const std::string &uri, const std::string ¶m,
const misc::BusServiceClient::ResponseCB &callback);
bool CallSync(const std::string &uri, const std::string ¶m,
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 ¶m,
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 ¶m,
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
, , .
, .
- UrlFetcher, , -- - - URL'. , - - , URL, URL, . Decorator.
:
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. @snizovtsevからの貴重なメモ: "...このようなタスクにはこの同期プリミティブを使用できません。タイムアウトの場合、ロック解除が2回呼び出されます。つまり、コードがアルゴリズムレベルで正しくないため、必要です。すべてを条件変数に書き換える」
候補者からの回答とコメントにより、最新のC ++標準とグッドプラクティスに関する彼の知識レベル、非同期とマルチスレッドの理解、レビューの細心の注意、および彼のコードを「デバッグ」する機能についてのアイデアを得ることができました。頭。さて、そしてさらなる会話のためのトピックを心から心に設定します。