Собеседование разработчика

в 14:36, , рубрики: .net, c#.net, human resources, Программирование, собеседования, метки: , ,

Техническое собеседование – практически неотъемлемый атрибут трудоустройства любого разработчика, а для старших разработчиков – проведение их (собеседований) ещё и чуть ли не повседневная обязанность. Но как за короткий срок (в идеале 20-30 минут) составить у себя более менее приемлемое представление о реальном опыте соискателя?

Помню, как меня впервые попросили прособеседовать по WPF молодого человека – я несколько часов составлял список того что стоит спросить (и перепроверял ответы, чтобы самому не ударить лицом в грязь) чтобы хоть с какой-то то долей уверенности потом сказать, нужен нам в компании такой человек или нет. И вот, вооружившись 10-15 вопросами, я вхожу в переговорную, представляюсь, задаю пару общих вопросов и между прочим уточняю:
— А сколько у вас лет опыта разработки с использованием WPF?
— Я не знаю WPF….
— …
Этот неловкий момент когда ты понимаешь, что предусмотрел всё, кроме самого очевидного…

Другой, не менее неожиданный для меня поворот был, когда в CV соискателя был указан опыт разработки 5 лет и перечислены куча интригующих описаний проектов, а по факту, человек с трудом смог объяснить, чем отличаются ссылочные типы от значимых, а про сборку мусора сказал, что знает лишь то, что о памяти в .Net думать не нужно…

Что же можно спросить, чтобы можно было положиться на ответ, как на что-то значимое?
— Спрашивать, какие книги он и по сколько раз прочитал? Но заученные формулировки не говорят о том, что человек способен решать реальные задачи, постановка которых отличается от книжных и порой требует отклонения от общих принципов разработки по тем или иным причинам.
— Выписать все технические нюансы среды и спрашивать о них? Но по правде говоря, кому хоть раз пригодилось знание о том, как работает сборка мусора (которая к тому же и меняется от версии к версии) и сколько там поколений? Я не говорю, что это лишнее знание – отнюдь, но знание или незнание этой особенности не позволят определить «качество» разработчика.
— Просить показать пример кода? Но какой код вам покажут? Сколько людей его уже правило? В каких условиях он был написан? Что если эти блестящие 300 строк писались месяц под шум прибоя атлантического океана в сезон дождей? Сможем ли мы потом воссоздать «рабочую» атмосферу, чтобы получить следующие 300 блестящих строк?

Я хочу поделится своей идей и услышать конструктивную критику такого подхода к проведению собеседований. Моя идея заключается в том, чтобы показывать «СВОЙ» код и слушать. За вечер я набросал пример ужасного кода, включив в него самые распространённые «ошибки». Я ожидаю, что старший разработчик, с реальным опытом разработки от 4 лет, должен идентифицировать более 80% процентов ошибок и указать на существующие проблемы в гипотетической архитектуре.

И так, собственно код:

1	using System;
2	using System.Collections.Generic;
3	 
4	namespace App.Services
5	{
6	    public enum LoginResult
7	    {
8	        Unknown = 0,
9	        Success = 1,
10	        WrongLogin = -1,
11	        WrongPass = -2,
12	        Error
13	    }
14	 
15	    public class LoginService
16	    {
17	        public string LastError = string.Empty;
18	 
19	        /// <summary>
20	        /// Allow to login new user
21	        /// </summary>
22	        /// <param name="login">login</param>
23	        /// <param name="password">password</param>
24	        /// <param name="asAdmin">asAdmin</param>
25	        /// <returns>login result</returns>
26	        public LoginResult Login(string login, string password)
27	        {
28	            List<Login> dbLogins = new List<Login>();
29	            try
30	            {
31	                dbLogins.AddRange(
32	                    DAL.GetItems<Login>(
33	                    "select * from db.Login where Name='" + login + "'"));
34	            }
35	            catch (Exception ex)
36	            {
37	                lock ((object)777)
38	                {
39	                    LastError = ex.Message;
40	                }
41	                throw ex;
42	            }
43	            if (dbLogins.Count < 1)
44	            {
45	                return LoginResult.WrongLogin;
46	            }
47	 
48	            var prevUser = App.CurrentUser;
49	            App.CurrentUser = dbLogins[0];
50	            if (password.CompareTo(App.CurrentUser.Password) != 0)
51	            {
52	                App.CurrentUser = prevUser;
53	                return LoginResult.WrongPass;
54	            }
55	 
56	            var log = System.IO.File.AppendText(App.LogFile);
57	            log.WriteLine("New user loggined. Login=" + App.CurrentUser.Name);
58	 
59	            if (!(bool)((EventService)App.Service).SendWithConfirm(prevUser))
60	            {
61	                log.Write("Error sending to user.");
62	            }
63          
64	            GC.Collect();
65	            GC.Collect();
66
67	            return LoginResult.Success;
68	        }
69	    }
70	}

