[컴] 80열은 지키지 않아도 괜찮다.

80 cols / 80 columns /

80열은 지키지 않아도 괜찮다.

개인적으로도 여러가지 생각이 들었지만, 그래도 80열을 맞추는 것이 가독성을 더 좋게 할 것이라 생각했다. 예를 들면, 신문의 타이포그래피를 봐도 그렇지만, width를 일정수준으로 맞춰놓는다. 이것이 확실히 한눈에 한줄을 보기 쉽게하고, 빠르게 읽을 수 있게 해준다.

이런 장점이 있지만, code 는 그것과는 조금 다르게 보는 것이 맞을 듯 하다. 필자도 때론 한줄에 적는것이 더 좋을 것 같은 코드라인을 본다. 하지만 어떻게 하면 80을 맞출 수 있을까 생각한다.

나만 그러고 있는 듯 하지만, 더이상 80열을 심각하게 고려할 필요는 없을 듯 하다. 유명한 개발자가 한 이야기라 더 설득력이 있게 들린다. (물론 리누스는 리눅스 커널코드에 대한 이야기를 한 것이긴 하다.)

이것때문에 사내 좀 더 젊은 개발자에게 물어본 적이 있는데, 80열을 맞춰야 된다는 생각을 가진 분들은 없더라.^^;;;

간략하게 이야기하자면, 더이상 우리는 작은 터미널화면을 사용하던 시대에 살지 않으며, 더이상 그것을 고려할 이유가 없다고 이야기한다. 80열 터머널을 가진 유저는 wrapping 기능을 이용하면 그만이라고 설명한다.

끊임없이 변한다. 그래서 꾸준히 학습해야 한다. IT세상은 지루할 틈은 없어보인다.

Reference

  1. 80-characters-per-line limits should be terminal, says Linux kernel chief Linus Torvalds • The Register

[컴] spring에서 test container 사용시간 단축하기

 

test container / testcontainer / 스프링에서 / 스프링부트 / springboot / 스프링

spring에서 test container 사용시간 단축하기

test container 를 이용해서 test 를 하면, container 를 load 하는 시간이 오래걸린다. 개인적으로 ssd 가 아닌 hdd 에서 동작하도록 해서 그런지 더 실행시간이 오래걸렸다.

그래서 test 를 자주 하려면, 최대한 test container 의 실행을 줄이는 것이 좋다. 즉, 덜 자주 unload , load 를 하는 것이 낫다.

container 를 1번만 실행

Testcontainer 를 사용하면 test class에 @Testcontainers를 사용하게 된다. 이것은 매 class마다 container 를 실행하게 된다.

대체로 test container 를 이용해서 test 를 하면, container 를 load 하는 시간이 오래걸린다. 개인적으로 ssd 가 아닌 hdd 에서 동작하도록 해서 그런지 더 실행시간이 오래걸렸다.

때문에, test 를 자주 하려면, 최대한 test container 의 실행을 줄이는 것이 좋다. 즉, 덜 자주 unload , load 를 하는 것이 낫다.

그래서 이것을 우리는 이것을 전체 test 에서 1번만 실행하게 할 것이다.

위 글에도 나와 있지만 static variable 에 할당하는 것으로 container 의 생성을 1번으로 만든다.

datasource 의 설정

이것은 ApplicationContextInitializer 를 이용한다.

특정 profile 에서는 현재 띄워져있는 container 를 사용하도록 한다

testcontainer를 부하를 줄이려 1번만 load 한다고 해도, TDD 등을 할때는 속도가 엄청 느리다. 계속 unload/load 가 이뤄지기 때문에 빠른 개발이 어렵다.

그래서 build 시점에는 testcontainer 를 사용해서 test 를 하지만, 개발을 할때는 현재 띄워져 있는 container에 접속해서 test 할 수 있도록 했다.

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(initializers = TestcontainersInitializer.class)
class FishApplicationTests {
}
...


