전체 글 441

[Go] slice 크기 조정 - append() 함수의 숨겨진 내부 동작

최근에 golang을 살펴보는 중 slice에서의 재밌는 동작을 하나 보게 되었다.  보통 동적 배열에 새로운 요소를 계속 추가하다가 요소 개수가 다 차면 두 배로 길이를 늘려주고 복사하여 기존 내용을 넣어준다고 알고 있다. Go에서도 slice에 대한 내용 중 비슷하게 두배로 늘려준다는 내용을 발견했다.  하지만 재밌는 점은 실제 1000개의 요소를 slice에 append하면서 append한 결과의 slice capacity를 보니 2의 승수를 따르지 않는 구간이 나타난다는 점이었다.  내 예상대로면 0짜리 capacity에 새롭게 요소를 넣어주는 동작을 1000번 반복한다면 아래와 같이 slice의 capacity를 늘려주는 동작을 할 것이라고 예상했다. 1 2 4 8 16 64 128 256 51..

Go 2024.08.18

[Go] 표준 라이브러리 container/list 코드 분석

최근 golang을 보고 있는데 꽤나 재밌는 내용이 있어서 정리해두고자 한다.  golang에는 표준 라이브러리로 list를 제공한다. 그런데 재밌게도 ring구조를 채택하고 있고, 이를 통해 더미 노드를 하나 만들어서 첫번째 노드의 prev노드로 사용하고, 마지막 노드의 next노드로써 사용한다.이렇게 함으로써 경계값 검사가 쉬워진다는 장점이 있다고 한다.  분석하면서 개인적으로 주석을 달아놓았는데 한번쯤 재밌게 읽을법한 코드라서 아래 첨부한다.   출처:golang에서 기본적으로 제공하는 container/list   // Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-s..

Go 2024.08.11

[Dev] 큐를 사용한 아키텍처에 대한 고민 (메세지 단위)

최근 만들고 있는 어플리케이션에서 큐를 사용하게 되어 큐를 사용하는 아키텍쳐에 대한 고민을 해봤다.  복잡하게 데드레터 정책까지 가져가면서 큐의 메세지에 대한 retry를 실행하려하진 않았다. 실패한 메세지의 경우 어차피 깨진 상태를 갖고 있다고 가정하고 warn 로그를 남기고 아카이브에 해당 작업을 실패로 기록한 뒤 큐에서 곧장 소비해서 없애버리는 정책을 가져가고자 했다.  큐에 넣을 메세지는 어떤 작업을 지시하는 Job에 대한 정보로 사용하고자 했다. 그러다보니 api endpoint를 한 개만 남겨두고 기존에 만들어뒀던 api들을 모두 없애버리는 방법도 있었다. 한 개의 endpoint는 queue에 submit하는 역할만 하는 일종의 producer전용 api가 되는 것이다. 반대쪽 consume..

개발 이야기 2024.05.14

[leetcode] 3079. Find the Sum of Encrypted Integers - Rust