Ошибки ( номер строки и описание, которое я ожидаю услышать от соискателя):
12 – Значение для «Error» будет «-1», что продублирует уже существующее и не позволит в будущем отличить одно от другого.
17 (1) – Public field. По правилам хорошего тона не рекомендуется делать поля публично доступными.
17 (2) – Запись в переменную далее по коду «реализована» через lock, но внешний потребитель может и не знать о том что обращение к переменной следует синхронизировать с кем-либо.
20 – Бессмысленные комментарии.
24 – Комментарий не соответствующий действительности.
28 – Публичный метод принял параметры из вне, но не выполнил проверку на их корректность (как минимум на null).
32 – Сильная связанность.
33 (1) – Потенциальная место для использования SQL инъекции. Так как для формирования запроса используется конкатенация а не параметры. А во вторых – не параметризованные запросы не кэшируются сиквел сервером (если СУБД сиквел).
33 (2) – Подобный стиль формирования запросов «привязывает» приложение к конкретной СУБД).
33 (3) – Конкатенация строк таким образом не самое эффективное решение.
35 – По правилам хорошего тона следует перехватывать ошибки, которые могут быть обработаны, а не всё подряд.
37 – Этот lock не будет работать.
39 – Бессмысленное значение в переменной и никакой пользы для разработчиков при диагностики.
41 – Актуальный стэк трйс, который мог бы быть полезен при диагностике ошибки безвозвратно потерян при таком порождении исключения.
49 (1) – Разрушение состояния приложения, так как при ошибке ниже (null пароль) в поле текущего пользователя будет уже новый логин.
49 (2) – Неявная бизнес логика. Почему отсекли другие логины?
50 (1) – Пароль не проверен на null и может быть исключение которое приведёт к разрушению состояния приложения.
50 (2) – Пароль хранится и используется в открытом виде.
53 – По правилам хорошего тона – не следует сообщать столь подробную информацию о причинах ошибки аутентификации.
56 (1) – Отсутствие продуманного механизма логирования как такового.
56 (2) – Открывается поток, но его закрытие и уничтожение не выполнены, данные могут быть и не записаны в конечный файл.
56 (3) – Операция работы с файлами может породить исключение, которое уровнем выше может быть трактовано как ошибка аутентификации, хотя по факту – логин уже прошёл.
57 – Бессмысленная информация, которая никак не упростит жизнь анализирующего лог файл, если он вдруг будет создан и кому ни будь потребуется.
59 (1) – Кроме связанности, вложенные вызовы с «завышенными» ожиданиями касательно возвращаемого результата.
59 (2) – Неочевидная бизнес логика.
61 – Бессмысленная запись в лог.
64,65 – Признак больших проблем с памятью в приложении. (Также я ожидаю услышать почему именно два вызова подряд и почему так делать всётаки не стоит)

Может, кто-то уже применял такой подход и может поделиться своим опытом?

Автор: asedovski

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js