소스코드 (변수, 함수, 클래스)네이밍 데이터 분석해 보기
종종 보게 된 페이스북 피드글 중에서...
프로그래머 4,522명이 대답했습니다.
네이밍(이름 짓기)은 나에게 많은 고민과 선택을 하게 만든다.
대충 지은 클래스 네이밍 하나 때문에 코드가 걸레가 되기도 하고,
잘 조합된 네이밍 규칙 하나로 소스가 구조적, 기능적으로 술~술~ 잘 풀리기도 한다.
그래서 이 중요한 네이밍에 대하여 알아봤습니다!!
참고로 아래 분석을 좀 더 진행하고자 하시는 분은 분석의 전체 과정을 담은 https://github.com/goodvc78/naming-feature-analysis 저장소의 소스를 다운받아서 진행하시면 됩니다.
오픈소스의 네이밍 특징들
우선, Github Most Starred Java에서 많은 이들이 알만한 소스 20개 선별하여 Clone 받고,
Clone 받은 소스의 총 52,887개 Java파일에서 변수/함수/클래스 네이밍을 추출하였다.
Java 소스코드에서 네이밍 추출
Regular Expression을 적절히 사용하여 주석을 제거하고,
Line단위로 변수/함수/클래스 네임을 인식할 수 있는 심플한 패턴만 만들어서 네이밍을 추출합니다.
Java 주석 제거 : 싱글 라인(//), 멀티라인 패턴(/* */) 찾아서 제거
변수 이름 추출 : 변수는 변할 수 있는 값이기 때문에 equal(=) 연산자의 left token을 변수 인식함
함수 이름 추출 : 단순히 '('로 split을 해서 left token이 함수가 될 수 있는 문자셋으로 구성된 것을 찾음
--> 이 패턴은 함수와 클래스가 명확히 분리되지 않아 클래스 이름도 종종 포함된다.
클래스 이름 추출 : class 단어가 오고, 공백 그리고 클래스 이름으로 허용되는 문자셋으로만 구성된 것 찾음.
추출된 네이밍에서 Java 언어의 예약어 및 'test'를 포함하는 네이밍은 제거
abstract default package synchronized boolean do if private this break double implements protected throw byte else import public throws switch enum instanceof return try catch extends int short char final interface static void class finally long strictfp volatile float native super while continue for new case goto null transient const operator future generic ineer outer rest var test
이렇게 하면 100% 정확하지는 않지만 데이터 분석에 괜춘하게 추출됩니다.
조합된 네이밍 단어를 Tokenizing
일반적으로 클래스/함수/변수 네이밍은 Java Naming rule 인 Camel Case를 기준으로 UpperCamelCase, lowerCamelCase, lower_delimiter_case, UPPER_DELIMITER_CASE 방식으로 조합되었기 때문에 이 기준으로 단어를 분리한다.
"parseDBMXMLFromIPAddress" -> ['parse', 'DBMXML', 'From', 'IP', 'Address']
Tokenize 된 단어의 품사 Tagging
단어의 연결 구조를 분석하기 위해 형태소 분석기인 NLTK(Natural Language Toolkit)로 아래 예시와 같이 품사 Tagging을 합니다.
[parse, DBMXML, From, IP, Address]
-> [parse[NN], 'dbmxml[NN], from[IN], ip[NN], address[NN]]
소스로부터 추출한 네이밍 데이터 셋
네이밍의 특징들을 찾아내기 위한 기본 데이터 셋을 만듭니다.
. 네임밍 데이터셋
. 품사가 Tagging 된 데이터셋
이제부터 좋은 오픈 소스는 어떤 네이밍 특징을 가지고 있는지 탐색해 보도록 하겠습니다.
Java 네이밍 rule을 잘 지키는 클래스, 함수, 변수
네임들의 출현 빈도 기준으로 된 WordCloud 결과를 통해 대략적으로 판단합니다
클래스는 대문자로 시작하는 UpperCamelCase
함수는 소문자로 시작하는 lowerCamelCase
변수는 소문자로 시작하는 lowerCamelCase
그리고 상수는 대문자와 '_'분리하는 UPPER_DELIMITOR_CASE
클래스 네임 Word Cloud
대문자로 시작하는 UpperCamelCase를 사용하며, 명사 위주의 단어들이 많이 보인다.
함수 네임 WordCloud
소문자로 시작하는 lowerCamelCase 형태의 구성으로 동사도 많이 보이는듯함.
예상대로 명확히 분류되지 않아 클래스 명도 종종 포함되어 있음이 확인됨.
변수 네임 WordCloud
단어 하나로 많이 표현되고,
가장 많이 쓰는 'i' 그리고 어디에서 있어야 할 'LOG' 가 떡하니 중앙에 자리 잡고 있네요.
유니크한 네이밍 비율은 : 변수=함수> 클래스
변수의 네이밍 수가 가장 많다고 생각했는데, 예상외로 함수 네이밍수와 비등하게 많음.
네이밍 된 평균 글자 수는 16자 : 클래스(20자)>함수(18자)>>변수(13자)
네이밍 글자 수는 평균 16자로 생각보다 길게 쓰는 듯했다. 그리고 클래스> 함수>>변수 순으로 네이밍의 글자 수가 달랐는데, 이는 기능이 많고, 스코프를 넓게 가져가는 네이밍 타입의 특성이 적절히 반영된 결과가 아닌가 싶다.
네임들의 글자 수별 분포는 치우침이 없이 아주 아름답게(^^) 정규분포를 잘 따르는 듯하다. 데이터를 다룰 때 이런 분포를 찾아내면 기분이 좋다! 너무 조으다!!!
참고로, Topic(저장소) 별 글자 수 분포
네이밍은 평균 3개 단어로 조합됨
3개 단어의 조합으로 네이밍을 하되, 변수는 짧게 함수와 클래스는 조금 더 길게 네이밍 됩니다..
클래스 네임 : 3.18 단어
함수 네임 : 3.36 단어
변수 네임 : 2.57 단어
네이밍의 품사 분포
많이 사용하는 품사는 명사>>>형용사> 동사입니다.
특히 함수는 동작을 설명하는 동사가 많이 포함된 것이 특징이다.
네이밍의 단어 연결 구조 : [명사|동사|형용사] + 명사 + 명사 +...
처음 단어만 목적에 맞게 품사가 선택되고 그다음 단어부터는 대부분이 명사 연속으로 구성된다.
클래스는 대부분이 명사와 형용사(실제로 명사 잘못 tagging 된 경우가 많음) 조합이고,
함수는 첫 단어에 동사, 형용사가 많다.
그리고 변수는 상태나 값을 가지기 때문에 시제와 단/복수의 형태가 적절히 사용됨이 보인다.
품사별 많이 사용된 단어는?
네이밍 단어 조합 분석을 위한 NLTK의 품사 Tagging의 정확도는 만족스럽지 못하다.
( NLTK는 일반 문장 규칙을 기반으로 구현되었기 네이밍 단어 조합에서는 정확도가 떨어짐이 당연해 보인다.)
클래스 단어의 품사별 사용 단어
명사 위주의 단어와 함께 design pattern과 관련된 단어들의 많은 사용이 보여진다.
함수 단어의 품사별 사용 단어
get, set 단어의 사용빈도와 더불어 동사가 적극적으로 사용됨이 보인다.
변수의 품사별 사용 단어
소스별 Topic 분석해 보기
네이밍의 단어들은 그 소스를 가장 잘 설명하는 용어일 것이다. 그래서 이 단어들의 Topic을 잘 추출해 보면 그 소스가 중요시하는 부분이나 특성을 잘 파악할 수 있을 것 같아 Topic 모델링을 해 보았다. Topic 모델링 방법 중 가장 많이 알려지고 간단한 TF-IDF를 사용하였다.
먼저 단순히 단어 빈도(Term Frequency) 기준으로는 Hadoop 소스(좌)와 ElasticSearch 소스(우)의 확인해 보면 Topic이 제대로 나타나지가 않았다.
그래서 단어 빈도(TF)에 문서 출현 빈도의 역수(IDF)를 Weight로 적용하는 TF-IDF로 Topic 모델링해 보면(아래 WordCloud), 고급진 LSA나 LDA 못지않게 (생각보다) 특징점이 잘 뽑여 나오는듯하다. (예상보다 예쁘게 잘 나와서 기분이 좋다.)
Elastic Search 소스의 Topic
아래 Elastic Search 소스의 Topic을 보면 는 shard, cluster, routing 등 분산 처리 기능의 위해 구현체가 많이 들어 있는 듯 보인다.
Hadoop 소스의 Topic
Hadoop 소스는 timeline, job, yarn, dfs, conf 등 분산 저장과 처리를 위한 Job 스케줄링과 자원 관리에 에 많은 신경을 쓴 소스로 보인다.
각 소스의 Topic 들
이렇게 Topic을 보고 있으니 소스를 분석을 시작할 때 주요 Topic 중 모르는 용어는 찾아 보고 시작하면 소스 분석이 훨 수월해질 것 같다는 생각도 든다.
어떤 소스들이 유사할까?
TF-IDF로 추출된 김에, Topic의 BOW(Bag of Words) Vector로 유사한 소스끼리 군집화 해 봤다.
군집화된 결과도 그럴듯하게 좋았다. 단순히 소스의 커미터끼리 묶인 것이 아닌, 기능이나 목적이 비슷한 계열의 소스끼리 연관되어 군집화 됨을 볼 수 있었다.
가장 유사도가 높은 소스는 목적이 유사한 안드로이드의 이미지 처리 라이브러리인 fresco와 picasso 였다.
1. Java Naming Rule을 철저히 준수한다.
- 클래스는 UpperCamelCase,
함수는 lowerCamelCase,
변수는 lowerCamelCase,
상수는 UPPER_DELIMITOR_CASE
2. 네이밍은 보통 16자, 3 단어로 적절히 길게 짓는다.
- 변수는 조금 짧게, 함수/클래스는 조금 길게
3. 네이밍 단어의 조합은 [명사|형용사|동사] + [명사] + [명사]...로 구성
4. 네이밍에 사용된 단어는 소스를 잘 설명한다.
5. 내가 작성할 소스와 비슷한 소스의 Topic 단어를 사전에 알아두면 좋다.
이번 네이밍 데이터 탐색의 목적은 개인적으로 코딩 시 (좋고 나쁨을 떠나) 네이밍 일관성을 위해
명시적 네이밍 규칙을 찾는 것이 목적인데 나름 적절한 결과를 얻은 듯하다.
그리고 네이밍 데이터를 가만히 보니 네이밍 규칙을 넘어 네이밍 하고자 하는 단어만 입력하면
자동완성처럼 적절한 네임을 추천하는 네이밍 추천 시스템을 만들어도 좋을 듯하다.
(시간 나면 만들어 봐야겠다.)
참고 자료
github 인기 저장소 : http://github-rank.com/star?language=Java
주석 찾기 패턴 : http://blog.ostermiller.org/find-comment
Java Naming Convention : https://en.wikipedia.org/wiki/Naming_convention_(programming)#Java
코드 하이라이트: http://colorscripter.com/
형태소 분석기 : http://www.nltk.org/
Gensim의 TF-IDF:https://radimrehurek.com/gensim/models/tfidfmodel.html
Python Word Cloud Package : https://github.com/amueller/word_cloud