leetcode 문제 중 Rust의 다양한 타입변환을 참고하기 좋은 문제가 있어 기록해둔다.   자세한 내용은 주석에 상세하게 적어두었으니 참고바란다.  알고리즘 문제 풀이 중 가장 기본적인 내용은 타입간 변환이다. i32 -> char -> char 's  -> string -> i32 -> 혹은 u8 u32 usize 등으로 변환이 자유자재로 가능해야한다.  이게 안되면 중간에 막히는 곳이 너무 많다.   /** 1530 ~ 1545 i32 char's string간 변환이 핵심인 듯 하네요 */impl Solution { pub fn sum_of_encrypted_int(nums: Vec) -> i32 { let mut output = 0; f..

[Rust] Rust가 ++연산자를 지원하지 않는 이유

Rust 로 리트코드를 풀던 중 한 문제에서 Rust의 재미있는 특성을 발견했다.  아래 코드를 보면 count += 1이 있다. count++로 사용하려 했으나 컴파일 타임 에러로 인해 사용할 수 없었다.  Rust는 ++, --같은 연산을 허용하지 않는다는 것이 이유였다.  왜 없을까?  우선 안전성과 명확성이 그 이유라고 한다.  명확성의 경우 count += 1처럼 어떤 연산을 하는지 명확하게 보여줄 수 있다고 하는 점 때문이다.이 부분은 조금은 이해가 가지만 안전성이란 대체 어떤 걸 이야기하는 걸까?  ++가 위험하다는 걸까?  알아보니 ++의 경우 사이드 이펙트를 발생시킬 여지를 갖고 있다고 한다. 그 예시가 바로 이런 코드라고 한다. int a = i++ + ++i;이 코드가 컴파일러마다 결..

Rust 2024.05.03

[leetcode] 2451. Odd String Difference - Rust

간만에 카페에서 쉬면서 평화로운 시간을 보낸다. 역시나 쉴때는 리트코드 푸는게 제일 재밌다.  심심해서 Rust로 풀어봤다.   재밌는 문제다. 문제 자체는 쉬운 편인데 Rust로 풀자니 Rust자체의 문법에서 살짝 걸려넘어지는 부분이 있었다. 정리해둘만한 부분이 있는데 같이 살펴보자.  자 우선 for word in &words에서 &로 borrow해서 사용한다. 이렇게 사용하는 이유는 borrow해서 사용하지 않으면 밑에서 words를 참조하려고 할때 위에서 소유권이 이미 이전되었기 때문에 컴파일 에러가 나기 때문에 borrow해서 사용해야 한다. 또 재밌는 부분은 String타입은 개별 word를 접근하려고 할때 String타입 그 자체에서 [] indexing으로 접근할 수 없기 때문에 word...

[leetcode] 1417. Reformat The String in C++

심심해서 오랜만에 c++로 leetcode 문제를 풀어봤다.  1417 Reformat the string 이라는 문제다. 쉬운 문제라 휘리릭 풀 수 있다.  역시나 PS는 한동안 안하면 다시 시작할때 꽤나 하기가 싫은 경향이 있긴 하다.  class Solution {public: string reformat(string s) { vector digits; vector chars; vector result; digits.reserve(s.length()); chars.reserve(s.length()); result.reserve(s.length()); for(char c: s) { ..

[kotlin] 코틀린 inline과 crossinline 키워드

코틀린에 흥미로운 키워드가 하나 있다.  inline과 crossinline이라는건데, 오늘 처음 봤다.  inline함수로 지정하면 컴파일 시 해당 함수의 바이트코드가 호출 지점에 직접 삽입된다고 한다. 이걸 인라인화라고 한다. 그래서 함수 호출의 오버헤드를 줄일 수 있다고 한다.  간단한 함수 있을때 사용하면 조금이나마 성능을 줄일 수 있을 것 같다. 별거없다. 그냥 코드 치환이고 성능 조금 더 올리고 싶을 때 쓰면 된다.  재밌는건 crossinline이라는 생소한 키워드도 있다.  이건 inline 함수의 람다 파라미터에 사용된다. inline 함수 내부에 전달된 람다가 비지역 반환(non-local returns)를 할 수 없음을 나타낸다고 한다. 혹은 방지라는 용어가 더 알맞겠다.  비지역 반..

Kotlin 2024.04.27

[개발 이야기] 신입에서 주니어로

작년 2월에 입사하고 벌써 1년이 훌쩍 넘었다.  졸업하자마자 곧장 신입으로 일했고 이것 저것 하다보니 벌써 신입 타이틀을 떼고 주니어가 되었다는게 신기하다.프론트엔드, 백엔드 등등 가리지않고 많은걸 해볼 수 있었다. 신입, 주니어, 시니어 등등 이런건 그저 호칭에 불과하지만 오늘따라 유독 와닿는 단어인것 같다.  마침 카페에 와서 글을 쓰다보니 유독 의미에 대해 생각하게 되는 것 같다.  처음 입사했을 때 지라 티켓만드는 것도 몰랐고, git rebase를 할 줄 몰라서 꼬인 커밋을 해결하지못하고 다시 clone받아야했던 적도 있다. MR은 어떻게 드려야하는지, 질문은 어떻게 해야하는지 그리고 문서 작성과 업무에 대한 공유까지 모든게 낯설었다. 어려운 프로젝트도 있었고 쉬운 프로젝트도 있었다. 그래서 ..

개발 이야기 2024.04.27

[개발 이야기] exception 핸들링에 대한 고민

최근 exception핸들링에 대해서 고민이 있다. 애플리케이션을 만들때 어떻게 예외를 처리해야할지에 대해 근본적인 해답이 없다는 생각이 든다.  외부 api호출같은 IO작업에서 주로 try catch같은 exception 처리를 하는게 좋은데, 이미 요청이 실패하거나 크리티컬한 이유로 실패해서 exception이 터졌다면 애초에 처리하고자하는 정상적인 상태에서 깨진 상황인데 이상황에서 뭘 더 핸들링할까라는 생각이 든다. 바꿔 말하자면 이미 깨진 상태인데 뭘 더 하겠냐라는 뜻이다.  크리티컬한 이슈가 아닌 경우를 생각해보자면, 뭔가를 등록하려는데 중복 등록이라던지 혹은 워닝으로만 남겨도 될만한 작업이라면 쉽다. 그런데 인증이 잘못되었거나 뜬금없는 timeout 혹은 전혀 대비되지 않았던 예외케이스처럼 크..

개발 이야기 2024.04.26

[kotlin] 코틀린 코루틴에 대한 개념 정리 (4)

코틀린에는 구조화된 동시성이란 개념이 있다고 한다.  꽤나 비중있는 주제인것 같아 깔끔하게 정리해보고자 한다.  코루틴에는 코루틴 내부에서 또 코루틴을 만들 수 있다.이 경우 부모코루틴과 자식 코루틴이 생긴다. 코루틴에는 Job객체로 코루틴을 추적할 수 있는데, Job객체 내부에는 parent와 children이라는 프로퍼티가 있어서 이걸로 부모 자식간 양방향 참조가 가능하다.참고로 parent는 Job?타입이고, children은 Sequence 타입이다. parent가 Job?인 이유는 루트 코루틴의 경우 부모가 없을 수도 있기 때문이다.  그리고 CoroutineContext의 경우 부모에서 자식으로 상속되고, 자식에서 별도의 CoroutineContext를 사용한다면 상속받은걸 덮어씌우게 된다. ..

Kotlin 2024.04.25

[kotiln] 코틀린 코루틴에 대한 개념 정리 (3)

지난번 포스팅에서 코루틴 빌더 함수와 Job객체에 대해 알아보았다.  이번 포스팅에서는 async와 Deferred에 대해서 알아보자.  이전에 배운 launch 코루틴 빌더 함수는 코루틴으로부터 결과값을 받을 수 없었다. 다만 Job객체를 받을 뿐이었다.  그런데 코루틴으로부터 작업에 대한 결과값을 받을 필요가 있을 수 있다. 이때 사용하는데 async와 Deferred응답 객체이다. async(Dispatchers.IO) { ... }와 같이 사용할 경우 Deferred를 리턴받고, 해당 Deferred타입의 변수에 대해 await()메서드를 사용하면 결과를 받을 수 있다. await()을 사용하는 이유는, 코루틴이 언제 완료될지는 모르기 때문에 Deferred가 미래의 값이라는 의미..

Kotlin 2024.04.22

[kotlin] 코틀린 코루틴에 대한 개념 정리 (2)

지난번 포스트에 이어 코틀린 코루틴에 대한 개념 정리를 이어가고자 한다. 코루틴에는 CoroutineStart.LAZY를 사용한 코루틴 지연이라는 개념이 있다. 왜 코루틴을 지연해야할까? 코루틴을 CoroutineDispatcher의 큐에 제출했다고해서, 곧장 코루틴을 특정 스레드에 할당해서 바로 실행해선 안될때 필요하기 때문이다. 그저 실행해야할 코루틴을 미리 만들어두고 나중에 실행시키는 것이다. 이 경우 launch의 start인자로 CoroutineStart.LAZY를 주어 제출하면 된다. 그리고 이후에 실행시킬 필가 있을때 start시키면 된다. 지연하고 나서 이후 시작할 수 있는 방법은 launch 코루틴 빌더함수를 통해 받은 Job객체를 사용하면 된다. Job객체는 코루틴을 실행시킬 수 있는 ..

Kotlin 2024.04.21

[Kotlin] 코틀린 코루틴에 대한 개념 정리 (1)

최근 코틀린을 다룰 일이 있었다. 코드는 그냥 작성하면 되는데, 코루틴에 대한 개념이 좀 부족했다고 생각했다. 애매하게 알고 있는 상태에서 코루틴의 기능을 쓰는게 썩 기분이 좋진 않았다. 뭔가 찝찝했다. 그래서 이번 기회에 코루틴에 대해 시간을 갖고 천천히 알아보고자 한다. 코루틴은 기본적으로 경량 스레드라고 불린다. 왜 경량 스레드냐면, 스레드에 붙였다 뗄 수 있기 때문이다. 왜 코루틴이 필요하냐를 정리하자면, 멀티스레드 프로그래밍에서의 일부 한계점을 극복하고자함이다. 우선 싱글 스레드부터 살펴보자. 스레드가 하나이므로 단 하나의 작업만 할 수 있다. 모든 일은 순차적으로 진행된다. cpu바운드던, 네트워크 IO 작업이던 모든지 하나라서 그다지 효율적이지 않다. 그래서 등장한게 멀티스레드 프로그래밍이다..

Kotlin 2024.04.20

[Rust] 러스트 Double Linked List 코드

최근 프로젝트 중 러스트를 사용할 일이 있어서 러스트를 학습 중이다.  대학교때 공부했던게 사용하지 않으니 머릿속에서 정말 말끔하게 증발해버렸다. (뭐 어딘가엔 어렴풋하게 있겠지만)  러스트 이중 연결리스트에 대한 코드다. 현재 학습 중인 자료에서 Rust double linked list코드가 나오는데 좋은 개념들이 함께 등장해서 분석해보면 좋을 것 같은 예제이다.  그나저나 lifetime은 아직도 긴가민가하다. 이런 syntax자체가 생소해서인지.  use std::cell::RefCell;use std::rc::{Rc, Weak};pub struct Node { data: isize, next: Option>>, prev: Option>>,}pub struct List { h..

Rust 2024.04.12

[C] C language의 연산자 우선순위는 설계 실수인가?

최근 흥미로운 내용을 접했다. C language의 연산자 우선순위에 설계상 결함이 있다는 이야기다. 전설의 C에 언어 설계 결함이 있을 수 있나? 라는 생각이 들었다. (지금도 결함 정도로 생각되진 않지만) 내용은 이렇다. & | 연산자와 == 연산자 간의 연산자 우선 순위로 인해 실수할 여지가 크다는 내용이다. & | 보다 ==의 연산자 우선순위가 더 높기 때문에 문제가 될 수 있다고 한다. 아래 코드가 있다고 보자. if (a & b == c) { // ... } 위 코드는 a&b의 결과가 c와 동등한지 확인하는 코드가 아니다. 오히려 b==c가 먼저 평가되고 그 결과와 a와 bit and를 한다. (당연히도) 해당 의견을 접하고 먼저 든 생각은 이렇다. 이게 왜 설계상 오류일까? 연산자 우선순위가..

C & C++/C 2024.01.01

[AWS] Dynamo: Amazon’s Highly Available Key-value Store

DynamoDB의 근간은 2007년 AWS에서 내놓은 Dynamo 논문에 기반을 둔다. 해당 논문을 읽어보고 간략하게 내용을 정리해보고자 한다.  주의 개인 학습을 위해 러프하게 읽어본 내용이라서 중간에 잘못 해석한 내용이 있을 수 있습니다. 간략하게 1회독 한 것이라서 정확하지 않습니다. 요약을 차차 수정할 예정이니 내용을 파악하고 싶다면 논문을 직접 보시는 게 좋습니다.  1. 서론 아마존은 전세계급 서비스를 운용이 논문에서는 Dynamo라 불리는 고가용성의 키벨류 저장소 시스템을 다룸 즉 always-on이 가능하게 하는 서비스임 토네이도 때문에 데이터 센터가 날아가거나 혹은 네트워크 장애가 발생하더라도 언제나 가용한 저장소 기술에 대한 니즈는 항상 있다. RDB의 일반적인 패턴은 비효율성을 가져왔..

Cloud/AWS 2023.11.10

[AWS] DynamoDB에서 쓰기 충돌을 방지하는 방법

최근 Dynamo 논문을 읽어보면서 흥미로운 개념을 발견했다. 대부분의 DB의 경우 last writes wins라는 전략을 택한다고 한다. 간단하게 말하자면 마지막에 쓴 자가 기존 데이터를 덮어씌우는 방식이다. 동시 쓰기의 문제를 심플하게 나중에 쓴 사람 걸 채택하는 방식으로 해결한다는 것이다. 이렇게 하는 이유는 개발자의 편의에 있기도 하고, (개발자들은 본인의 client단에 복잡한 충돌 처리 로직을 작성하는 걸 싫어한다고 한다) 단순하게 그 방법이 가장 간단하기 때문이라고도 한다. 그런데 Dynamo 논문에서는 DynamoDB의 경우 last writes wins가 아니라 애플리케이션에서 해당 충돌에 대한 권한을 가질 수 있도록 만들었다고 한다. 즉 애플리케이션 단의 로직으로 해당 충돌 문제를 해..

Cloud/AWS 2023.11.10

[RabbitMQ] RabbitMQ 구성요소와 용어 정리

용어 RabbitMQ의 클라이언트 브로커와 통신하는 모든 애플리케이션을 의미함 Producer 메세지를 생성하고 RabbitMQ 브로커로 전송함 Consumer RabbitMq 브로커로부터 메세지를 받아서 처리함 RabbitMQ의 브로커 중앙 메시징 시스템 브로커는 Producer로부터 메세지를 받아서 적절한 큐에 저장하고 그 큐의 메세지를 Consumer에게 전달함 구성요소 Exchange 메세지를 받아 적절한 큐로 라우팅하는 컴포넌트 direct, topic, fanout, headers등 타입을 가짐 각 타입에 따라 메세지를 다른 방식으로 라우팅함 Queues 메세지가 저장되는 곳 메세지를 컨슈머에게 전달하기 전에 일시적으로 저장하는 버퍼 역할 Blindings Exchange와 큐 사이의 연결을 ..

[RabbitMQ] RabbitMQ 공부 자료 모음

이번 주에 RabbitMQ에 대해서 알아보았다. 꽤나 재밌는 내용이 많았다. 단순히 producer, consumer만 있는게 아니라 exchange라는 개념까지? 그리고 클러스터링과 미러링, 성능에 대한 이야기도 모두 재밌게 보았다. AMQP라는 새로운 프로토콜에 대해서도 알 수 있었다. (디테일한 스펙은 내용이 너무 많아서 다 보지 못했다.) 공부하면서 보던 링크를 기록해둔다. RabbitMQ에 대해서 간략하게 학습하고 싶은 분이 계시다면 아래 링크를 참고하시기 바란다. RabbitMQ 공식 사이트 https://www.rabbitmq.com/ RabbitMQ 성능 가이드 https://chopstick-91.tistory.com/160 RabbitMQ internal https://github.co..

반응형