졸업프로젝트 week16

4 minute read

팀원회의

시간을 맞춰 오랜만에 팀원 모두가 회의에 참여하였다. 현재 진행상황과 향후방향에 대해서 의논하고 모여서 프로젝트를 진행하였다.

현재 빌드환경구축에 있어서 팀원 한 명만 갖추어져 있어서, 빌드에 있어서 필요한 것들(ex. 여러대로 여러번 빌드하여 속도 평균값내기. 여러 코드 각각 돌려봄으로써 시간단축)을 원활하게 수행하기 위해 다른 팀원들도 서둘러 빌드환경을 구축해야한다. 빌드환경구축이 된 컴퓨터 한 대로만 빌드를 하기에는 많은 어려움이 발생할 것이다. 나는 지난번 코드설치에 있어서 발생한 에러에 대해 멘토님의 답변들을 토대로 에러를 해결중이며, 곧 빌드환경구축이 될 것 같다.

각자의 진행상황, 전체의 진행상황을 파악 후 이번주는 예정되어 있던 샘플어플 테스팅 및 코드 개선 시도를 진행하기로 하였다.


샘플어플테스팅

개선사항으로 삼고 있는 ContentProviderOperation.java 코드의 withValue 함수의 동작을 보기 위해 블로그를 참고하여 샘플어플을 제작하고 테스팅하였다.

63330141-43091b80-c36e-11e9-9577-0271c9cc8528

테스팅 결과


코드개선시도

우리가 개선하려고 하는 코드 부분은 ContentProviderOperation.java 코드의 withValue 함수로 아래와 같다.

캡처00

반복되는 if-else 문을 줄이기위해서, 성능을 개선하기 위해서 어떤식으로 코드를 개선해야할지 의논하였다. 먼저, 계속해서 언급되었던 해싱 개념을 적용하여 해시맵을 구성하는 방식에 대해 의논하였다. 현재 value의 타입검사 부분에서 if-else문이 반복되고 있기에 value 타입검사 부분을 줄이면 성능이 좋아지지 않을까 판단되어 이 부분에 해싱을 적용해보기로 하였다.

HashMap<Object,Object> valueTypeMap = new HashMap<Object, Object>();
                valueTypeMap.put(String.class,(String)value);
                valueTypeMap.put(Byte.class,(Byte)value);
                valueTypeMap.put(Short.class,(Short)value);
                valueTypeMap.put(Integer.class,(Integer)value);
                valueTypeMap.put(Long.class,(Long)value);
                valueTypeMap.put(Float.class,(Float)value);
                valueTypeMap.put(Double.class,(Double)value);
                valueTypeMap.put(Boolean.class,(Boolean)value);
                valueTypeMap.put(byte[].class,(byte[])value);
                mValues.put(key,valueTypeMap.get(value.getClass()));

위와 같이 key와 value를 모두 Object 타입으로 갖는 valueTypeMap 이라는 value 타입검사 해시맵을 생성하고, 그 안에 value의 타입들을 .class로 인스턴스를 생성하여 key 값으로 넣어주었다. 그리고 mValues에 value의 타입에 맞게 put이 되도록 만들어 주었다.

그러나 자료형 체크를 getclass로 하는 것보다 getName()을 통해 스트링 비교를 하는것이 함수 테스트 결과 더 빠른것으로 나타나 아래와 같이 해시맵의 key 타입을 String으로 바꾸고, getName()을 사용하는 것으로 수정하였다.

HashMap<String,Object> valueTypeMap = new HashMap<String, Object>();
                valueTypeMap.put(String.class.getName(),(String)value);
                valueTypeMap.put(Byte.class.getName(),(Byte)value);
                valueTypeMap.put(Short.class.getName(),(Short)value);
                valueTypeMap.put(Integer.class.getName(),(Integer)value);
                valueTypeMap.put(Long.class.getName(),(Long)value);
                valueTypeMap.put(Float.class.getName(),(Float)value);
                valueTypeMap.put(Double.class.getName(),(Double)value);
                valueTypeMap.put(Boolean.class.getName(),(Boolean)value);
                valueTypeMap.put(byte[].class.getName(),(byte[])value);
                mValues.put(key,valueTypeMap.get(value.getClass().getName()));

이를 실제 코드의 withValue 함수에 적용하였고, 여러번 수정을 거친 결과 만들어낸 withValue 함수는 아래와 같다.

