Я учусь на факультете, который «продаёт» студентов в компании-партнёры. После окончания второго курса все обязаны пойти на круглогодичную стажировку (возможно, оплачиваемую). Я, решивший и готовившийся к работе системным аналитиком, проходил соответствующие собеседования. В общей сложности я прошёл их около 10. Не все были связаны с университетом — некоторые компании просто нашли моё резюме.
Мне сделали несколько офферов, и я выбрал организацию, в которой сейчас и работаю. Все собеседования были разные: какие-то показательные, какие-то совсем не относящиеся к системному анализу. Например, вопрос о том, как выделить 8 килобайт памяти на С, меня сильно удивил. Эту компанию, впрочем, тоже можно понять — они проверяли междисциплинарные навыки, что для кого-то может считаться логичным при наборе студентов.
Собеседования были настолько разными, что я задумался: как бы я сам провёл собеседование и пытался выявить у потенциального стажёра необходимые навыки? Так у меня сформулировался вопрос:
Какой ключевой навык аналитики, претендующего на позицию джуна, можно попытаться выявить за ограниченное время собеседования?
Если у кого‑то ответ отличный от моего, то буду рад услышать!
Это был не ключевой вопрос для меня, поэтому он просто «висел» где-то в памяти и ждал подходящего момента. В один из дней я наткнулся на статью «Как написать ТЗ на простую программу (калькулятор)», в которой автор очень подробно разбирает требования, как бы то не казалось простой программе. Основной акцент был сделан на выявлении потребности через умение задавать вопросы, чтобы определить реальные потребности. В итоге нашелся ответ на исходный вопрос, когда сам того не ожидал (знаете, бывает когда внезапно лампочка загорается в голове).
Ведь правда, для построения адекватной модели решения аналитик всегда задает вопросы. Аналитик в целом, что делает, Задает вопросы, чтобы потом самому же на них искать ответы у разных стейкхолдеров, разными способами.
И вот мой ответ про ключевой навык - умение задавать вопросы.
Концепция собеседования
Осознав основную идею, на которой должно строиться собеседование аналитика, мне предстояло выбрать подход из тех, что я выделил для себя. Пусть моя выборка собеседований и не совсем репрезентативна, но я смог выделить два основных подхода, которые применялись на практике:
«Понять» — где ключевой целью было выявить мыслительные цепочки, которые у меня возникают при решении той или иной задачи. Например, на собеседовании в казино (я тогда об этом не знал) у меня пытались понять, чем я руководствовался в учебных проектах: почему принимал те или иные решения, почему создавал какие-то артефакты.
«Спросить» — где основным ожиданием от меня было получение «типового» ответа. Например, на собеседовании в финтех-компанию мне задали задачу: есть 2 таблицы — «покупка» и «пользователь». Нужно написать запрос, чтобы вывести всех пользователей, которые делали покупки в заданном диапазоне дат.
Оба варианта включают в себя блок теории из списка «Топ миллиард вопросов системному аналитику». Однако речь идёт именно о практической части. Субъективно считаю, что первый подход более ценен в собеседовании, поэтому я склоняюсь к вопросам, где нет однозначно правильного ответа.
Итого: необходимо придумать задание, которое будет проверять навык задавать вопросы и позволит оценить рассуждения кандидата без ожидания заранее шаблонного решения.
Мне понравилась идея из статьи про калькулятор: даже к самым простым программам может быть множество требований, которые можно выявить только через вопросы. Ещё как-то мы обсуждали это с руководителем тестирования, и он сказал, что у них раньше (может и сейчас) было модно спрашивать: «Как протестировать сковородку?».
Была сформирована концепция, удовлетворяющая поставленным выше требованиям:
Я играю роль заказчика.
Даю простое требование: приложение с 1–2 функциями.
Бизнес- или нефункциональные требования могут меняться для любого человека, если он работает с тем же самым приложением, что и предыдущий кандидат.
Кандидат должен сформулировать требования к системе, но сделать получится только через вопросы.
С этой идеей я попросился поучаствовать в собеседовании стажёров следующей волны, которые приходили после окончания второго курса. Мою идею поддержали и разрешили мне принять участие в собеседованиях, чему я был очень рад конечно же.
Задания
Сформированная концепция и референс в виде калькулятора позволили быстро накидать достаточное количество идей заданий. Ниже представлены идеи заданий, оформленные в html формате для большей наглядности.
1. Приложение для сложения двух чисел
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Сложение чисел</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 20px;
}
input, button {
margin: 5px;
}
</style>
</head>
<body>
<h2>Сложение двух чисел</h2>
<input type="number" id="num1" placeholder="Первое число">
<input type="number" id="num2" placeholder="Второе число">
<button onclick="addNumbers()">Сложить</button>
<p>Результат: <span id="result">—</span></p>
<script>
function addNumbers() {
const number1 = parseFloat(document.getElementById('num1').value);
const number2 = parseFloat(document.getElementById('num2').value);
const sum = number1 + number2;
document.getElementById('result').textContent = isNaN(sum) ? 'Ошибка ввода' : sum;
}
</script>
</body>
</html>
2. Будильник
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Будильник</title>
<style>
body {
font-family: 'Segoe UI', sans-serif;
background: #f0f8ff;
text-align: center;
padding-top: 50px;
}
h2 {
color: #2c3e50;
}
input, button {
padding: 10px;
font-size: 16px;
margin-top: 10px;
border-radius: 5px;
border: 1px solid #ccc;
}
button {
background-color: #3498db;
color: white;
cursor: pointer;
}
button:hover {
background-color: #2980b9;
}
.alarm-set {
margin-top: 20px;
color: green;
}
</style>
</head>
<body>
<h2>Будильник ⏰</h2>
<label for="alarmTime">Установи время:</label><br>
<input type="time" id="alarmTime"><br>
<button onclick="setAlarm()">Установить</button>
<div id="alarmStatus" class="alarm-set"></div>
<audio id="alarmSound" src="https://www.soundjay.com/buttons/beep-07.mp3" preload="auto"></audio>
<script>
let alarmTime = null;
let alarmTimeout = null;
function setAlarm() {
const timeInput = document.getElementById('alarmTime').value;
const alarmStatus = document.getElementById('alarmStatus');
if (!timeInput) {
alarmStatus.textContent = "Пожалуйста, выбери время.";
alarmStatus.style.color = 'red';
return;
}
const now = new Date();
const alarmDate = new Date(now.toDateString() + ' ' + timeInput);
if (alarmDate <= now) {
alarmDate.setDate(alarmDate.getDate() + 1); // на следующий день
}
const timeToAlarm = alarmDate - now;
if (alarmTimeout) clearTimeout(alarmTimeout);
alarmTimeout = setTimeout(() => {
document.getElementById('alarmSound').play();
alert("⏰ Время просыпаться!");
}, timeToAlarm);
alarmTime = timeInput;
alarmStatus.textContent = "Будильник установлен на " + timeInput;
alarmStatus.style.color = 'green';
}
</script>
</body>
</html>
3. Вызов официанта
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Вызов официанта</title>
<style>
body {
background-color: #fff8f0;
font-family: 'Segoe UI', sans-serif;
text-align: center;
padding-top: 100px;
}
h1 {
font-size: 32px;
margin-bottom: 40px;
}
button {
background-color: #e67e22;
color: white;
border: none;
padding: 20px 40px;
font-size: 24px;
border-radius: 12px;
cursor: pointer;
transition: background-color 0.3s ease;
}
button:hover {
background-color: #d35400;
}
#status {
margin-top: 30px;
font-size: 22px;
color: #2c3e50;
}
.bell {
font-size: 60px;
color: #e67e22;
margin-bottom: 20px;
}
</style>
</head>
<body>
<div class="bell">?</div>
<h1>Нужна помощь?</h1>
<button onclick="callWaiter()">Вызвать официанта</button>
<div id="status"></div>
<script>
function callWaiter() {
const status = document.getElementById('status');
status.textContent = "Официант уведомлён, ожидайте...";
setTimeout(() => {
status.textContent = "";
}, 10000); // Через 10 секунд статус исчезает
}
</script>
</body>
</html>
4. Приложение для заметок
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Заметки</title>
<style>
body {
font-family: 'Segoe UI', sans-serif;
background: #f5f5f5;
padding: 30px;
max-width: 700px;
margin: auto;
}
h1 {
text-align: center;
color: #333;
}
textarea {
width: 100%;
height: 150px;
padding: 15px;
font-size: 16px;
margin-bottom: 10px;
border-radius: 8px;
border: 1px solid #ccc;
resize: vertical;
}
button {
padding: 10px 20px;
font-size: 16px;
background-color: #2ecc71;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
margin-right: 10px;
}
button:hover {
background-color: #27ae60;
}
ul {
list-style-type: none;
padding: 0;
margin-top: 20px;
}
li {
background: white;
padding: 12px;
margin-bottom: 10px;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
position: relative;
}
.delete-btn {
position: absolute;
right: 15px;
top: 15px;
background: #e74c3c;
color: white;
border: none;
padding: 5px 10px;
font-size: 14px;
border-radius: 5px;
cursor: pointer;
}
.delete-btn:hover {
background: #c0392b;
}
</style>
</head>
<body>
<h1>Мои заметки</h1>
<textarea id="noteInput" placeholder="Введите заметку..."></textarea>
<br>
<button onclick="addNote()">Сохранить</button>
<button onclick="clearAll()">Очистить все</button>
<ul id="notesList"></ul>
<script>
const noteInput = document.getElementById('noteInput');
const notesList = document.getElementById('notesList');
function loadNotes() {
const notes = JSON.parse(localStorage.getItem('notes')) || [];
notesList.innerHTML = '';
notes.forEach((note, index) => {
const li = document.createElement('li');
li.textContent = note;
const delBtn = document.createElement('button');
delBtn.textContent = 'Удалить';
delBtn.className = 'delete-btn';
delBtn.onclick = () => deleteNote(index);
li.appendChild(delBtn);
notesList.appendChild(li);
});
}
function addNote() {
const text = noteInput.value.trim();
if (text) {
const notes = JSON.parse(localStorage.getItem('notes')) || [];
notes.push(text);
localStorage.setItem('notes', JSON.stringify(notes));
noteInput.value = '';
loadNotes();
}
}
function deleteNote(index) {
const notes = JSON.parse(localStorage.getItem('notes')) || [];
notes.splice(index, 1);
localStorage.setItem('notes', JSON.stringify(notes));
loadNotes();
}
function clearAll() {
if (confirm("Вы уверены, что хотите удалить все заметки?")) {
localStorage.removeItem('notes');
loadNotes();
}
}
loadNotes();
</script>
</body>
</html>
5. Приложение для смены картинок
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Смена картинок</title>
<style>
body {
font-family: 'Segoe UI', sans-serif;
text-align: center;
padding-top: 50px;
background-color: #f0f8ff;
}
img {
width: 300px;
height: auto;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
margin-bottom: 20px;
transition: opacity 0.5s ease;
}
button {
padding: 10px 20px;
font-size: 18px;
background-color: #3498db;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background-color: #2980b9;
}
</style>
</head>
<body>
<h2>Нажми кнопку, чтобы сменить картинку</h2>
<img id="image" src="https://placekitten.com/300/200" alt="Случайная картинка">
<br>
<button onclick="changeImage()">Сменить картинку</button>
<script>
const images = [
"https://towiki.ru/images/thumb/c/ca/%D0%9F%D1%80%D0%BE%D1%81%D0%BF%D0%B5%D0%BA%D1%82-%D0%9B%D0%B5%D0%BD%D0%B8%D0%BD%D0%B0-DSC31052.jpg/300px-%D0%9F%D1%80%D0%BE%D1%81%D0%BF%D0%B5%D0%BA%D1%82-%D0%9B%D0%B5%D0%BD%D0%B8%D0%BD%D0%B0-DSC31052.jpg",
"https://picsum.photos/300/200",
"https://placebear.com/300/200",
"https://place-puppy.com/300x200",
"https://loremflickr.com/300/200/nature"
];
let currentIndex = 0;
function changeImage() {
currentIndex = (currentIndex + 1) % images.length;
const img = document.getElementById('image');
img.style.opacity = 0;
setTimeout(() => {
img.src = images[currentIndex];
img.style.opacity = 1;
}, 300);
}
</script>
</body>
</html>
6. Полив растений
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Полив растений</title>
<style>
body {
font-family: 'Segoe UI', sans-serif;
background: linear-gradient(to top, #d0f0c0, #ffffff);
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
}
h2 {
margin-top: 40px;
color: #2e7d32;
}
button {
font-size: 18px;
padding: 12px 28px;
margin-top: 20px;
background-color: #4caf50;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease;
}
button:hover {
background-color: #388e3c;
}
#plant-container {
position: relative;
margin-top: 40px;
width: 200px;
height: 250px;
}
#plant {
width: 100%;
height: auto;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
}
.water-drop {
position: absolute;
width: 12px;
height: 12px;
background: rgba(30, 144, 255, 0.7);
border-radius: 50%;
animation: drop 1.2s ease-out forwards;
}
@keyframes drop {
0% {
top: -20px;
opacity: 1;
}
100% {
top: 140px;
opacity: 0;
}
}
</style>
</head>
<body>
<h2>Полей растение ?</h2>
<button onclick="waterPlant()">Полить</button>
<div id="plant-container">
<img id="plant" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTqq2wORHOycpYxphh6btWVQogQPPI1kxKBug&s" alt="Растение">
</div>
<script>
function waterPlant() {
const container = document.getElementById('plant-container');
for (let i = 0; i < 10; i++) {
const drop = document.createElement('div');
drop.className = 'water-drop';
drop.style.left = `${30 + Math.random() * 40}%`;
drop.style.animationDuration = `${0.8 + Math.random() * 0.6}s`;
container.appendChild(drop);
setTimeout(() => {
drop.remove();
}, 1500);
}
}
</script>
</body>
</html>
Результаты
Мои ожидания были более оптимистичными. Какое количество заданий, такое и количество студентов пытались к нам попасть. Всем было сказано, что я заказчик (что нужно задавать вопросы, я напрямую естественно не говорил) и мне необходима следующая система, попробуйте описать требования к этой системе.
В итоге: все забыли про какие-то требования кроме функциональных и только двое пытались задавать вопросы. В основном все просто говорили только то, что должна делать система, по сути, переформулировка моих слов, но никто не задался вопросом Зачем и Как. Меня этот факт реально удивил. При чем, чем более простое задание, тем более сложным оно оказалось. В ситуации со сложением двух чисел, кроме функции непосредственно подразумеваемой в названии, кандидатам было сложно что-то сказать - приходилось делать явные намеки.
Хотя результаты были не самыми положительными, задания оказались очень показательными: они наглядно продемонстрировали важность ключевого для аналитика навыка — умения задавать вопросы, который на самом деле далеко не так прост и очевиден.
P.s. тех двоих, кто задавал какие-то вопросы мы в итоге взяли на стажировку.
Это была моя история, которой мне захотелось поделиться, если кто-то имеет другое мнение по отношению к ключевому навыку аналитика или к подходу проведения собеседований, или задачам предлагаемым к кандидатам, то буду рад услышать.
Думаю, что я не единственный кто придумал и использовал подобные задания, поэтому если у вас есть другие варианты или истории, то было бы круто пополнить коллекцию!
Также хочу отметить, что аналитик, в том числе стажер, должен обладать разным навыками, для каждой позиции они свои, о них можно поговорить в другой раз или в другой статье.
ivankudryavtsev
Чувствую, что мне сейчас насуют минусов в карму, но тут не высказаться невозможно. Знаю я один такой факультет в Сибирском ВУЗе из трех букв.
Считаю это одной из крупных ошибок, совершаемых в высшем образовании. Людей уже на втором курсе насильно закидывают в колесо разработки (иди, куда возьмут).
В итоге, студент вместо того, чтобы потратить лучшие студенческие годы на развитие горизонтальных связей, обучение тому как учиться, фактически активно коммерциализируется и далее не готов что-то делать «бесплатно» - лабы, курсовые. Я уверен, что это это ведет к снижению качества образования и сводит его где-то к «выпускникам курсов».
Есть решения правильные, а есть простые - закидывать на стажировку на втором курсе - простое и сомнительное решение. Кому надо - сам начнет работать, а ВУЗ должен учить студента найти свое место в жизни, а не «срезать» амбиции - это подходит для тех, кто звезд с неба не хватает, спору нет.
Если бы был хороший 3х летний инженерный техникум - он должен был бы делать именно так, но это не уровень ВУЗа.
N1X
Ну т.е. повсеместная система "Вышка просто ради диплома для всех", когда студенты работают с устаревшими технологиями, а преподают порой люди, вообще не знающие состояние отрасли, давала лучшее качество образования?
Здесь скорее от человека зависит. Тот кто имеет предрасположенность - всегда установит эти самые связи. А интроверт - куда его не запихни будет в уголочке сидеть. Вряд ли в универах без "коммерциализации" студентов как-то специально развивают социальные навыки и прорабатывают с психологом проблемы...
Это я о том, что если эта "коммерциализация" полностью не заменяет учебный процесс - так возможно все не так уж и плохо.
ivankudryavtsev
А Университет и не должен преподавать «технологии», он должен преподавать базу для развития знаний. Технологии приходят и уходят, а логика, дискретная математика, алгебра, реляционные СУБД, теория алгоритмов и структур данных, управление памятью, численные методы, функциональные, императивные, декларативные ЯП и т.п. остаются.
Современные средства разработки на базе ИИ позволяют любую прикладную штуку изучить и запилить по-быстрому. А вот оценить ее качество - для этого нужны базовые знания.
Да я так же считал лет 15 назад, как и Вы. Теперь - нет)
N1X
Ну может быть я выразился не совсем корректно. Под технологиями я понимал не непосредственно языки/фреймворки, а вообще применяемые на практике в отраслях подходы. Потому что к сожалению очень большое количество учебных заведений вообще оторваны от реальности. Поправка: были в конце нулевых, возможно конечно все сильно поменялось в лучшую сторону и я не объективен... По крайней мере часто даже если что-то и давалось - оно давалось так криво что было не понятно зачем это нужно и как и где применять. В итоге к тому моменту когда это нужно оно уже безнадежно забыто. Я не считаю что даже в таком виде ВУЗ бесполезен, однозначно полезен, но вот как раз теория в связке с практикой как по мне коэффициент полезности может здорово поднять, главное не из крайности в крайность.
ivankudryavtsev
Вы все правильно говорите - актуальность учебного процесса - это вопрос. В общем-то, этот заход с "продажей" - это пораженческое решение в поисках результата. Конечно, учебный процесс, даже в части базовых знаний должен адаптироваться к духу времени.