public class TestcontainersInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    private static final String MIGRATION_LOCATION = "filesystem:db/migration";
    public static final MariaDBContainer<?> mariaDB = new MariaDBContainer<>("mariadb:10.6")
            .withDatabaseName("myapp")
            .withUsername("myapp-user")
            .withUrlParam("useBulkStmts", "false")
            .withPassword("strong-password")
            .withReuse(true);

    public static final LocalStackContainer localStack = new LocalStackContainer(
            DockerImageName.parse("localstack/localstack"))
            .withServices(LocalStackContainer.Service.S3)
            .withReuse(true);

    public static final KafkaContainer kafka = new KafkaContainer(
            DockerImageName.parse("confluentinc/cp-kafka:7.5.0"))
            .withReuse(true);

    /*
     * Static block runs before Spring Boot starts the application context.
     */

    @Override
    public void initialize(@NotNull ConfigurableApplicationContext ctx) {
        // if system.property active profile is test, do not start containers
        final String EXCLUDE_PROFILE = "testnocontainer";
        var activeProfiles = ctx.getEnvironment().getActiveProfiles();
        if (activeProfiles.length <= 0 || !activeProfiles[0].equals(EXCLUDE_PROFILE)) {
            // if active profile is NOT 'testnocontainer'

            // 만약 여러개의 test class 를 실행하면 이부분은 당연히 여러번 실행된다. 하지만 괜찮다.
            // static 이라서 여러번 실행되지 않았다.

            /**
             * This routine runs multiple times, but due to the use of the static variables,
             * it only works once
             */
            /*
             * deepStart() is used to start containers in parallel.
             */
            Startables.deepStart(mariaDB, localStack, kafka).join();
            
            runMigrations(); // run flyway

            // 여기를 실행하지 않는 profile 은 application.xml 의 datasource 쪽을 바라보게 된다.
            // 그러므로 datasource setting 을 해놔야 한다.
            TestPropertyValues.of("spring.datasource.url=" + mariaDB.getJdbcUrl())
                .and("spring.datasource.username=" + mariaDB.getUsername())
                .and("spring.datasource.password=" + mariaDB.getPassword())
                .and("spring.kafka.bootstrap-servers=" + kafka.getBootstrapServers())
                .applyTo(ctx);
        }
    }

    private static void runMigrations() {
        Flyway.configure()
                .dataSource(mariaDB.getJdbcUrl(), mariaDB.getUsername(),
                        mariaDB.getPassword())
                .locations(MIGRATION_LOCATION)
                .schemas(mariaDB.getDatabaseName())
                .baselineOnMigrate(true)
                .load().migrate();
    }
}

See Also

  1. 쿠…sal: [컴] Spring Test 에서 @Sql 을 code 로

[컴] AI 에서 어떻게 model 을 디자인 하는 것일까?

 

AI 에서 어떻게 model 을 디자인 하는 것일까?

아래 영상을 보고 간단하게 keras 를 이용해서 ai model 을 만들어볼 수 있다.

  • Make Your First AI in 15 Minutes with Python - YouTube
  • 에러
    • ValueError: Input 0 of layer "sequential_1" is incompatible with the layer: expected shape=(None, 455, 30), found shape=(None, 30) 와 같은 에러가 발생하는데 code에서 model.add(tf.keras.layers.Dense(256, input_shape=x_train.shape[1:], activation='sigmoid')) 로 변경하면 된다. x_train.shape 대신 x_train.shape[1:]를 사용하는 것이다.

여기서 궁금중은 그러면 model 을 만들때 사용한 layer를 어떤 기준으로 추가했느냐이다. 그리고 그 layer에 사용한 activation function 은 어떤 기준으로 선택했는가 이다.

model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Dense(256, input_shape=x_train.shape, activation='sigmoid'))
model.add(tf.keras.layers.Dense(256, activation='sigmoid'))
model.add(tf.keras.layers.Dense(1, activation='sigmoid'))

그럼 어떻게 model 을 만들까?

이것에 대한 대답을 다음 글에서 확인할 수 있을 듯 하다.

이글은 deep learning 의 성능을 향상시키는 방법을 이야기하는데, 여러가지 방법이 있다.

  • 데이터양을 증가시키는 방법
  • 데이터를 normalize 하는 법
  • 데이터를 시각화해서 모양을 봐보라, 그러면 이것이 가우스분포같은지, log분포같은지등을 보고, 필요한 변환을 해볼 수 있다.
  • feature selection
  • 문제를 구성하는 방법을 변경해봐라
  • 여러 알고리즘을 통한 향상
    • 선택한 알고리즘이 best가 아닐 수 있다. linear methods, tree methods, instance methods, 다른 neural network methods 들로 평가해봐라.
    • 논문등 다른 사람들이 했던 비슷한 문제들을 찾아서 아이디어를 얻어라(리서치를 해라)
    • 샘플링한 dataset을 다시 잘 sampling 한다. 예를 들어 train/test 로 나눴다면, train 에 해당하는 dataset이 문제의 대표성을 띠는지 등. 또는 작은 dataset을 사용하고, 그에 맞는 model을 선택해서 테스트해보고 큰 dataset으로 확장해 볼 수도 있다.
  • 알고리즘 튜닝을 통한 향상
    • 진단, overfitting인지 underfitting인지
    • 가중치 초기화
    • 학습률을 조정
    • activation function
    • network topology , 여러가지 구성을 테스트해본다. 1개의 많은 newrons를 갖는 hidden layer를 시도하던지, layer당 적은수의 neuron들을 갖는 deep network 를 시도하던지, 이 2개를 전부해보던지등.
    • batches and Epochs, batch size를 변경하는 것은 gradient를 정의하고, weight들을 얼마나 자주 update하는지를 정한다. epoch는 배치마다 ‘network 에 노출되는 전체 dataset’ 이다.
    • 정규화, overfitting을 억제하는 좋은 방법이다. dropout이라는 정규화기술도 있다.
    • 최정화와 손실, 이전에 최적화는 ‘확률적 경사하강법(stochastic gradient descnet)’ 였지만, 이젠 많은 optimizer들이 있다.
    • 빠른 정지(Early Stopping), 성과가 저하되기 시작하면 학습을 중단한다. 그리고 다른 sample을 만들던지 하는등으로 시간을 절약할 수 있다.

[컴] Docker 의 DockerCli.exe -SwitchDaemon

SwitchDaemon 은 무슨 용도 /

Docker 의 DockerCli.exe -SwitchDaemon

ref. 2 를 보면, linux 에서 windows container 를 실행할 수 없다.

windows 에서는 WSL2 를 제공하기 때문에, linux container 를 실행할 수 있고, windows 이기에 windows container도 실행 가능하다. 그래서 ref. 2 에 보면, linux container와 windows container 를 동시에 실행하는 것도 가능하다.

참고로, Docker for windows에는 windows container를 위해선 WindowsEngine을 사용하고, linux container 를 위해선 LinuxEngine을 사용한다.

engine 변경 방법

이 때 engine 을 변경하는 방법이 DockerCli.exe -SwitchDaemon 이다.

C:\Program Files\Docker\Docker
DockerCli.exe -SwitchDaemon

특정 engine 으로 변환하려면 다음처럼 하면 된다.

DockerCli.exe -SwitchWindowsEngine
DockerCli.exe -SwitchLinuxEngine

References

  1. Run Linux and Windows Containers on Windows 10
  2. docker - Can Windows containers be hosted on Linux? - Stack Overflow
  3. Docker ❤️ WSL 2 - The Future of Docker Desktop for Windows | Docker

[컴] Spring Test 에서 @Sql 을 code 로

springboot test / junit / unittest/ /통합테스트 / .sql / query / 쿼리실행 / 초기 데이터 세팅 / setup / @Sql 대신 사용

Spring Test 에서 @Sql 을 code 로

아래와 같은 annotation 을

@JooqTest
@Sql({"classpath:myquery1.sql", "classpath:myquery2.sql"})
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class MyTests {
    ...
}

아래처럼 변경했다. 아래는 특정 profile 이 아닐때만 sql 을 실행하도록 했다.

@JooqTest
// @Sql({"classpath:myquery1.sql", "classpath:myquery2.sql"})
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class MyTests {

    // require: @JooqTest
    @Autowired
    DSLContext ctx;
    @Autowired
    DataSource dataSource;
    @Autowired
    Environment env;

    ProductStatusBgJobProcessor backgroundJobProcessor;

    @BeforeAll
    void beforeAll() {
        runSqlInitData(dataSource);
    }

    @BeforeEach
    void setUp() {

        ...
    }

    @Test
    void myTest1() throws Exception {

        ...

    }

    private void runSqlInitData(DataSource dataSource) {
        final String EXCLUDE_PROFILE = "testnocontainer";
        var activeProfiles = env.getActiveProfiles();
        if (activeProfiles.length <= 0 || !activeProfiles[0].equals(EXCLUDE_PROFILE)) {
            // when not 'testnocontainer' profile
            ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
            populator.addScripts(
                    new ClassPathResource("myquery1.sql"),
                    new ClassPathResource("myquery2.sql"));
            populator.setSeparator(";");
            populator.execute(dataSource);
        }
    }
}

Spring, Integration Test 에서 sql file을 실행하기

sql script 를 실행하기 위해 다음 4개의 함수를 사용할 수 있다.

  • org.springframework.jdbc.datasource.init.ScriptUtils: SQL 스크립트가 parse되고 실행되는 방법을 완전히 제어할 때 사용
  • org.springframework.jdbc.datasource.init.ResourceDatabasePopulator
    • 내부적으로 ScriptUtils 를 사용
  • org.springframework.test.context.junit4.[AbstractTransactionalJUnit4SpringContextTests](https://docs.spring.io/spring-framework/reference/testing/testcontext-framework/support-classes.html#testcontext-support-classes-junit4)
    • 내부적으로 ResourceDatabasePopulator를 사용
  • org.springframework.test.context.testng.[AbstractTransactionalTestNGSpringContextTests](https://docs.spring.io/spring-framework/reference/testing/testcontext-framework/support-classes.html#testcontext-support-classes-testng)
    • 내부적으로 ResourceDatabasePopulator를 사용

Reference

  1. Executing SQL Scripts :: Spring Framework

[컴] SpringBoot v3 에서 openapi v2 사용

javadoc / 자동 문서 / swagger / api 문서 작성 /

SpringBoot v3 에서 openapi v2 사용

gradle 사용시 spring boot 에서 openapi spec의 문서를 만드려면 아래 build.gradle 처럼 springdoc-openapi-starter-webmvc-ui 를 추가하면 된다.

  • implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'

springboot v3 을 사용한다면 springdoc-openapi 2.x 를 사용해야 한다. springdoc-openapi-starter-webmvc-uispringdoc-openapi-ui의 openapi-v2 이다.

// build.gradle
plugins {
    id 'java'
    id 'org.springframework.boot' version '3.2.1'
    id 'io.spring.dependency-management' version '1.1.4'
}

group = 'com.nsm'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'
}

tasks.named('test') {
    useJUnitPlatform()
}

test

내 springBoot server가 localhost:8080 에 떠있는 경우, 다음 경로로 가면 api 문서 화면이 보인다.

json format은

disable

다음 옵션 2개를 꺼주면 된다.

springdoc.api-docs.enabled=false
springdoc.swagger-ui.enabled=false

문서작성 annotation

일부는 자동으로 만들어주지만, 정확하지 않은 값으로 만들어준다. 명시적으로 api 문서에 값을 넣을때는 annotation 을 활용할 수 있다.

아래를 참고하면 된다.

다만, @RequestBody의 경우 spring 의 annotation 과 겹쳐서 @io.swagger.v3.oas.annotations.parameters.RequestBody 등으로 사용해야 할 수 있다.

@PostMapping
@Operation(summary = "Create a User", description = "This can only be done by the logged in user.")
ResponseEntity<MyResponse> createUser(
        @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "Created User object", 
          required = true, content = @Content(schema = @Schema(implementation = MyPostBody.class))) 
        @Valid @RequestBody MyPostBody user) {
    return ResponseEntity.status(HttpStatus.CREATED)
            .body(userService.createOne(user));
}

Reference

  1. OpenAPI 3 Library for spring-boot

[컴] 구글 워크스페이스 특정계정의 2단계인증 중지 방법

구글 계정/ 구글 어드민 / google workspace / google gsuite /

구글 워크스페이스 특정계정의 2단계인증 중지 방법

2024-01-01 화면 기준

  1. https://admin.google.com/
  2. 메뉴 –> 디렉토리 –> 사용자
  3. 수정하기를 원하는 사용자의 이름을 클릭 –> 상세화면이 보인다.
  4. ‘보안’ 부분으로 간다. 여기서 확장(expand) icon 클릭
  5. ‘본인 확인 요청’ 클릭
  6. 사용 중지

References

  1. 본인 확인 요청, 2단계 인증, 로그인 관련 문제 해결하기 - Google Workspace 관리자 고객센터
  2. 사용자의 본인 확인 요청 일시적으로 사용 중지하기 - Google Workspace 관리자 고객센터