public Builder withValue(String key, Object value) {
           Log.d("withValue","Start"); // 로그 시작
           if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
               throw new IllegalArgumentException("only inserts and updates can have values");
           }
           if (mValues == null) {
               mValues = new ContentValues();
           }
           if (value == null) {
               mValues.putNull(key);
           }
           /* else if (value instanceof String) {
               mValues.put(key, (String) value);
           } else if (value instanceof Byte) {
               mValues.put(key, (Byte) value);
           } else if (value instanceof Short) {
               mValues.put(key, (Short) value);
           } else if (value instanceof Integer) {
               mValues.put(key, (Integer) value);
           } else if (value instanceof Long) {
               mValues.put(key, (Long) value);
           } else if (value instanceof Float) {
               mValues.put(key, (Float) value);
           } else if (value instanceof Double) {
               mValues.put(key, (Double) value);
           } else if (value instanceof Boolean) {
               mValues.put(key, (Boolean) value);
           } else if (value instanceof byte[]) {
               mValues.put(key, (byte[]) value);
           } */
           else {
               try {
                   HashMap<String,Object> valueTypeMap = new HashMap<String, Object>();
                   valueTypeMap.put(String.class.getName(),(String)value);
                   valueTypeMap.put(Byte.class.getName(),(Byte)value);
                   valueTypeMap.put(Short.class.getName(),(Short)value);
                   valueTypeMap.put(Integer.class.getName(),(Integer)value);
                   valueTypeMap.put(Long.class.getName(),(Long)value);
                   valueTypeMap.put(Float.class.getName(),(Float)value);
                   valueTypeMap.put(Double.class.getName(),(Double)value);
                   valueTypeMap.put(Boolean.class.getName(),(Boolean)value);
                   valueTypeMap.put(byte[].class.getName(),(byte[])value);
                   mValues.put(key,valueTypeMap.get(value.getClass().getName()));
               }
               catch (Exception e) { // 예외처리
                   throw new IllegalArgumentException("bad value type: " + value.getClass().getName());
               }
           }
           Log.d("withValue","End"); // 로그 끝
           return this;
       }

mValues의 타입인 ContentValues에 put함수가 오버라이드로 오버로딩되어있는데, 그 안에 해시맵의 get 함수의 리턴타입인 object타입의 put함수가 없어서 아래와 같이 별도로 추가하였다.

public void put(String key, Object value) {
        mValues.put(key, value);
    }

    /**
     * Adds a null value to the set.
     *
     * @param key the name of the value to make null
     */

cf) 또한 해싱기법과 별개로 컴파일러가 최적화시에 if-else문보다 switch문이 조금 더 유리하다, switch문의 성능이 조금 더 좋다는 검색 결과들을 기반으로 if-else문을 switch문으로 바꾸어보는 시도를 하였다.

public Builder withValue(String key, Object value) {
    if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
        throw new IllegalArgumentException("only inserts and updates can have values");
    }
    if (mValues == null) {
        mValues = new ContentValues();
    }
    /*if (value == null) {
        mValues.putNull(key); */
    switch(value)
    {
      case value == null:
        mValues.putNull(key);
      case value instanceof String:
        mValues.put(key, (String) value);
        break;
      case value instanceof Byte:
        mValues.put(key, (Byte) value);
        break;
      case value instanceof Short:
        mValues.put(key, (Short) value);
        break;
      case value instanceof Integer:
        mValues.put(key, (Integer) value);
        break;
      case value instanceof Long:
        mValues.put(key, (Long) value);
        break;
      case value instanceof Float:
        mValues.put(key, (Float) value);
        break;
      case value instanceof Double:
        mValues.put(key, (Double) value);
        break;
      case value instanceof Boolean:
        mValues.put(key, (Boolean) value);
        break;
      case value instanceof byte[]:
        mValues.put(key, (byte[]) value);
        break;
      default:
        throw new IllegalArgumentException("bad value type: " + value.getClass().getName());
        break;	            	
    }
    return this;
}

위의 switch문은 정말 아무생각없이 if-else 문을 그대로 옮긴것이기에 개념적으로 안 맞는 부분이 있었다. case 뒤에는 값이 들어가야 한다는 개념이 맞지 않아, 링크를 참고하여 switch문으로 다시 바꾸어보았다.

public Builder withValue(String key, CLAZZ value) {
    if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
        throw new IllegalArgumentException("only inserts and updates can have values");
    }
    if (mValues == null) {
        mValues = new ContentValues();
    }       
    CLAZZ value = CLAZZ.valueOf(value.getClass().getName());
    switch(value)
    {
      case null:
        mValues.putNull(key);
        break;
      case St:
        mValues.put(key, (String) value);
        break;
      case By:
        mValues.put(key, (Byte) value);
        break;
      case Sh:
        mValues.put(key, (Short) value);
        break;
      case In:
        mValues.put(key, (Integer) value);
        break;
      case Lo:
        mValues.put(key, (Long) value);
        break;
      case Fl:
        mValues.put(key, (Float) value);
        break;
      case Db:
        mValues.put(key, (Double) value);
        break;
      case Bl:
        mValues.put(key, (Boolean) value);
        break;
      case Bt:
        mValues.put(key, (byte[]) value);
        break;
      default:
        throw new IllegalArgumentException("bad value type: " + value.getClass().getName());
        break;	            	
    }
    return this;
}
       
enum CLAZZ {
  St,By,Sh,In,Lo,Fl,Db,Bl,Bt;
}

각 타입마다 enum 객체를 만들어서, 해당 객체값의 case에 해당되는 key와 value를 put하는 방식으로 switch문을 개선해보았다.

이렇게 코드를 여러 방면으로 개선해보려고 시도하였다. 개선코드를 빌드하면서 에러도 발생하고, 빌드하는데에 시간이 오래걸려서 개선한 코드들을 완벽히 빌드해보지 못 했다. 추후 빌드를 모두 해보아야할 것 같다.


향후계획

빌드환경구축 덜 된 팀원들 환경구축.

개선해본 코드들 빌드해보기.

추후 개선할 코드부분 찾아보기.

Tags:

Categories:

Updated: