Code Mining. Могут ли аналитики читать код?

Здравствуйте, меня зовут Губин Никита. Ведение современного бизнеса невозможно без множества специалистов различных областей. Каждый из них выполняет свою роль, создавая команду, способную достигнуть поставленных целей.

Эффективность команды напрямую зависит от оптимизации взаимодействия между различными ее членами.

В данном посте я хочу рассмотреть взаимодействие аналитиков и DS-специалистов и способе его оптимизации.

Аналитики используют методы анализа для исследования потребностей деятельности организаций с целью определения проблем и их решений.

DS-специалисты решают задачи бизнеса как техническую. Обрабатывают массивы данных, находят в них новые связи и закономерности.

Результатом их взаимодействия может стать ситуация, в которой DS-специалист листает код для аналитика, который хорошо понимает область и знает, что они ищут.

Подобный сценарий демонстрирует дыру в трудозатратах, решить которую я предлагаю с помощью “Code Mining”.

Code Mining – это метод анализа репозитория программного обеспечения, позволяющий извлечь полезную информацию и артефакты из кода. Он включает в себя:

- Анализ кода проекта;

- Сбор данных и метрик;

- Улучшение процесса разработки программного обеспечения.

Так же может применяться для:

- Выявление закономерностей и тенденций в изменениях кода;

- Оценка качества кода;

- Обнаружение потенциальных ошибок и уязвимостей;

- Создание отчетов и визуализаций.

Аналитики и код

Почему же аналитикам трудно самостоятельно анализировать исходный код?

Выделим несколько причин:

- Незнакомые средства, в виде расширенного поиска по составам репозиториев;

- Непривычное разрозненное расположение информации, которая распределена по умозрительным и непонятным для аналитика признакам;

- Возможное несоответствие документации с исходным кодом.

Решение

В качестве решения было разработано приложение, которое парсит все файлы проекта с кодом в один excel файл, поделенный на логические блоки:

<p>Рисунок 1 Пример работы</p>

Рисунок 1 Пример работы

Преимущество данного решения:

- Привычный инструмент. Excel – один из основных инструментов аналитика;

- Код проекта, состоящий из нескольких файлов, собирается в одном месте;

- За счет структуры файла, у аналитика появляются широкие возможности по фильтрации, анализу и поиску необходимой информации.

Реализация

Код написан на Python и предназначен для разбора кода так же на Python.

В посте будут разобраны ключевые моменты. Полный код доступен по ссылке на Github:

Изначально, необходимо собрать файлы (.py), которые в дальнейшем будем обрабатывать:

#Метод выгрузки данных def folder(fold,pth,filenames): if fold == True: filenames = glob(os.path.join(pth, "*.py")) elif fold == False: for root, dirs, files in os.walk(pth): files = [f for f in files if not f[0] == '.'] dirs[:] = [d for d in dirs if not d[0] == '.'] for file in files: if(file.endswith(".py")): filenames.append(os.path.join(root,file)) return filenames

Предусмотрено 2 варианта сбора:

- Только из указанной папки;

- Из указанной папки и всех подпапок (кроме скрытых).

Задаем DataFrame со структурой будущего excel файла:

# Создаем DataFrame с соответствующими колонками col = ['Стратегия', 'Путь', 'Исходная функция', 'Номер строки фрагмента', 'Тип фрагмента', 'Фрагмент'] df = pd.DataFrame(columns=col)

Построчно обрабатываем файлы:

for i in my_code: counter += 1 # Обрабатываем строку i = i.strip(' ') # Проверка для записи исходной строки if 'def ' not in i: ish += i # Обрабатываем комментарии if i[0] == '#': if per != '': perem() # Заполняем IF не в одну строку if y == 1: df.at[row_in_dataframe, 'Стратегия'] = strategy df.at[row_in_dataframe, 'Путь'] = path df.at[row_in_dataframe, 'Номер строки фрагмента'] = counter df.at[row_in_dataframe, 'Тип фрагмента'] = 'Условие IF' df.at[row_in_dataframe, 'Фрагмент'] = usl row_in_dataframe += 1 usl = '' y = 0 dfwrite('Комментарий') # Обрабатываем пустые строки elif i.strip('\n') == '': continue

Python обладает четкой структурой, поэтому, каждая строка проверяется на условия:

