Любая из вакансий в компании Auslogics предполагает выполнение тестового задания. Это обязательная часть процесса отбора соискателей. Тестовые задания разрабатываются для каждой отдельной должности и учитывают весь набор компетенций, которыми должен обладать сотрудник, который в будущем займет эту должность.
Вопросы и задачи тестов изменяются практически с каждой новой вакансией. О критериях, на которые мы обращаем внимание при проверке работ детально написано в разделе «Карьера у нас». К сожалению, мы не можем разобрать ошибки тестовых заданий для всех должностей, имеющихся в компании, но для примера мы решили привести и прокомментировать ряд выполненных соискателями тестовых работ на должность "Программист Delphi".
var
CS: TCriticalSection;
...
CS.Enter;
if (Dir <> CurrentDir) then
begin
CS.Leave;
Exit;
end;
CS.Leave;
...
var
IconCreator: TThread;
...
if Assigned(IconCreator) then
begin
IconCreator.Terminate;
IconCreator.WaitFor;
IconCreator.Free;
IconCreator := nil;
end;
...
...
try
SRC.Canvas.Lock;
Buffer.Canvas.Lock;
...
Buffer.Canvas.Unlock;
SRC.Canvas.Unlock;
except
Result := False;
SRC.Canvas.Unlock;
Buffer.Canvas.Unlock;
end;
...
- Повторный вызов методов Unlock в блоке except лишний и ненужный, т.к. достаточно использовать конструкции try finally. Это позволяет избежать дублирования и сделать код более читабельным и логичным.
- Отсутствие операторов try finally между вызовами Lock и Unlock может привести к тому, что ресурс останется заблокированным или будет вызван Unlock на незаблокированном ресурсе.
- Вызов Unlock в блоке except может выполниться до того, как будет вызван Lock для этого ресурса.
...
try
J := TJPEGImage.Create;
J.LoadFromFile(dir + aFileName);
SRC.Assign(J);
J.Free;
except
if Assigned(J) then
J.Free;
Result := False;
end;
...
- При возникновении ошибки в конструкторе TJPEGImage в секции exception значение переменной J будет неопределенно, т.е. она может не равняться nil, что приведет к вызову метода Free для несуществующего объекта и как следствие к ошибке access violation.
- Логика данного участка кода предполагает использование блока try finally для контроля за уничтожением объекта TJPEGImage. Использование try finally позволит избежать ненужных проверок на существование объекта и дублирование метода Free.
...
if(lkPath[Length(lkPath)] <> '\')then
lkPath := lkPath + '\';
...
unit ufmMain;
interface
uses
uThread;
...
implementation
...
end.
unit uThread;
interface
...
implementation
uses
ufmMain;
...
end.
const
ThreadSuccess= 9;
ThreadError= -1;
type
TThumbsThread = class(TThread)
protected
procedure Execute; override;
end;
procedure TThumbsThread.Execute;
begin
ReturnValue:=0;
try
...
ReturnValue := ThreadSuccess;
except
ReturnValue := ThreadError;
end;
end;
procedure TMainForm.RedrawThumbnails();
begin
...
if Assigned(ThumbsThread) then
begin
ThumbsThread.Terminate;
while (ThumbsThread.WaitFor= 0) do
Application.ProcessMessages;
ThumbsThread:= nil;
end;
ThumbsThread:= TThumbsThread.Create(true);
ThumbsThread.FreeOnTerminate:= false;
...
ThumbsThread.Resume;
...
end;
- Цикл ожидания с проверкой результата выполнения функции WaitFor нелогичен и, в случае ошибки выполнения потока, приведет просто к зависанию приложения, т.к. функция WaitFor блокирует выполнение, ожидает завершение потока и возвращает результат работы потока. Т.е. значение, возвращаемое функцией WaitFor, с течением времени не меняется. К тому же, сам цикл в данном случае нелогичен, т.к. он не выполняется (функция блокирует выполнение до завершения потока).
- Непонятно и нелогично использование свойства потока ReturnValue, т.к. оно фактически нигде не используется (только для цикла с проверкой WaitFor, о чем написано в предыдущем пункте).
- Объекты типа TThumbsThread никогда не освобождаются, при этом создаются в больших количествах, что приводит к утечкам памяти.
type
TFindPictures = class(TThread)
private
procedure AddPicture(Name : string; aIndex : Integer);
protected
procedure Execute; override;
end;
procedure TFindPictures.Execute;
var
SearchRec : TSearchRec;
ThumbImage : TGPImage;
ImageIndex : Integer;
begin
FindFirst(Directory + '\*.*', faAnyFile, SearchRec);
if SearchRec.Name <> '' then
begin
repeat
if isPicture(SearchRec.Name) then
begin
ThumbImage := CreateThumb(IncludeTrailingPathDelimiter(Directory)
+ SearchRec.Name);
ImageIndex := AddThumbInList(ThumbImage);
AddPicture(SearchRec.Name, ImageIndex);
end;
until ((FindNext(SearchRec) <> 0) or Terminated)
end;
FindClose(SearchRec);
end;
procedure TFindPictures.AddPicture(Name: string; aIndex : Integer);
var
Picture : TListItem;
begin
Picture := ListView.Items.Add;
Picture.Caption := Name;
Picture.ImageIndex := aIndex;
end;
type
TListViewThread = class(TListView)
protected
FindPicture : TFindPictures;
public
procedure DirectoryChange(var Msg : TMessage); message WM_DIRECTORY_CHANGE;
end;
procedure TListViewThread.DirectoryChange(var Msg: TMessage);
var
CurrentDirectory : string;
begin
CurrentDirectory := PChar(Pointer(Msg.LParam));
Self.Items.Clear;
if Assigned(FindPicture) then
FindPicture.Terminate;
FindPicture := TFindPictures.Create(CurrentDirectory, Self);
FindPicture.Resume;
end;
- Объекты типа TFindPictures никогда не освобождаются, но создаются при каждой смене директории, что приводит к утечкам памяти.
- При завершении работы приложения не выполняется остановка потока, что может привести к очень долгой выгрузке приложения из памяти, в случае большого количества графических файлов в папке (приложение не завершится, пока не будут загружены все файлы из папки).
- При прерывании потока нет ожидания его завершения, поэтому, в случае переключения на другую папку, когда чтение файлов еще не завершено, поток будет еще выполнятся, и добавит в список отображения последний обрабатываемый файл.
- Работа с GUI компонентами из потока не синхронизирована, что может приводить к различным ошибкам в работе приложения.