# Обрабатываем переменные elif ('=' in i) and (('if ' or 'else' or 'elif ') not in i): y = 0 p = 1 per += i counterP=counter elif (p == 1) and (('if ' or 'else' or 'elif ') not in i): per += i # Обрабатываем IF с условием в одну строку elif (('if ' or 'else' or 'elif ') in i) and (':' in i): if per != '': perem() if ret != '': reter() dfwrite('Условие If') p = 0

Но если каждую строку просто записывать в DataFrame, то в итоговом результате получим “кашу”.

Элементы часто занимают более одной строки, поэтому в коде предусмотрены флаги, для записи однотипных данных в одну запись. Например, когда подряд объявляются несколько переменных:

Отобранные данные записываются в DataFrame:

#Обработка фрагментов def dfwrite(fragm): global row_in_dataframe, strategy, path, counter, i, df df.at[row_in_dataframe,'Стратегия']=strategy df.at[row_in_dataframe,'Путь']=path df.at[row_in_dataframe,'Номер строки фрагмента']=counter df.at[row_in_dataframe,'Тип фрагмента']=fragm df.at[row_in_dataframe,'Фрагмент']=i row_in_dataframe+=1 pass

Полученный результат записываем в Excel или в csv:

#Параметры и формат сохранения def save(df,xl,pthEnd): if xl == True: df.to_excel(os.path.join(pthEnd, "CodeMine_Result.xlsx")) elif xl == False: df.to_csv(os.path.join(pthEnd, "CodeMine_Result.csv"), encoding="windows-1251", sep="~")

Для удобства работы добавим пользовательский интерфейс:

if __name__ == "__main__": root = Tk() root.geometry('600x400') root.title("Разбор риск-стратегий") var1 = BooleanVar() var1.set(False) var2 = BooleanVar() var2.set(False) lbl = Label(text="Задайте параметры") lbl.pack() frame1 = Frame(borderwidth=1, relief=SOLID) path_label = Label(frame1,text="Введите путь до риск-стратегии") path_label.pack(anchor=NW) path_entry = Entry(frame1, width=50) path_entry.pack(anchor=NW) open_button = Button(frame1,text="Открыть проводник", command=open_dir1) open_button.pack(anchor=NW) frame1.pack(anchor=NW, fill=X, padx=5, pady=5)
<p>Рисунок 2 Интерфейс</p>

Рисунок 2 Интерфейс

Путь до обрабатываемых папок выбираем через проводник:

def open_dir1(): global path_entry,filepath1 path_entry.delete(0, END) filepath1 = filedialog.askdirectory() path_entry.insert(0,filepath1)

А после выполнения программы предлагаем открыть результат:

# Сохраняем полученный DataFrame save(df, xl, pthEnd) resultMess = askyesno(title="Разбор выполнен успешно", message="Открыть полученный файл?") if resultMess == True: if xl == True: os.startfile(os.path.join(pthEnd, "CodeMine_Result.xlsx")) else: os.startfile(os.path.join(pthEnd, "CodeMine_Result.csv"))
<p>Рисунок 3 Сообщение после обработки</p>

Рисунок 3 Сообщение после обработки

Давайте рассмотрим применение программы на примере:

<p>Рисунок 4 Пример разбираемого кода</p>

Рисунок 4 Пример разбираемого кода

Результатом разбора данного фрагмента будет excel файл:

<p>Рисунок 5 Результат разбора</p>

Рисунок 5 Результат разбора

На рисунке 5 можно увидеть, какие переменные используются при работе и как они преобразовываются. А за счет фильтров можно отобрать только необходимую в данный момент информацию:

<p>Рисунок 6 Фильтр по переменной Age</p>

Рисунок 6 Фильтр по переменной Age

Вывод

Данная программа позволила привлечь к проверке исходного кода специалистов, ранее не сталкивающихся с подобными задачами. Полученная обратная связь была позитивной и, сейчас, система проходит активную стадию тестирования.

Очевидно, что это не конечный продукт и на основе обратной связи будут дорабатываться и внедряться различные методы визуализации и обработки данных. Например, на основе графов.

Но уже сейчас, можно дать ответ на вопрос из темы поста. Да, аналитики могут читать код. И основа, заложенная в тему данного поста, является тому подтверждением.

Спасибо за внимание.

11
1 комментарий

Крутая статья! Продолжай писать, интересно)

1