Container 레이아웃 치트시트

https://medium.com/jlouage/container-de5b0d3ad184


Flutter Layouts Walkthrough: Row, Column, Stack, Expanded, Padding

https://medium.com/coding-with-flutter/flutter-layouts-walkthrough-row-column-stack-expanded-padding-5ed64e8f9584


Flutter Layout Cheat Sheet

https://proandroiddev.com/flutter-layout-cheat-sheet-5363348d037e


레이아웃 Flutter 영상 #1

https://codingwithflutter.com/

Flutter App Tutorial #1

이 글의 모든 내용은 udemy 강좌를 공부하고 따라해본 내용입니다.

https://www.udemy.com/dart-and-flutter-the-complete-developers-guide

완성 된 형태이다.

첫 화면에서 오른쪽 아래 플로팅 버튼 클릭시 오른쪽 화면처럼 이미지와 글자를 가진 뷰가 하나씩 추가되는 형태이다.

소스는 http json 을 통해서 가져왔다.

소스는 https://github.com/bear2u/flutter-sample-pic.git 에서 확인가능하다. 


main.dart 시작

flutter는 첫진입은 일반적으로 lib/main.dart 로 시작된다.

  • 매트리얼 테마를 사용하기 위해서 import를 한다.
  • runApp 은 메테리얼 라이버러리를 통해 실행된다.
  • App 은 따로 빼서 진행한다.
# lib/main.dart

import 'package:flutter/material.dart';
import 'src/app.dart';

void main() {  
  runApp(App());
}

lib에 src 폴더를 만들고 app.dart 를 생성한다.

  • StatefulWidget을 통해서 서버로 들어오는 아이템들을 리스트로 보내주고 있다.
  • Scaffold 는 Floating Action Button 과 타이틀바 및 바텀바등을 기본적으로 가지는 위젯이다.
  • await 는 비동기방식을 동기형태로 바꿔주고 네트워크 결과값을 가져온다.
  • 그리고 미리 정의된 ImageModel.FromJson 을 통해 디코딩을 거친다.
  • 마지막으로 setState()을 통해 images 라는 리스트에 아이템을 추가를 해서 state 변경을 한다.
# lib/src/app.dart

import 'package:flutter/material.dart';
import 'package:http/http.dart' show get;
import 'models/image_model.dart';
import 'dart:convert';
import 'widgets/image_list.dart';

class App extends StatefulWidget {
  @override
    State<StatefulWidget> createState() {
      // TODO: implement createState
      return AppState();
    }
}

class AppState extends State<App> {
  int counter = 0;
  List<ImageModel> images = [];

  void fetchImage() async {
    counter++;
    var response = await get('https://jsonplaceholder.typicode.com/photos/$counter');
    var imageModel = ImageModel.fromJson(json.decode(response.body));

    setState(() {
      images.add(imageModel);
    });

  }

  Widget build(context) {
    return MaterialApp(
      home: Scaffold(
        body: ImageList(images),
        appBar: AppBar(
          title: Text("Lets see some images!"),
        ),
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.add), //Widget 추가
          onPressed: fetchImage,
        ),
      ),
    );
  }
}

// Must define a 'build' method that returns
// the widgets that *this* widget will show

모델 정의

서버로 부터 가져온 JSON 결과값을 dart 내 오브젝트 형태로 변경할수 있도록 할수 있다.

# lib/src/models/image_model.dart

/**
 * JSON Decoding Model
 */
class ImageModel {
  int id;
  String url;
  String title;

  ImageModel(this.id, this.url, this.title);

  ImageModel.fromJson(Map<String, dynamic> parsedJson) {
    id = parsedJson['id'];
    url = parsedJson['url'];
    title = parsedJson['title'];
  }

  // 이렇게도 정의할 수 있다.
  // ImageModel.fromJson(Map<String, dynamic> parsedJson)
  // : id = parsedJson['id'],
  //   url = parsedJson['url'],
  //   title = parsedJson['title'];

  @override
    String toString() {
      // TODO: implement toString
      return '$id,$url,$title';
    }
}

리스트 뷰 정의

  • ListView 의 경우 React상에 바보뷰라고 하는 상태가 전혀 없고 값만 가지고 핸들링을 한다.
  • final 사용을 통해 값이 immutable 한지 체크를 할 수 있다. (바뀌면 안된다)
  • 그리고 위젯을 함수로 빼서 사용가능하다. (buildImage)
  • border의 경우 decoration 으로 가능하다.
  • 생성자로 값을 받아서 그 값을 뷰에 세팅해주고 있다.
import 'package:flutter/material.dart';
import '../models/image_model.dart';

class ImageList extends StatelessWidget {
  final List<ImageModel> images;

  ImageList(this.images);

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return ListView.builder(
        itemCount: images.length,
        itemBuilder: (context, int index) {
          return buildImage(images[index]);
        });
  }

  Widget buildImage(ImageModel image) {
    return Container(
      decoration: BoxDecoration(
        border: Border.all(color: Colors.grey),
      ),
      padding: EdgeInsets.all(20.0),
      margin: EdgeInsets.all(20.0),
      child: Column(
        children: <Widget>[
          Padding(
            child: Image.network(image.url),
            padding: EdgeInsets.only(bottom: 10.0),
          ),        
          Text(image.title)
        ]),
    );
  }
}

이로써 아주 간단한 앱을 만들어보았다.

큰 흐름을 이해 할수 있는 소스였다.


Await / Future 비동기 함수 호출

Http 로 통신할때 일반적으로 비동기로 호출을 하는 편이다. 비동기란 함수 호출시 블럭이 되지 않고 한번 다 훝고 콜백식으로 완료가 됐을 경우 다시 결과를 받는 경우를 말한다.

만약 아래와 같은 코드에서 실행시 결과값은 마지막에 'I got the data' 로 떨어지게 된다.

그리고 자바스크립트에서 Promise 형태와 비슷한 걸 볼수 있다.

import 'dart:async';

void main () {
  print('1. start to fetch data');
  
  get('http://weasds.com')
    .then((data) {
      print(data);
    });
  
  print('3. finish call to fetch the data');
}

Future<String> get(String url) {
  return new Future.delayed(new Duration(seconds: 3), () {
    return '2. I got the data!!';
  });
}
...........
1. start to fetch data
3. finish call to fetch the data
2. I got the data!!
// 순서가 1-3-2 로 되는 걸 볼수 있다.

그리고 Promise말고도 await로 비동기를 기다렸다가 가져오는 방법도 지원한다.

import 'dart:async';

void main () async {
  print('1. start to fetch data');
  
  print(await get('http://weasds.com'));
  
  print('3. finish call to fetch the data');
}

Future<String> get(String url) {
  return new Future.delayed(new Duration(seconds: 3), () {
    return '2. I got the data!!';
  });
}

.........

1. start to fetch data
2. I got the data!! //약 3초뒤 나온다.
3. finish call to fetch the data

참고



JSON 핸들러

서버와 통신시 제일 자주 사용되는 형태가 JSON 이다. 그럼 다트에서는 어떻게 다룰수 있는 지 살펴보겠다.

테스트 환경은 https://dartpad.dartlang.org/ 에서 진행한다.

import 'dart:convert';

void main() {
  var rawJson = '{"url": "http://blah.jpg","id":1}';

  var parsedJson = json.decode(rawJson);
  print(parsedJson);
  print(parsedJson['url']);

}

.............
{url: http://blah.jpg, id: 1}
http://blah.jpg

그리고 모델 클래스를 만들어서 매핑하고자 할때에는 값을 키값을 줘서 값을 가져온다음 set 을 통해서 모델을 만들수 있다.

import 'dart:convert';

void main() {
  var rawJson = '{"url": "http://blah.jpg","id":1}';

  var parsedJson = json.decode(rawJson);
  var imageModel = new ImageModel(
            parsedJson['id'], 
            parsedJson['url']
  );

  print(imageModel);

}

class ImageModel {
  int id;
  String url;  

  ImageModel(this.id, this.url);

  String toString() {
    return '$id,$url';
  }
}

하지만 만약 여러개 속성을 파싱할때 이 방식은 좀 불편하다.

그래서 fromJson 함수를 제공해준다. 이 함수는 JSON 을 미리 정의된 값을 매핑해주는 역할을 한다.

그럼 코드를 보면 이해가 빠를거라 본다.

관련 링크

import 'dart:convert';

void main() {
  var rawJson = '{"url": "http://blah.jpg","id":1}';

  var parsedJson = json.decode(rawJson);
  var imageModel = new ImageModel.fromJson(parsedJson);

  print(imageModel);

}

class ImageModel {
  int id;
  String url;  

  ImageModel(this.id, this.url);

  ImageModel.fromJson(Map<String, dynamic> parsedJson) 
    : id = parsedJson['id'],
      url = parsedJson['url'];


  String toString() {
    return '$id,$url';
  }
}

............
1,http://blah.jpg


Flutter 카카오톡 오픈 채팅방 바로가기 : https://open.kakao.com/o/gsshoXJ


StatefulWidget

StatefulWidget은 위젯에 변경되는 state 를 담고 있는 커스텀 위젯을 뜻한다.

그럼 어떤식으로 만들어지는 지 살펴보자.

우선 StatefulWidget 을 extends 한다.

class App extends StatefulWidget {
    
}

State를 상속받은 클래스를 만든다.

class AppState extends State<App> {
  int counter = 0;

  Widget build(context) {
    return MaterialApp(
      home: Scaffold(
        body: Text('$counter'),
        appBar: AppBar(
          title: Text("Lets see some images!"),
        ),
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.add), //Widget 추가
          onPressed: () {
            // 이벤트 콜백 함수                        
          },
        ),
      ),
    );
  }
}

createState 함수를 StatefullState 클래스에 정의를 한다.

@override
State<StatefulWidget> createState() {
  // TODO: implement createState
  return AppState(); // 전 단계에서 만든 클래스
}

마지막으로 변경될 값을 setState() 함수내에서 정의한다.

여기에선 floating action button 을 클릭시 counter 를 1씩 올리는 작업이 이루어진다.

....
onPressed: () {
  // 이벤트 콜백 함수            
  setState(() {
    counter += 1; // 1씩 올리고 있다.
  });
},
....          

Flutter 카카오톡 오픈 채팅방 바로가기 : https://open.kakao.com/o/gsshoXJ

커스텀 위젯 추가

하나의 파일에 많은 코드를 추가시 복잡해지고 길어지는 단점이 있다. 이럴때 파일로 빼서 분리를 할수 있다.

임포트 방법

내부에 src 폴더를 만들고 그 안에 app.dart 파일을 만들자.

클래스 구조를 만들수 있다.

  1. import 매트리얼
  2. Stateless(StatefulWidget)Widget class 생성
  3. Build 함수 구현
  4. main.dart 에서 src/app.dart 호출
# src/app.dart

import 'package:flutter/material.dart';

class App extends StatelessWidget {
  Widget build(context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("Lets see some images!"),
        ),
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.add), //Widget 추가
          onPressed: () {
            // 이벤트 콜백 함수            
          },
        ),
      ),
    );
  }
}
# main.dart

import 'package:flutter/material.dart';
import 'src/app.dart';

void main() {  
  runApp(App());
}

그런데 여기에서 StatelessWidget 과 StatefulWidget 이 나오는데 차이점은 무엇일까?

StatelessWidget의 경우 상태관리가 필요없는 위젯을 뜻한다. 즉 다시말해 내부에서 변하는 값을 가지는 게 없는 경우이다.

StatefulWidget은 반대로 state 관리를 함으로써 값이 변할때 다시 랜더링을 해주는 차이이다.

StatefulWidget은 어떻게 만들어지는 다음 시간에 알아보도록 하겠다.



Scaffold 위젯 추가


Flutter 카카오톡 오픈 채팅방 바로가기 : https://open.kakao.com/o/gsshoXJ


기본적으로 모바일 구조가 상단에 Appbar가 있으며 하단에 바텀시트가 있으며 floating action button이 있다.

그 구조를 기본적으로 지원하는 하나의 위젯이 Scaffold라고 보면 된다.

그럼 하나씩 적용해보자.

import 'package:flutter/material.dart';

void main() {
  var app = MaterialApp(
    home: Scaffold(
      appBar: AppBar(),    // 추가  
    ),
  );

  runApp(app);
}

짜잔~ 이런 타이틀바가 생긴걸 볼수 있다. 이걸 AppBar 라고 한다.

그리고 아래 floating button 을 추가도 아주 쉽게 할수 있다.

import 'package:flutter/material.dart';

void main() {
  var app = MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: Text("Lets see some images!"),        
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add), //Widget 추가
        onPressed: () { // 이벤트 콜백 함수
          print('Hi there!');
        },
      ),      
    ),
  );

  runApp(app);
}

추가적으로 메테리얼 아이콘을 변경시

https://material.io/tools/icons 에서 검색해서 Icons.*** 변경하면 된다.


Flutter 시작하기.


Flutter 카카오톡 오픈 채팅방 바로가기 : https://open.kakao.com/o/gsshoXJ


Flutter는 구글에서 나온 모바일 프레임워크입니다. Reactive Native 와 비슷하다고 보면 될것 같습니다. 네이티브 성격을 가진 하이브리드 앱인 셈이죠.

무엇보다 강력한 점은 각 플랫폼(Android, IOS)에 있는 대표 디자인 즉 메테리얼 디자인을 손쉽게 짤수가 있습니다.

하지만 플랫폼별로 다르게 나올수가 있는데 그 이유는 메테리얼도 플랫폼에 맞게 바뀌어서 나올 수 있기 때문입니다.

만약 IOS 에서 특유의 시스템을 이용하고 싶으면 쿠퍼티노 위젯을 사용하면 됩니다.

그 외에도 안드로이드 스튜디어, 비쥬얼 스튜디어 코드등 통합 IDE 도 사용 가능한 점이 큰 메리트입니다.

더 자세한 내용을 원하시면 공식홈페이지를 방문하시길 바랍니다.

구조

헬로우 플러터를 우선 보는게 중요하죠.

각 플랫폼별로 플러터 프로젝트를 생성합니다.

(vscode 에선 view -> 명령 팔렛트 -> flutter new project 선택)

그리고 실행을 해봅니다. ( 터미널에서 flutter run )

중요한건 화면까지 뛰우는 구조인데.

중요한건 4가지를 보시면 됩니다.

  1. import
  2. main 함수 생성
  3. main에 widget 추가
  4. 그 위젯을 화면에 추가

코드로 살펴보겠습니다.

import 'package:flutter/material.dart';

void main() {
  var app = MaterialApp(
    home: Text('Hi there!'),

  );

  runApp(app);
}

그럼 다음과 같이 투박한 화면이 나옵니다. ^^;;

그럼 다음시간에는 좀 더 위젯을 추가하도록 해보겠습니다.


GDG 부산 카페 바로가기

상하이로 출국

올해 처음 GDG 부산에 합류를 하게되었다. 부산에 마땅한 개발행사가 없고 특히나 수도권인 서울에 다 몰려있는 현실이 너무 안타까워서 나라도 나서자라는 마음에 시작하게 된 GDG 부산... 이리저리 착오끝에 구글 IO extended를 작게나마 진행했으며 다음 행사를 앞두고 있다. 

그런 와중에 상하이에서 GDG Asia를 진행하니 신청하라고 공지를 봤다. 혹시나 하는 마음에 신청해보고 얼떨결에 뽑히게 되었다. 

그렇게 나름 하나씩 준비를 해나가는 과정에서 같은달에 Google IO Extended 2018 Busan 을 개최를 하고 8월 마지막달에 드디어 GDG 아시아 분들이 모여있는 상해로 가게 되었다. 


조은님께서 알려주신 유심을 구매를 따로 하고(완소) 입국을 하고 떨리는 마음에 비자 심사대에 통과를 할려는 찰나에 뭔가 문제가 있다고 이미그레이션 사무실로 따라오라고 한다. 완전 긴장한 상태로 따라 갔는데 전상상의 착오로 오해가 있다고 말을 하고 풀려(?) 났다...


전철을 타보다. 

그리고 도착한 시간이 상해시간(시차 -1시간)은 2시쯤에 도착을 하게 되었다. 이미 도착하기전 슬랙 채널의 많은 분들이 경유를 상세히 알려주셨지만 그래도 한번 서민들 이동을 경험하고자 전철을 타고자 결심했다. 그래서 전철 표판매기에서 약 30분을 혼자서 끙끙거리며 구매를 하고 전철을 타보았다. 특이한 점은 전철에 들어갈때 공항에서 입국하는 것처럼 모든 짐을 엑스레이 검사를 한다는 점이다. 그리고 더 놀라운건 난 분명히 줄을 잘 서고 있는데 자꾸 새치기를 당해서 뒤로 밀려간다는 사실...;;;


호텔 도착

일단 우여곡절끝에 약 1시간 30분정도 전철을 두번 갈아타고 도착을 하게되었다. 푸동 에미뉴라는 스테이션이다. 내리자 마자 보이는 호텔의 웅장함에 다시 한번 고마움을 느끼며 걸어갔다. 입구에서 다행히 수호천사 조은님을 만나서 무사히 체크인을 하고 숙소에 짐을 풀수 있었다. 

엘리베이터를 타는 순간 하늘을 뚫고 나갈듯한 속도감에 당황도 했었다...;; 1층에서 36층까지 가는데 단 1초 걸린것 같은 느낌까지 받았다..




금요일 저녁 파티

도착한 그날이 금요일이었는데 저녁 6시부터 식사를 할 수 있었다. 그 자리에는 GDG 한국별로 각 챕터별 분들과 다른 나라의 챕터분들을 만날수 있었다. 개발자분도 계시고 디자이너분들도 계시고 회사 대표님도 계시는 아주 다양한 분야의 분들이 모인 자리이었다. 

무엇보다 적응이 필요한건 음식이었는데 전에도 상해에 왔을때도 음식때문에 좀 고생했는데 그 날도 덜하긴 했지만 여전히 중국 음식은 느끼하고 향기가 상당히 자극적이다. 그래도 맛이 있으며 준비해주신 음식에 고마움을 많이 느낄수 있었다. 



GDG 다른 분들과의 교류

금요일 저녁에 여러 챕터의 분들을 볼수 있었는데요. 그 중 인상깊은건 GDG 일본의 경우 분야별로 특수화 되어있다는 것이다. 예를 들어 GDG iot 라던가 GDG gcp 등과 같이 분류가 잘 되어 있었다. 한국도 이렇게 분류가 되어있는 것도 좋을 것 같다.

그리고 그 자리에서 만났던 분들은 대체적으로 영어를 잘 하는 편이었다. 많은 자극을 받은 자리였다고 말할수 있을것 같다. 

또 전에는 몰랐지만 맥주 맛이 맛있다는 느낌이 들었다. 아무래도 다른 분들과 행복한 시간을 보낸 것 같아서 그런것 같다. 


GDG 본격 행사

드디어 다음 날 토요일에 본행사가 열렸다. 오전부터 오후까지 진행하는 행사로 아주 유익했었다. 특히 안드로이드 관련해서 발표를 할땐 꽤 유심히 봤던 것 같다. 여러가지 스웩이랑 가방등이 있었는데 퀄리티도 좋았고 상당히 만족스러웠다. 




인사이트

행사에서 특히 유익했던건 GDG 행사를 진행하는데 있어 어려운 점이나 극복해야 하는 점등을 발표주제로 둬서 서로 다른 나라의 챕터분들끼리 모여서 발표하는 자리가 인상깊었던 같다. 

나도 겨우 한번의 작은 행사를 가졌지만 노쇼라던가 GDG 오거나이저 비활동적인 걸 어떻게 극복해야 할지 다들 고민하고 있다는 것에 공감대가 형성된 것 같다. 

그리고 화상으로 발표하시는 첫번째 세션에서 부산이 가진 지리적 한계를 어떻게 극복하면 되는지를 알수 있을것 같다. 

부산에서는 행사개최를 함에 있어서 양질의 스피커 확보가 시급하다. 이 부분을 행아웃으로 가능하지 않을까 생각해본다. 

그러면 서울분들도 무리해서 안 내려오셔도 되고 부산에 계시는 많은 분들도 지식을 공유 받을 수 있지 않을까 한다. 

또 하나 작은 밋업이 큰 밋업으로 만들어 나갈 수 있다는 걸 이자리에서 다들 공감하는 것 같다. 특히 인천분들은 잦은 작은 행사를 통해서 인지도를 높여가며 큰 행사를 만들어 나가는 모습에 깊이 감명 받았다. 

다른 아시아 분들의 영어실력에 또 다른 놀라움을 가진 것도 분명하다. 특히 일본!! 영어 너무 잘한다..


출국?

하루동안 행사를 마무리 하고 다음날 출국을 해야하는 일정을 준비했다. 하지만 그 날 상하이 구글 오피스를 갔는데 엄청난 높이에 놀랐다. 안개낀 고층 건물이란...정말 엄청났다..

비록 출국 일정때문에 상하이 구글 오피스 건물에는 못 갔지만 사진을 보니 다들 즐거운 시간이었던 것 같다. 다음에 기회가 다시 되면 꼭 올라가보고 싶다. 

중국의 우버?

공항으로 이동시 위치가 애매해서 전철로 가기도 그렇고 악명높은 택시 타는 것도 좀 그래서 한번 유명한 디디추싱? 이라는 중국의 우버란 앱을 사용해보았다. 

이미 출국전에 신용카드를 연동해놓고 간 상태라 결제는 별로 문제가 안될 것 같다. 

그리고 앱을 실행해서 호출하니 5분내로 도착을 했는데 따로 정류소가 있었는데 그걸 몰라서 10초전에 겨우 도착을 해서 공항으로 갈 수 있었다. 


출국?

드디어 출국 수속을 받고 기다리는데 이게 왠걸...김해에서 돌풍이 많이 불어서 공함 도착이 안된다고는 소식이 들렸다. 정말 난감했는데 동방항공에서는 숙소 및 버스를 제공해주었다.. 

숙소가 조금 허름하지만 룸메이트 분이 체크인을 하고 다른 데로 가는 바람에 난 혼자서 편하게 잘 수 있었다. 그날은 정말 신경을 많이 써서 그런지 엄청 피곤했었다. 


특히 음식이 너무 먹기가 힘들어서 주위에 살펴보니 카르푸가 있고 KFC 도 마침 있어서 저녁을 먹을 수 있었다. 

이나라에서 특이한 점은 전부 QR 코드로 다 결제하고 주문받는 다는 것이다. 그리고 위챗을 이용해서 다 할 수 있다는 것이다. 정말 대단한 나라인것 같다. 한국도 배울점은 많다고 본다. 


드디어 출국

새벽 5시에 준비를 하고 공항에 가서 다시 출국 준비를 했다. 하지만 다시 지연되고 약 1시간 넘게 비행기에서 돌다가 드디어!! 김해로 갈수 있었다. 정말 기뻣다. 


결론

올해 처음 GDG가 되고 아직 친분이 없는 상태에서 비록 한국은 아니지만 상해에서 다른 챕터의 분들을 만날수 있어서 정말 유익했다. 그리고 구글러 분들의 노력으로 이러한 행사가 개최될 수 있어서 감사하다는 말씀을 드리고 싶다. 


GDG 화이팅




Pm2를 이용한 Spring boot deploy

EC2에 노드 서비스를 배포 함에 있어서 forever와 pm2를 이용을 하는 편이다.

Pm2는 슬랙이나 외부 연동도 좋아서 자주 이용되는 편이다.

그래서 이번에 Spring boot 도 배포를 하는데 pm2 를 이용할 수 있을까 찾아보니 당연히 가능하다.

우선 스프링 부트를 배포를 해보자.

mvn package

그럼 war or jar 파일이 나올것이다.

나온걸 서버로 올려놓고. 노드를 설치를 한다.

나는 주로 nvm 을 이용해서 설치를 하는 편이다.

설치를 진행 한 다음 pm2를 설치를 하자.

npm install -g pm2@latest

그리고 패키징된 war 파일이 있는 곳에 json 파일을 하나 만들자.

>> app.json

{
  "apps": [{
    "name": "War",
    "cwd": ".",
    "args": [
      "-jar",
      "/path/to/your.war" //여기에 war 파일 위치
    ],
    "env": {
    },
    "script": "/usr/bin/java",
    "node_args": [],
    "log_date_format": "YYYY-MM-DD HH:mm Z",
    "exec_interpreter": "none",
    "exec_mode": "fork"
  }]
}

마지막으로 pm2 을 이용해서 app.json 을 실행하자.

pm2 start app.json

그럼 잠시 후 문제가 없을 경우 정상적으로 서비스형태로 도는 걸 볼수 있다.

재 시작시

pm2 restart War

중지시

pm2 stop War

그리고 외부 서비스와 연동이 가능하다. (슬랙등)

여기에선 https://app.keymetrics.io 을 사용해보겠다.

무료로 한개까진 사용이 가능하다.

'스터디 > Server' 카테고리의 다른 글

[Server 세팅] 우분투에 nginx, SSL 세팅 가이드  (0) 2018.04.09

ou may need to try setting certain variables within your session

These particular values may be too small for your DB Connection to fulfill the query efficiently. These can be set within as follows:

  • To see what values these settings have currently do the following:
    • SHOW VARIABLES LIKE 'max_heap_table_size';
    • SHOW VARIABLES LIKE 'tmp_table_size';
  • To set max_heap_table_size to 64M do the following:
    • SET max_heap_table_size = 1024 * 1024 * 64;
  • To set tmp_table_size to 32M do the following:
    • SET tmp_table_size = 1024 * 1024 * 32;

Please consult the MySQL Documentation on Temp Table Usage

If you cannot set these values within your own session, contact your hosting provider to dynamically set them in your my.cnf.

Give it a Try !!!

'링크모음' 카테고리의 다른 글

간단하게 http를 테스트하고 싶을때  (0) 2017.10.18
쿠폰 포함 ($11)

React

General JS

Interview Prep

Other Languages


가변 인자를 보통 넣어서 사용시 ( ... )로 사용되는데 이를 Variadic 이라고 한다. 

예를 보자. 

func sum(numbers ...int){
    sum := 0
    for _, num := range numbers {
        sum += num
    }
    return sum
}
sum(1,2,3) //6
sum([]int{1,2,3}...) //6
sum(1) //1

Sum 함수는 int 인자값에 대한 가변적으로 가능하다. 

sum([]int{1,2,3}...) //6

의 경우 뒤에 ... 을 붙여서 할수 있는데 더 예를 보자면

func f(ids []int){
//
}
func service(id int){
    f([]int{id})
}
func service2(id []int){
    f(id)
}

위를 Variadic 을 적용해보면

func f(ids ...int){
//
}
func service(id int){
    f(id)
}
func service2(id []int){
    f(id...)
}

이렇게 타입도 가변적으로 바꿔서 넣을 수 있다. 

apt-get update     
apt-get install python2.7    
ln -s /usr/bin/python2.7 /usr/bin/python 


Boltdb 연동

공식 Github

빠르고 효율적인 저레벨 DB 중 하나인 bolt db 이다. key, value 로 되어있고 byte로 값을 넣을 수 있다는 장점이 있다.

우선 설치는

$ go get github.com/boltdb/bolt/...
// DB 여는 작업
package main

import (
	"log"

	"github.com/boltdb/bolt"
)

func main() {
	// Open the my.db data file in your current directory.
	// It will be created if it doesn't exist.
	db, err := bolt.Open("my.db", 0600, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	...
}

다른 프로세스가 여기 DB를 열때 락이 걸려있어서 못 연다 그러면 기존 프로세스가 DB를 닫을 때까지 무한대기를 할수 밖에 없는 상황이 발생한다. 이럴때 시간이 지나면 자동으로 대기를 풀어버릴수 있다.

db, err := bolt.Open("my.db", 0600, &bolt.Options{Timeout: 1 * time.Second})

기본적으로 3가지 함수를 가진다.

  • 읽기-쓰기
  • err := db.Update(func(tx *bolt.Tx) error {
    	...
    	return nil
    })
    
  • 읽기전용
  • err := db.View(func(tx *bolt.Tx) error {
    	...
    	return nil
    })
    
  • 배치(다중 업데이트)
  • err := db.Batch(func(tx *bolt.Tx) error {
    	...
    	return nil
    })
    

버킷을 만드는 소스

CreateBucketIfNotExists은 버킷이 없는 경우 생성하는 함수이다.

package main

import (
	"fmt"
	"github.com/boltdb/bolt"
	"log"
)

func main() {
	fmt.Println("test")
	db, err := bolt.Open("my.db", 0600, nil)
	if err != nil {
		log.Fatal(err)
	}

	db.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists([]byte("MyBucket"))
		if err != nil {
			return fmt.Errorf("Create bucker: %s", err)
		}
		fmt.Println("update done")
		return nil
	})

	defer db.Close()
}

그럼 값을 넣어보고 조회를 해보자.

주의 할 내용은 모든 key / value 은 byte로 넣어야 한다.

package main

import (
	"fmt"
	"github.com/boltdb/bolt"
	"log"
)

func main() {
	fmt.Println("test")
	db, err := bolt.Open("my.db", 0600, nil)
	if err != nil {
		log.Fatal(err)
	}

	db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("MyBucket"))
		err := b.Put([]byte("answer"), []byte("42"))
		return err;
	})

	db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("MyBucket"))
		v := b.Get([]byte("answer"))
		fmt.Printf("The answer is : %s\n", v)
		return nil
	})

	defer db.Close()
}

////////////
test
The answer is : 42

만약 키값을 시퀸스로 계속 올리고 싶다면??

NextSequence() 을 사용하면 가능하다.

// CreateUser saves u to the store. The new user ID is set on u once the data is persisted.
func (s *Store) CreateUser(u *User) error {
    return s.db.Update(func(tx *bolt.Tx) error {
        // Retrieve the users bucket.
        // This should be created when the DB is first opened.
        b := tx.Bucket([]byte("users"))

        // Generate ID for the user.
        // This returns an error only if the Tx is closed or not writeable.
        // That can't happen in an Update() call so I ignore the error check.
        id, _ := b.NextSequence()
        u.ID = int(id)

        // Marshal user data into bytes.
        buf, err := json.Marshal(u)
        if err != nil {
            return err
        }

        // Persist bytes to users bucket.
        return b.Put(itob(u.ID), buf)
    })
}

// itob returns an 8-byte big endian representation of v.
func itob(v int) []byte {
    b := make([]byte, 8)
    binary.BigEndian.PutUint64(b, uint64(v))
    return b
}

type User struct {
    ID int
    ...
}

그 외에도 여러가지 옵션들이 있다. 공식 레포 에서 확인가능하다.

반갑습니다. 

개발자는 공부를 안하면 쉽게 도태되어 지고 흐름에 뒤쳐지게 됩니다.

혹시 100일 뒤 돌아보면 그동안 뭐 했지 라는 후회를 하시고 계신가요?

그럼 매일 15분씩이라도 공부하고 자기 계발을 하면 100일, 1년 후에 돌아보면 아주 커다란 자산이 되어 있을거라고 저는 믿고 있습니다. 

여러분도 정말 얼마 안되는 15분이라는 시간을 자기계발에 쏟으시면 분명 멋진 개발자가 되실꺼라 믿고 있습니다. 응원해드리겠습니다. !!


전공 공부팀 1기 100일 완료 후기 바로 보기


이번 2기도 새롭게 인증방이 열리고 새로우신 분들과 진행을 하게 되었습니다. 

그리고 새로운 방식의 인증으로 개발자 공부를 진행하고 있습니다.

하지만 조금 정리가 안되어 있는 것 같아서 다시 한번 정리를 해보겠습니다. 

슬랙주소 : every15mindevstudy.slack.com 입니다. 

처음 오시는 분은 꼭 초대 링크를 통해서 오셔야 합니다.

https://goo.gl/TgsAhX


제 2기 15분 전공 공부팀 100일 안내입니다. 


- 목적 : 100일동안 매일 15분이상 개발관련(업무외) 자기계발로 인증 하는 방법입니다. 

자세한 공부 인증 내용은 http://javaexpert.tistory.com/909 에서 볼 수 있습니다. 


인증은 기존 카톡 오픈 채팅방에서 슬랙으로 이동되었습니다. 

1. https://goo.gl/TgsAhX 으로 가셔서 슬렉 초대 링크를 받으십니다. 

2. 그러면 아래와 같은 로고를 가진 슬랙방이 만들어 집니다. 

3. 그리고 #인증채널 에 조인 하시고 인증을 https://goo.gl/Lm8vaD 폼에서 인증해주시면 됩니다. ( 예> 수지아빠/5/개인앱개발/20 )

4. 혹시 잘못입력 하신 경우엔 https://goo.gl/Cr7Uyu 에서 로그를 보시고 직접 수정하시면 됩니다. 

5. 그러면 슬랙에 인증채널에서 축하메세지가 약 5분안에 돌아오면 제대로 완료가 된겁니다. 

6. 마지막으로 그동안 공부한 로그등은 https://goo.gl/cRmyto (현황판)  에서 확인 가능합니다. 


주소 정리

입력폼 : https://goo.gl/TgsAhX

현황판 : https://goo.gl/cRmyto

수정시 : https://goo.gl/Cr7Uyu

채널이름 : 인증채널


블록체인 전공 책 같이 인증하면서 공부 진행하기

- 목적 : 정해진 전공책을 보고 싶으신 분들끼리 인증하면서 끝까지 다 보면서 공부하는 목적

관련 모집 내용은 http://javaexpert.tistory.com/950 에서 확인 가능합니다. 


주의 : 매일 안하셔도 됩니다. 다만 너무 빠지면 안됩니다. 


정리

채널이름 : book_master_bitcoin1

인증내용 : ex) 2~3장/40~80/40


이상입니다. 모쪼록 오셔서 꼭 공부하는 습관을 들여서 멋진 개발자로 거듭나길 바랍니다.



안녕하세요. 

블록체인 전공서적을 같이 읽어서 인증하는 스터디 모임을 개설했습니다. 

전공 공부팀 카톡 오픈 채팅방 바로 가기

처음 책으로는 비트코인, 블록체인과 금융의 혁신 책입니다. 

원제로는 mastering bitcoin 1판 입니다. 현재 2판까지 나왔지만 번역은 아직 안된 상태입니다. 


http://www.yes24.com/24/Goods/22357437?Acode=101


책이 다소 두껍지만 내용은 정말 좋다고 생각합니다. 입문서로는 딱이라고 봅니다. 

대상은 블록체인 처음 입문하시는 개발자분이거나 개념적으로 좀 더 공부를 하고 싶으신 분입니다.

블록체인에 항상 관심만 있으신 분도 오셔서 같이 인증도 하시고 토론도 해보시는 자리가 되셨으면 합니다. 

  1. 인증 방법은 카톡 오픈 채팅방으로 먼저 오십니다. ( 입장하기 )
  2. 슬랙으로 들어오셔서 해당 이름으로 된 채널에 입장하셔서 매일 또는 주기적으로 인증해주시면 됩니다. 
현재 매일 전공 공부팀도 같이 활동중입니다. 혹시 관심이 있으시면 같이 참가하셔도 됩니다. 








Golang 으로 CRUD Restfual Api 만들기

최근 블록체인을 공부하면서 이더리움 코어를 보고 싶다는 생각이 자주 들었다. 그리고 하이퍼레저에서 스마트 계약 개발시 Go 로 짜고 있는 걸 보고 고랭을 배워야 겠다는 마음을 먹고 하나씩 보고 있습니다.

언어를 제일 배우고 제일 먼저 해보는 건 무엇보다 게시판 하나 짜보는 거겠죠?

그래서 Restful Api 를 먼저 구성해보고 화면단을 만들어서 해보도록 합니다.

어설픈 TDD 방식으로 하나씩 짜보도록 하겠습니다.

우선 Go 가 아직 설치가 안되신 분은 https://golang.org/dl/ 으로 가셔서 받으시길 바랍니다.

그리고 환경 설정을 해줍니다.

혹시 Gopath 와 Gopath bin 설정이 안되신 분은 여기 에서 따라해보시면 됩니다.

현재 DB는 몽고디비를 사용중이며 도커로 연동중입니다.

그럼 우선 처음 시작은 main.go 로 구성해보죠.

# main.go

package main

import "fmt"

func main() {
    fmt.Println("Hello Go")
}

>>> Hello Go
> go run main.go //실행

그리고 App 파일을 만들어서 서버 관리를 위임하도록 합니다.

main.go 에서 App 인스턴스를 생성해서 서버쪽을 실행하고 DB도 연결하도록 합니다.

# app.go

package main

type App struct {
}

func (a *App) Initialize(serverIp, dbName, collectionName string) {

}
func (app App) Run(port string) {

}

그럼 main 에서는 어떻게 호출 하면 될까요?

package main

func main() {
    app := App{}
    app.Initialize(
        "192.168.99.100",
        "godb",
        "movies",
    )

    app.Run("8000")
}
  • App 인스턴스를 만들고
  • 초기화를 하고
  • App Run 함수를 통해서 실행을 합니다.

일단 제일 기본 뼈대는 진행된 것 같네요. 그럼 TDD로 먼저 테스팅을 작성해봅니다.

참고로 저도 고랭 처음이기도 해서 아주 어설프게 진행하니 양해부탁드립니다. ^^

그럼 main_test.go 를 하나 생성해줍니다. 그리고 샘플 예제를 하나 넣어서 테스트를 해봅니다.

혹시 유닛 테스팅 방법이 궁금하시면 여기 로 가셔서 참고하시길 바랍니다.

package main_test

import (
    "fmt"
    "github.com/restapi"
    "os"
    "testing"
)

var a main.App

var ip, dbName, collectionName = "192.168.99.100", "godb", "movies"

func TestMain(m *testing.M) {
    a = main.App{}
    a.Initialize(
        ip,
        dbName,
        collectionName,
    )

    prevTesting()

    code := m.Run()

    postTesting()

    os.Exit(code)
}

func prevTesting() {
    fmt.Println("prevTesting....")
}

func postTesting() {
    fmt.Println("postTesting....")
}

func TestExam(t *testing.T) {

    fmt.Println("TestExam inside")
}
prevTesting....
=== RUN   TestExam
TestExam inside
--- PASS: TestExam (0.00s)
PASS
postTesting....

내용은 보시면 아무것도 없습니다.

단지 테스팅을 하는데 TestExam을 실행시 항상 TestMain에서 전처리 후처리를 거쳐서 진행한다는 게 중요합니다.

자바로 생각하면 before와 after로 보시면 되겠네요. 보통 DB를 열어서 더미 데이트들을 넣어주고 마지막엔 지워주는 역할을 해도 되거나 DB연결을 도와줘도 됩니다.

일단 저는 다음에 쓰도록 하고 먼저 CRUD 서비스를 개발을 해보겠습니다.

이 예제는 크게 5가지 기능을 가집니다.

  • AddMovie
  • GetMovie
  • UpdateMovie
  • DeleteMovie
  • GetMovies

그럼 테스팅 클래스에 먼저 TestAddMovie함수를 정의 해봅시다. 영화를 추가하는 기능을 테스팅합니다.

func TestAddMovie(t *testing.T) {
    //TODO 영화 더미 데이터 하나를 가져온다.
    //TODO String으로 Json을 이용해서 변환해준다.
    //TODO Body 에 넣어서 Post 로 보내본다.
    //TODO 그리고 결과가 정상적으로 StatusCreated 코드가 떨어지는 지 본다.
    //TODO 입력 값을 JSON 으로 출력해서 정상적으로 입력되었는지 하나씩 체크
}

그럼 실제 코드로 옮겨보면 다음과 같이 만들수 있겠네요.

func TestAddMovie(t *testing.T) {

    //TODO 영화 더미 데이터 하나를 가져온다.
    darkNight := getMovieDummy()

    //TODO String으로 Json을 이용해서 변환해준다.
    darkNightMarshel, err := json.Marshal(darkNight)

    if err != nil {
        panic(err)
    }

    //TODO Body 에 넣어서 Post 로 보내본다.
    req, _ := http.NewRequest("POST", "/movie", bytes.NewBufferString(string(darkNightMarshel)))
    response := executeRequest(req)

    //TODO 그리고 결과가 정상적으로 StatusCreated 코드가 떨어지는 지 본다.
    checkResponseCode(t, http.StatusCreated, response.Code)

    //TODO 입력 값을 JSON 으로 출력해서 정상적으로 입력되었는지 하나씩 체크
    var m main.Movie
    json.Unmarshal(response.Body.Bytes(), &m)

    if darkNight.Name != m.Name {
        t.Errorf("Its not name equal %v", m.Name)
    }

    if darkNight.Year != m.Year {
        t.Errorf("Its not Year equal %v", m.Year)
    }

    if !cmp.Equal(darkNight.Directors, m.Directors) {
        t.Errorf("Its not Directors equal %v", m.Directors)
    }

    if !cmp.Equal(darkNight.Writers, m.Writers) {
        t.Errorf("Its not Writers equal %v", m.Writers)
    }

    if !cmp.Equal(darkNight.BoxOffice, m.BoxOffice) {
        t.Errorf("Its not BoxOffice equal %v", m.BoxOffice)
    }
}

그리고 더미 데이터는 임의로 만들어서 리턴을 해줍니다.

func getMovieDummy() *main.Movie {
    return &main.Movie{
        Name:      "The Dark Knight",
        Year:      "2008",
        Directors: []string{"Christopher Nolan"},
        Writers:   []string{"Jonathan Nolan", "Christopher Nolan"},
        BoxOffice: main.BoxOffice{
            Budget: 185000000,
            Gross:  533316061,
        },
    }
}

이 데이터 방식은 몽고 디비 컬렉션에 들어갈 내용입니다.

그러면 DB 연동 하고 실제 AddMovie함수를 만들어봐야 겠군요.

app.go 에 DB 연동 부분을 추가를 해줍니다.

type App struct {
    Router     *mux.Router
    session    *mgo.Session
    collection *mgo.Collection
}

func (a *App) Initialize(serverIp, dbName, collectionName string) {
    session, err := mgo.Dial(serverIp)
    a.session = session
    a.collection = a.session.DB(dbName).C(collectionName)

    if err != nil {
        panic(err)
    }
    //defer session.Close()

    a.Router = mux.NewRouter()
    a.initializeRoutes()
}

하단에 라우팅을 추가하는 함수가 있네요.

func (a *App) initializeRoutes() {
    //영화 추가
    a.Router.HandleFunc("/movie", a.addMovie).Methods("POST")
}

그리고 지금 당장은 안쓰지만 후에 서버를 실행할려면 다음과 같이 하단에 넣어주셔야 합니다.

func (a *App) Run(port string) {
    log.Fatal(http.ListenAndServe(":"+port, a.Router))
}

현재 mux 와 몽고 디비 라이버리를 가져와서 사용을 하고 있습니다. 명령어를 통해서 소스를 받아와서 연동을 해주도록 합니다.

go get github.com/gorilla/mux
go get gopkg.in/mgo.v2

그럼 영화 추가 로직을 넣기 위해선 model.go 을 만들어서 실제 DB핸들링 하는 건 다시 빼서 위임을 시켜보도록 하죠.

# model.go

type Movie struct {
    ID        bson.ObjectId `json:"id" bson:"_id,omitempty"`
    Name      string        `json:"name" bson:"name"`
    Year      string        `json:"year" bson:"year"`
    Directors []string      `json:"directors" bson:"directors"`
    Writers   []string      `json:"writers" bson:"writers"`
    BoxOffice BoxOffice     `json:"boxOffice" bson:"boxOffice"`
}

type BoxOffice struct {
    Budget uint64 `json:"budget" bson:"budget"`
    Gross  uint64 `json:"gross" bson:"gross"`
}

우선 Movie와 BoxOffice를 정의를 합니다.

# model.go

//영화 정보를 입력함
func (m *Movie) AddMovie(db *App) (string, error) {

    m.ID = bson.NewObjectId()
    var name = db.collection.Name
    fmt.Println(name)
    err := db.collection.Insert(m)
    if err != nil {
        return "", err
    }

    return m.ID.Hex(), nil
}

아이디를 생성해서 DB에 입력하는 로직입니다.

그리고 추후 입력된 내용에 대해 ID 를 리턴해서 다시 핸들링 (업데이트 및 삭제) 하게끔 할수 있습니다.

그럼 이 모델 로직을 가져와서 사용하는 곳을 만들어봐야겠네요.

실제 라우팅되서 처리되고 모델에 있는 로직함수가 실행된다고 보면 됩니다.

Test -> main - app - model

# app.go

func (a *App) addMovie(w http.ResponseWriter, r *http.Request) {
    var movie Movie
    postBody, err := ioutil.ReadAll(r.Body)
    if err != nil {
        respondWithError(w, http.StatusBadRequest, "parsing error")
        return
    }
    json.Unmarshal(postBody, &movie)

    defer r.Body.Close()

    if _, err := movie.AddMovie(a); err != nil {
        respondWithError(w, http.StatusInternalServerError, err.Error())
        return
    }

    respondWithJSON(w, http.StatusCreated, movie)
}

응답에 대한 오류와 성공 처리는 respond를 통해서 하고 있습니다.

# app.go

func respondWithError(w http.ResponseWriter, code int, message string) {
    respondWithJSON(w, code, map[string]string{"error": message})
}

func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
    response, _ := json.Marshal(payload)

    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(code)
    w.Write(response)
}

이제 AddMovie 쪽이 완성이 되었네요. 그럼 영화정보를 가져와야겠네요.

우선 테스팅 코드에 입력을 한다음

# main_test.go

func TestGetMovie(t *testing.T) {
    //id := bson.NewObjectId()
    id := addDommyMovie(getMovieDummy())
    req, _ := http.NewRequest("GET", "/movie/"+id, nil)
    response := executeRequest(req)
    checkResponseCode(t, http.StatusOK, response.Code)

    var m main.Movie
    json.Unmarshal(response.Body.Bytes(), &m)
}

라우팅 처리하는 곳 가서 GetMovie함수를 추가해줍니다.

func (a *App) getMovie(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)

    movie := Movie{ID: bson.ObjectIdHex(vars["id"])}
    if err := movie.GetMovie(a); err != nil {
        switch err {
        case mgo.ErrNotFound:
            respondWithError(w, http.StatusNotFound, err.Error())
        default:
            respondWithError(w, http.StatusInternalServerError, err.Error())
        }

        return
    }

    respondWithJSON(w, http.StatusOK, movie)
}

로직을 담당하는 model.go에서 GetMovie를 추가해줍니다.

//영화를 가져오는 함수
func (m *Movie) GetMovie(db *App) error {

    //var movie Movie
    err := db.collection.Find(bson.M{"_id": m.ID}).One(&m)
    if err != nil {
        return err
    }

    return nil
}

네. 사실 한줄 씩 테스팅 코드를 짜는 게 맞지만 대략적인 흐름만 알려드렸네요.

그럼 업데이트, 삭제, 전체 리스트 가져오기도 이런식으로 추가해서 진행할 수 있습니다.

그럼 다음에는 이 기능들을 이용해서 프론트단(React) 개발 및 연동을 해보겠습니다.

고랭 가즈아~~

현재 매일 15분 이상 전공공부팀 제 2기를 시작했으며 관심있으신 분은 참가하셔서 같이 공부를 하시길 바랍니다. 

매일 15분 전공공부팀 2기 안내글 바로가기


100일 성공 기록 목록들


최근 전공 팀 공부를 매일 15분이상(?)씩 해서 5월 초에 100일 성공을 했습니다. 

이 공부팀에 대해서 간단하게 설명하면 매일 카톡 오픈 채팅방에 15분이상 공부한 내용을 인증을 하면 됩니다. 

앱개발이 제 전문분야인데 웹이랑 블록체인을 주로 공부를 한 것 같네요. 

로그들을 한번 정리를 해보았습니다. 

수지아빠
108일

1일 / RxJava 그룹핑 예제 공부 / https://goo.gl/RfuQUY / 30분

2일차 / 개인앱 개발 및 마켓 출시 완료 / 90분 /https://play.google.com/store/apps/details?id=pe.kr.mhwguide

3일차 / RxKotlin Collection 공부 / 90분 / https://goo.gl/PbxYzo

4일차 / 스터디 자동 인증시스템 구축 및 테스팅 / 5시간

5일차 / 리엑트 네이티브 유데미 강좌 섹션 6,7 / 30분

6일차 / 리엑트 네이티브 유데미 강좌 29~45 (150개중) / 40분

7일차 / 개인 앱 업데이트/ 40분

8일차 / 유데미 rn 강의 / 3시간

9일차 / 유데미 rn 강의 / 2시간

10일차 / 유데미 rn 강의 / 90분

10일차 추가인증 / RN 예제 실습하기 #1 / https://github.com/bear2u/RN_study/tree/master / 2시간

11일차 / RN 예제 실습하기 #1 (완료) / https://github.com/bear2u/RN_study / 1시간

12일차 / RN 예제 실습하기 #2 로그인실습 (완료) / https://github.com/bear2u/rn-auth-example / 3시간

추가인증 / RN 리덕스 유데미 강의 / 1시간

13일차 / RN 예제 실습하기 #3 리덕스 연동해보기 / https://github.com/bear2u/rn-redux-exam / 2시간 30분

14일차 / RN 예제 실습하기 #3 리덕스 연동해보기 완료/ https://github.com/bear2u/rn-redux-exam / 1시간

노드 크롤링 프로젝트 / 1시간

15일차 / RN 예제 실습하기 #4 최종 예제 리덕스 연동 시작부분 / https://github.com/bear2u/RN_study2 / 2시간

추가인증 / 컨테이너 기반 가상화 플랫폼 ‘도커(Doker)’의 이해 온라인 강의 / 1시간 30분

16일차 / 도커 실행 강의 / 30분

17일차 / 블록체인 udemy 강좌 / https://github.com/bear2u/dApp-web3-examl1
/ 9시간

추가인증 / 블록체인 udemy 강좌 ~ 66까지 / 2시간

18일차 / 블록체인 웹서버에 추첨서비스 배포해보기 완료 (~99) / 8시간

추가인증 / 도커 이미지 만들기 온라인 강의 (티아카데미) / 2시간

https://github.com/bear2u/ether-lottery-exam

19일차 / 퀵스타트를 블록체인으로 만들어보자 예제#1 (100~121) / 3시간

https://gist.github.com/bear2u/7d42151c1a1126309d73669e0e6547a7

20일차 / Hyperledger 설치 삽질 / 2시간 30분

21일차 / 퀵스타트를 블록체인으로 만들기 실습 / 3시간 / https://github.com/bear2u/kickstarter-blockchain-exam

22일 / 블록체인 사설 구축 문서 리딩/1시간

23일 / 도커문서리딩 / 30분

24일 / 클린 코더 #1 / 20분

25일 / aws cloudfront 리딩 / 30분

26일 / 클린 코더스 #1,#2,#3 / 120분

27일 / 클린 코더스 #4 / 60분

추가인증 / 퀵스타터 블록체인 실습 진행중 / 60분 / https://github.com/bear2u/kickstarter-blockchain-exam

28일 / 퀵스타터 블록체인 실습 약 30프로 진행중 / 120분 / https://github.com/bear2u/kickstarter-blockchain-exam

29일 / 퀵스타터 블록체인 실습 약 50프로 진행중 / 40분 / https://github.com/bear2u/kickstarter-blockchain-exam

30일 / markdown 오픈소스 올려보기(rxjava2 변환완료) / 60분 / https://github.com/EveryDay-15min-Study-Team/MarkdownEditors

31일 / markdown 에디터 분석 / 60분

32일 / 퀵스타터 블록체인 실습 60프로 진행 / 40분 / https://github.com/bear2u/kickstarter-blockchain-exam

33일차/퀵스타터 블록체인 실습 70프로 진행 / 60분 / https://github.com/bear2u/kickstarter-blockchain-exam/commit/b8ba369270e9cec2627f4107c9ce100d596c4c03

34일차 / 코틀린인액션 ( 고차함수 ) / 60분

35일차 / 코틀린인액션 ( 인라인 람다 ) / 60분 /

36일차 / 퀵스터타를 블록체인으로 만들어보자 70프로 / 120분 /

37일차 / 솔리디티 문서 정독 / 30분

38일차 / 이더리움 지갑 만들기/ 30분

39일차 / 솔리디티로 좀비 만들기 / 60분

40일차 / 퀵스타터를 블록체인 형식으로 만들기 92% 완료 / 90분 / https://github.com/bear2u/kickstarter-blockchain-exam

41일차 / 퀵스타터를 블록체인 형식으로 만들기 완료 / 150분 / https://github.com/bear2u/kickstarter-blockchain-exam

42일차 / 커니의 안드로이드 대거편 / 30분

43일차 / 크립토좀비(블록체인) 레벨 2 따라해보기 / 2시간 / https://github.com/bear2u/til/blob/master/blockchain/test/c880-be44-b808-c2a8-2.md

44일차 / 크립토좀비 레벨2 완료 / 30분 / https://github.com/bear2u/til/blob/master/blockchain/dApp/zombie3.md

45일차 / 블록체인 코인뒤집기 설계 / 1시간

추가인증 / Hexo 블로그 생성 및 관리 / 1시간

46일차 / 블록체인 크립토좀비 레벨 3 완료 / 2시간 / https://github.com/bear2u/til/blob/master/blockchain/dApp/zombie3.md

47일차 / 블록체인 동전뒤집기 준비 / 30분

48일차 / 크립토좀비 레벨5(중간) 진행 / 4시간 / https://github.com/bear2u/til/blob/master/blockchain/zombies/zombie5.md

49일차 / Proof of Wook (블록체인 증명 시스템 알고리즘) 공부 / 1시간

50일차 / ERC20 코인 만들기 실습 / 2시간

ERC 827 코인 이론 공부 / 30분

52일차 / node and redux (full stack) 유데미 강좌 하루쿠 서버 올려보기 / 2시간 / https://github.com/bear2u/til/blob/74fb1341c5d168d24fc4a32b144a7802f1c4be91/node/fullstack_day1.md

53일차 / 블록체인 원리 공부 / 20분

54일차 / 블록체인 클론해보기 동강 / 5시간 / https://github.com/bear2u/nomadcoin

55일차 / 비트코인 클론해보기 동강 / 1시간 / https://github.com/bear2u/nomadcoin

추가인증 / mvp 크로님 rxjava 추가하기 / 30분

추가인증 / 비트코인 클론 소스 분석 / 20분

56일차 / 비트코인 클론 동강 / 1시간

추가인증 / 크로님 mvp dagger 적용 / 1시간

추가인증 / 좀비 요약본 정리 / 30분

57일차 / 비트코인 클론 동강 / 2시간 / https://github.com/bear2u/nomadcoin

추가인증 / mvp dagger2 적용 / 1시간

추가인증 / 기술 블로그 번역 연습 (1일차) / 1시간
https://github.com/bear2u/til/blob/master/android/Dagger2/binds_contributesAndroidInjector.md

58일차 / 모닝 비트코인 클론 동강 / 30분 / https://github.com/bear2u/nomadcoin

58일차 추가 / Dart 코드랩 및 flutter 앱 실행 / 2시간 / https://github.com/bear2u/til/blob/master/dart/Java_to_dart_codelab.md

59일차 / flutter 문서 실습 / 1시간
추가 / CSS 이론 수업 / 30분
추가 / 비트코인 클론 동강 / 25분
추가 / 기술블로그 독해연습 / 30분 / https://github.com/bear2u/til/blob/fa33793b60db979ad57a5840d6edc0505a2980ce/android/Dagger2/binds_contributesAndroidInjector.md#3%EC%9D%BC%EC%B0%A8

60일 / CSS 실습 / 1시간 / https://github.com/bear2u/til/blob/c2b747df950165bfa63d2c8ee59c8a32723ac324/web/README.md

61일 / CSS 카톡 처럼 만들기 / 1시간

추가 / dapp truffle 프레임 테스팅 및 디버깅 공부 / 1시간

62일 / dapp truffle 프레임워크 기초 공부 / 1시간

63일 / dapp truffle 프레임워크 펫샵 분석 / 2시간

64일 / 카톡 css 공부 / 1시간

65일 / 카톡 css 공부 / 2시간

66일 / 크립토 좀비 레벨 6 공부 / 30분

TIL Docker
https://github.com/bear2u/til/blob/master/server/docker/installing_wordpress_with_mysql.md

67일 / 크립토 좀비 레벨 6 공부, Docker로 워드프레스 세팅 / 20분, 2시간

TIL 좀비 6
https://github.com/bear2u/til/blob/master/blockchain/zombies/zombie6.md
추가인증 / 좀비6 공부하기 / 30분
추가인증 / 도커 동강 / 1시간 30분

68일차 / 이진탐색 알고리즘 정리 / 1시간 / http://javaexpert.tistory.com/931?category=699716

69일차 / 도커 책 훝어보기 / 1시간

추가 / 선택정렬 정리하기 / 1시간 / http://javaexpert.tistory.com/932

70일차 / 블록체인 dapp 이베이 구현 공부 / 2시간

71일차 / 블록체인 dapp 이베이 IPFS 서버 연결 공부 / 2시간

72일차 / 블록체인 이베이 ipfs 연결 및 에스크로 기능 구현 / 2시간 추가인증 / bootstrap 유데미 동강 / 6시간 / https://github.com/bear2u/boostrap_sandbox

73 일차 / 스팀잇 구조 분석 / 2시간

74 일차 / 부트스트랩 동강 실습 / 1시간

75 일차 / 블록체인 하이퍼레저 실습해보기 / 8시간

76 일차 / 블록체인 틱택톡 게임 개발해보기 실습 / 완료 / 8시간 / https://bear2u.github.io/tictoc_games_in_dapp_deployed/index.html

77일차 / 블록체인 raiden 설치 및 운영 삽질 / 실패 / 3시간

78일차 / 블록체인 공부 / 2시간

79일차 / 블록체인 + React 공부 / 2시간

80일차 / 고랭 언어 배우기 50% / 2시간

추가인증 / 블체복권을 truffle로 재구성 / 2시간 / https://github.com/bear2u/truffle_lottery

이더리움 해커톤

그림으로 이해하는 알고리즘 책 완독 / 4시간

그림 알고리즘 책 4장 ~ 완독 / 4시간

84 일차 / 리엑트 리덕스 공부 / 2시간

85 일차 / aws blockchain 삽질 / 4시간

86일차 / aws ALB 분석 / 3시간

7일차 / aws vpn 분석 / 3시간

88일차 / 고랭 문법 공부 / 40분

89일차 / 개인 플젝 / 4시간

90일차 / 개인 플젝 / 10시간

91일차 / 개인 프로젝트 / 5시간

92일차 / Flutter 기본 공부 / 2시간

93일 / flutter 공부하기 / 9시간 / https://github.com/bear2u/flutter_cat_box

94일 / 이더리움 코어 분석 / 1시간

95일 / React & Redux 게시판 개발 해보기 / 2시간

96일 / 부트스트랩 유데미 강의 / 1시간

97일 / React 기본 공부 / 1시간

98일/비트코인 분석 동강 공부/2시간

99일 / 이더리움 지갑 android 오픈 소스 분석 / 1시간

100일 / React Router 응용 부분 실습 / 1시간

101 / 블록체인 리엑트 개인 프로젝트 개발 / 10시간

102/리엑트웹 플젝 개발/13시간

103/블록체인 댑 스터디/2시간

104/react 스터디/2시간

105/bitcoin 책 정독/1시간

106/erc20 token project 개발/ 2시건

107 / Golang 스터디 준비 / 2시간

108 / Golang 스터디 준비 / 1시간

109/고랭 스터디/3시간/5.22

110/DAPP 개발 스터디/3시간/5.23

111/GoLang restApi 구축 공부/3시간/https://github.com/bear2u/til/tree/master/golang/restfulapi/5.24

참 많이도 공부를 했네요. ^^ 뿌듯합니다. 

100일 동안 같이 공부하면서 서로 자극도 많이 받고 위로도 되고 도움도 되었던 것 같습니다. 

혼자 가면 외롭고 힘들지만 같이 가면 끝까지 갈 수 있단 걸 다시 느낀 자리였던것 같습니다. 

100일 동안 블록체인 위주로 공부를 했네요. 아직 갈 길이 멀지만 다시 2기방에서 불 태워서 꼭 블록체인 전문가가 되는 그날까지..^^


현재는 진행중인 도전 목록들

  • 매일 15분 원서 읽기 도전 30일째
  • 일주일에 3회 블록체인 스터디 리딩 중(고랭, 이더리움, 하이퍼레저)
읽어주셔서 감사합니다. 더욱 더 열심히 노력하는 멋있는 아빠가 되도록 하겠습니다. ^^


출처 : https://stackoverflow.com/questions/29478751/how-to-cancel-an-emcascript6-vanilla-javascript-promise-chain

While there isn't a standard way of doing this in ES6, there is a library called Bluebird to handle this.

There is also a recommended way described as part of the react documentation. It looks similar to what you have in your 2 and 3rd updates.

const makeCancelable = (promise) => {
  let hasCanceled_ = false;

  const wrappedPromise = new Promise((resolve, reject) => {
    promise.then((val) =>
      hasCanceled_ ? reject({isCanceled: true}) : resolve(val)
    );
    promise.catch((error) =>
      hasCanceled_ ? reject({isCanceled: true}) : reject(error)
    );
  });

  return {
    promise: wrappedPromise,
    cancel() {
      hasCanceled_ = true;
    },
  };
};

const cancelablePromise = makeCancelable(
  new Promise(r => component.setState({...}}))
);

cancelablePromise
  .promise
  .then(() => console.log('resolved'))
  .catch((reason) => console.log('isCanceled', reason.isCanceled));

cancelablePromise.cancel(); // Cancel the promise

Taken from: https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html

https://ethereum.stackexchange.com/questions/28703/full-list-of-geth-terminal-commands

By running geth and entering the start of each of the global objects I'm aware of I can get the following lists, but I won't mark this as the correct answer as I'm sure there is documentation out there somewhere.

> eth.

eth._requestManager            eth.getBlockUncleCount         eth.getWork                    
eth.accounts                   eth.getCode                    eth.hashrate                   
eth.blockNumber                eth.getCoinbase                eth.iban                       
eth.call                       eth.getCompilers               eth.icapNamereg                
eth.coinbase                   eth.getGasPrice                eth.isSyncing                  
eth.compile                    eth.getHashrate                eth.mining                     
eth.constructor                eth.getMining                  eth.namereg                    
eth.contract                   eth.getPendingTransactions     eth.pendingTransactions        
eth.defaultAccount             eth.getProtocolVersion         eth.protocolVersion            
eth.defaultBlock               eth.getRawTransaction          eth.resend                     
eth.estimateGas                eth.getRawTransactionFromBlock eth.sendIBANTransaction        
eth.filter                     eth.getStorageAt               eth.sendRawTransaction         
eth.gasPrice                   eth.getSyncing                 eth.sendTransaction            
eth.getAccounts                eth.getTransaction             eth.sign                       
eth.getBalance                 eth.getTransactionCount        eth.signTransaction            
eth.getBlock                   eth.getTransactionFromBlock    eth.submitTransaction          
eth.getBlockNumber             eth.getTransactionReceipt      eth.submitWork                 
eth.getBlockTransactionCount   eth.getUncle                   eth.syncing                    

> personal.

personal._requestManager personal.getListWallets  personal.newAccount      
personal.constructor     personal.importRawKey    personal.sendTransaction 
personal.deriveAccount   personal.listAccounts    personal.sign            
personal.ecRecover       personal.listWallets     personal.unlockAccount   
personal.getListAccounts personal.lockAccount     

> admin.

admin.addPeer              admin.importChain          admin.startRPC             
admin.constructor          admin.isPrototypeOf        admin.startWS              
admin.datadir              admin.nodeInfo             admin.stopRPC              
admin.exportChain          admin.peers                admin.stopWS               
admin.getDatadir           admin.propertyIsEnumerable admin.toLocaleString       
admin.getNodeInfo          admin.removePeer           admin.toString             
admin.getPeers             admin.sleep                admin.valueOf              
admin.hasOwnProperty       admin.sleepBlocks          

> miner.

miner.constructor          miner.setEtherbase         miner.toLocaleString       
miner.getHashrate          miner.setExtra             miner.toString             
miner.hasOwnProperty       miner.setGasPrice          miner.valueOf              
miner.isPrototypeOf        miner.start                
miner.propertyIsEnumerable miner.stop      


'링크모음 > BlockChain News' 카테고리의 다른 글

크립토 키티 소스  (0) 2018.04.30
블록체인 공부 모음 링크  (0) 2018.04.13
SMT 백서  (0) 2018.04.12
블록체인 관련 참조 사이트 모음  (0) 2018.02.12

5월 21일. 핫한 IT, 개발, Blockchain, 노마드 뉴스 TOP5

1. TOP 10 자바스크립트 에러
(5월 16일. code burst.)
- 가장 흔한 자바스크립트 탑10 에러!
- can not read property!
- 어떻게 에러를 피하는지 팁 공개​

2. 재택근무? 집에서 효율적으로 일하는 5가지 방법
(4월17일. Medium.)
- 디지털노마드, 프리랜서라서 집에서 일하는 당신을 위한 팁
- 1번. 잠옷입고 일하지 마라
- 린이 추천합니다.

3. 봇을 만들며 알게된 7가지 레슨
(5월 18일. Hacker Noon.)
- 트위터봇을 만든 개발자가 배운 7가지 레슨
- 1번. 타잎스크립트 까먹지마
 
4. 구글 자바스크립트 스타일 가이드 13가지 신박한 가이드
(3월 27일. free code camp)
- 역시 구글 갓
- 드르륵 하지말고 괜춘한거 줍줍 하길

5. 리액트 네이티브로 애니메이션 만들기
(3월 21일. Medium. 좋아요 4.3K)
- 오오- 스무스한데?


5월 첫재주 뉴스

1. 풀스택 개발자가 되기위한 테크트리 2017년도 버전
(2017년. medium)​
작년 17년도 자료이긴 하지만 여전히 박수를 37K나 받은 유용한 자료라서 공유합니다. 테크트리를 보면서 한번 정리해보세요. 시작은 항상 html, css, javascript 부터!!

2. 차세대 자바스크립트  ECMAscript 2016, 2017, 그리고 2018!!
(4월 3일. freecodecamp)
매년 마다 업그레이드 되는 차세대 자바스크립트, 일명 에크마스크립트! 매년 어떻게 발전했고 업그레이드 했는지 차근차근 살펴보고 업데이트 하자. 

3. 트위터 대규모 해킹사건! 비밀번호 바꾸는 것 잊지 않으셨죠?
(5월 4일. ProductHunt)
 
4. IPFS가 어떻게 웹을 바꾸고 있는가!
(5월 3일. rubiksdigital)

5.페이스북이 AI를 훈련시키는 방법? 인스타그램 해쉬태그!
 (5월 3일. medium)


4월 28일자 뉴스

1. 리액트 개발자라면 알아야하는 10가지 팁
(4월 27일. creativebloq)​
Higher-order components, Container and presentational components, Error boundaries.. 그외 총 10가지. 리액트 개발자라면 이정도는 알아야한다 10가지 팁!

2. VS Code가 이것도 할 수 있어? VSC 사용팁 16가지
(4월 25일.vscodecandothat.com)
나도 몰랐던 VSC의 숨은 기능 살펴보기. 워매? 이것도 가능함??? 참. emmet, prettier은 다들 잘 사용하고 계시죠?? 아직도 모른다면 지금 바로 클릭!

3. 디지털 노마드와 코리빙의 상관관계
(4월 24일. BBC)
 
4. 매우 큰 자바스크립트 어플리케이션 디자인하기
(4월 15일. Medium. 좋아요 20K)

5.도쿄 그리고 홍콩 in 2018
 (4월 23일. haywirez)


4월 21일자 뉴스

1. 프로그레시브 웹 앱(PWA) + iOS  
(3월 30일. Medium. 좋아요 17K)​
 iOS 11.3에 애플이 조용히 PWA 지원기능을 올렸다는데..?!
앱스토어 승인 없이 iOS앱을 설치할 수 있다고?!

2. 내가 TypeScript를 쓰게된 이유 
(3월 10일. Medium. 좋아요 1.1K)
어쩌다 사용하게된 TypeScript에 홀딱 반하게된 사연
자바스크립트 ES6 기반이라는거!

3. 블록체인은 사실 실전에서는 활용되지않는 죽은 기술이다 
(4월 5일. Medium. 좋아요 30K)
 
4. 어떻게 GraphQL이 리덕스를 대체하나
(3월 10일. Medium. 좋아요 7.1K)

5. 백엔드 개발자 로드맵 2018. 어떻게 차근차근 기술을 연마하는가 
 (4월 3일. Medium. 좋아요 4K)


4월 5일자 뉴스

#1. 프로그레시브 웹 앱 (PWA)에 대한 6가지 오해
- PWA는 오프라인 앱만 가능하다 ?!?!
- PWA는 모바일 전용이라 데스크탑 환경은 구리다 ?!?!
- PWA는 아직 개발중이다 ?!?!
https://medium.com/samsung-internet-dev/6-myths-of-progressive-web-apps-81e28ca9d2b1

#2. 개발자라면, 크롬 말고 파이어폭스!
- 요소검사
- css grid
- box model
- font faily 등등 특히 프런트 쪽 살펴볼때 대박 편하다는 평가!
https://medium.com/swlh/calling-all-web-developers-heres-why-you-should-be-using-firefox-983f012d4aec

#3. 만우절 4월 1일. 개발자 드립 모음
- ATM 드론
- 람보르기니 크립토커런시 스토어
- 마시면 새로운 언어를 득도하게 되는 맥주 (오!!)
https://blog.producthunt.com/lets-play-a-game-b5fba27fd844

#4. Typescript 2.8로 완성한 최종 리액트 컴포넌트 패턴!
https://levelup.gitconnected.com/ultimate-react-component-patterns-with-typescript-2-8-82990c516935

#5. 이모티콘으로 한방에 (귀엽게) 설명하는 Hash(해쉬)!
https://medium.com/swlh/this-simple-yet-powerful-invention-is-changing-the-world-d04688c25f13


3월 28일자 뉴스

#1. 블록체인 개발자가 되어야하는 이유​
- 현재 1명 블록체인 개발자마다 14개의 일자리가 제공됨. 
- 즉. 일자리를 넘쳐나는데 정작 개발자가 없음
- Upwork에 따르면 일자리 성장속도는 매년 3만 5천 %임. (!!)
- TOP 3 스킬: 하이퍼레저, 리플, 솔리디티
https://hackernoon.com/become-a-blockchain-developer-and-get-rich-74712f1dd310

#2. 스택오버플로우 2018년 설문조사 결과
- 72% 자바스크립트 사용, 69% HTML, 66% CSS, 59% SQL, JAVA 45% 
- TOP 3 JS 라이브러리: Node JS(50%), Angular(38%), React (28%)
- 25% 개발자들은 해커톤에 참여함. 이유는? 재밌어서
- 45% 개발자들은 이미 개발자로 활동하고 있음에도 부트캠프에 참여함. 왜? 더 배우고 싶어서​
https://medium.freecodecamp.org/stack-overflow-2018-developer-survey-faac8d3eb357

#3. Web 3.0 시대의 등장
- 3천개의 크립토 코인 그리고 9백개의 DApps 
- 시장 규모 800 billion +
- 어떻게 web 2.0에서 블록체인의 3.0으로 바뀌고 있는지!
https://medium.com/@matteozago/why-the-net-giants-are-worried-about-the-web-3-0-44b2d3620da5

#4. 웹 개발자가 되고싶다고? php 배우지 말고 node js를 배우라구!​
https://hackernoon.com/want-to-be-a-web-developer-learn-node-js-not-php-dc298154fafd

#5. 멍청하고 잘못된 리액트, 자바스크립트 코드 분별법!​
https://medium.freecodecamp.org/learn-to-spot-red-flags-in-your-react-javascript-code-d52d5fac85f4


3월 15일자 뉴스

1. PostgresSQL vs MongoDB
https://hackernoon.com/https-medium-com-cn007b-postgresql-vs-mongodb-6d8bdb7c1697

#2. Progressive 웹앱? 미래의 모바일 웹앱 개발이라고?
https://hackernoon.com/progressive-web-apps-the-future-of-mobile-web-app-development-f29257b0dea2

#3. WebSocket 그리고 CSS3로 보여주는 겁내 쿨한 매직 (오! 신기!)
https://medium.com/outsystems-engineering/making-magic-with-websockets-and-css3-ec22c1dcc8a8

#4. 에스토니아, 디지털노마드 비자 2019년 시행 예정
http://emerging-europe.com/in-brief/estonia-launch-digital-nomad-visa/

#5. 존버시대에 당신이 해야 할 2가지
https://hackernoon.com/2-things-to-do-while-the-cryptocurrency-market-falls-2c6cdfbd6809


2월 21일자 뉴스

#1. 프로그래머에게 유용한 크롬 익스텐션, 코드 익스텐션 22개 모음​
https://medium.freecodecamp.org/tools-i-wish-i-had-known-about-when-i-started-coding-57849efd9248

#2. 당신이 블록체인 앱 빌드를 배워야하는 이유​
https://medium.com/loom-network/why-you-should-learn-to-build-blockchain-apps-be9a92e8d08e

#3. 코드 공유하는 5가지 방법 모음​
https://hackernoon.com/5-practical-ways-to-share-code-from-npm-to-lerna-and-bit-732f2a4db512

#4. 안녕? 난 블록체인 개발자야!
https://medium.com/wethinkideas/how-to-validate-if-your-ideas-need-a-blockchain-e1a4846d16fd

#5. 코딩은 적성이 아니야??? 때려치기전에 이걸 읽어봐​
https://medium.freecodecamp.org/why-so-many-developers-quit-before-ever-getting-a-job-please-dont-1c0fd6459e5e


2월 6일자 뉴스

#1. 엑스포(expo)로 게임 빌드하기
https://blog.expo.io/building-a-connected-game-with-expo-f09295c512a9

#2. 마케터라면 이제는 알아야하는 챗봇 chatbots
https://medium.com/swlh/the-ultimate-guide-to-chatbots-for-lead-generation-7dac67f8296b

#3. 구글을 떠나 그랩 (grab)에 입사한 이유
https://medium.com/@steve.yegge/why-i-left-google-to-join-grab-86dfffc0be84

#4. 원격 일자리/회사/웹 플래폼 최종 Ultimate 리스트
https://github.com/ajukco/remote-jobs-list

#5. 블록체인 + 페이스북 = ?? 2018년에 무슨일이!!
https://hackernoon.com/facebook-and-crypto-what-you-need-to-know-for-2018-6bcd71794853

'링크모음 > etc' 카테고리의 다른 글

CI / CD 설명 [펌]  (0) 2018.01.29
영어공부 팁 모음  (0) 2017.11.25
영어 저작권 없는 자료 링크  (0) 2017.11.24
카카오톡 개인정보 약관 저장  (0) 2017.11.21
소스 검색 방법 펌  (0) 2017.11.18

윈도우 상에서 도커를 이용해서 몽고 DB 세팅

윈도우상에서 몽고디비 설치시 가끔 오류 나는 부분이 있다. 그럼 설치도 안되고 개발도 안된다.

그럴때 도커를 이용해서 빠르게 테스팅을 할수 있다.

우선 도커를 켜서 다음 명령어를 하자.

docker pull mongo
docker run --name database -d -p 27017:27017 mongo --noauth --bind_ip=0.0.0.0

27017 포트에 0.0.0.0 으로 바인딩하는 문구이다.

-noauth 는 아이디랑 비번없이 들어갈 수 있다.

만약 설정시 아래와 같이 가능하다.

docker run --name some-mongo -d mongo --auth
docker exec -it some-mongo mongo admin

db.createUser({ user: 'jsmith', pwd: 'some-initial-password', roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] });

................................
Successfully added user: {
    "user" : "jsmith",
    "roles" : [
        {
            "role" : "userAdminAnyDatabase",
            "db" : "admin"
        }
    ]
}

그러면 잘 설치가 되었는지 확인해보자.

docker ps

윈도우 유저의 경우 virtucal box 에 방화벽을 열어야 한다.

virutal box 열기

기본 머신 선택한 후에 셋팅 열기

설정에 네트워크 메뉴 열기

네트워크 옵션 하단에 포워딩 메뉴 열기

그리고 줄 하나 추가 한다.

mongo / TCP / host port ( 임의로 < 1111 > ) / guest port ( 27017 )

그리고 클라이언트를 다운받는다.

보통 주로 받는 건

https://robomongo.org/

https://www.mongodb.com/download-center?jmp=hero#compass

(무료 커뮤니티 버전 선택)


그리고 마지막으로 클라이언트 접속을 해본다.

IP 는 localhost 또는 127.0.0.1 로 하고

포트는 임의로 정한 1111 로 해본다.

그럼 admin 으로 접속된걸 볼수 있다.

참고 사이트

https://codehangar.io/mongodb-image-instance-with-docker-toolbox-tutorial/

https://hub.docker.com/_/mongo/

[PowerMockup]

개발을 할때에나 기획을 할때 늘 스토리보드를 보면서 서로 대화를 하면 잘 통한다. 
사람은 글보단 그림이 좀 더 직관적이기 때문이다. 
그래서 이번참에 목업툴 제대로 된걸 구해보자고 해서 찾아보았다. 

우선 1순위는 파워목업이었다. 안에 슬라이스도 많고 꽤 쓸만한것 같다. 
현재 버전 4점대로 나온것 같다. 

그럼 한번 사용을 해보자. 

우선 해당 홈페이지는 여기이다. 

파워목업은 파워포인트가 깔려있어야 사용가능하다. 

그럼 실제 스크린샷은 어떨까?


오른쪽 Shape 의 경우 아직 내가 정식유저가 아니다 보니 활성화가 다 안되어있다. 구입하는 경우 활성화 될거라 본다. 

그럼 대충 이렇다 치고 구매는 어떻게 해야 할까?

종류별로 다 있다. 

유의할 점은 버전링을 봐야 한다. 현재 4.3 인데 Major 버전( 4 )이 올라가기 전까지 무료로 업데이트가 가능하다고 한다. 



그럼 구매링크는?

https://www.powermockup.com/order

다운로드는 어디에서?

https://www.powermockup.com/download

다트 기본

온라인 다트 편집기에서 실행가능하다.

https://dartpad.dartlang.org/

함수편

기본 출력

void main() {
    var test = "test";
    print('test = $test');
}

기본값 설정

void printMsg(String msg, [String value = 'undefined']) {
  print('msg = $msg, value = $value');
}
void main() {
  printMsg('1234', '5678');
  printMsg('1234');
}

........................
msg = 1234, value = 5678
msg = 1234, value = undefined

name, value 쌍으로 map 형태로 인수 넣기

void printMsg({String msg, String value}) {
  print('msg = $msg, value = $value');
}
void main() {
  printMsg(
    msg: "1234",
    value: "5678"
  );
}
..............................
msg = 1234, value = 5678

함수를 인자로 넣을수도 있다.

double add(double a, double b) => a + b;

//Function 정의자를 유의해서 보자
Function makeAdder(double value) {
  return (x) => add(value, x);
}

void main() {
  var adder1 = makeAdder(10.0);
  var adder2 = makeAdder(20.0);

  print('adder1 = ${adder1(5)} , adder2 = ${adder2(10)}');
}
...................................
adder1 = 15 , adder2 = 30

리스트

일반 리스트에 추가

유의할 점은 같은 타입만 추가 가능하다.

void main() {
  List<int> list = [2, 1, 3];
  list.add(4);
  print(list);
  print(list[0]);
}
..............

[2, 1, 3, 4]
2

for문 사용해서 출력

void main() {
  List<int> list = [2, 1, 3];
  printList(list);
}

void printList(List<int> list) {
  for(var i=0; i< list.length; i++) {
    print(i);
  }
}

foreach 사용

void main() {
  List<int> list = [2, 1, 3];
  usingForEach(list);
}

void usingForEach(List<int> list) {
  list.forEach( (x) {
    print(x);
  });
}

//짧게 설정 가능
void usingForEachShort(List<int> list) {
  list.forEach( (x) => print(x));
}

void main() {
  Map<String, int> cats = {
    'ABC': 1,
    'DEF': 2
  };

  print(cats);
}

Class

toString은 이미 Object에서 정의되어 있어서 오버라이딩 방식으로 다시 정의할 수 있다.

class Cat {
  String name;
  int age;

  @override
  String toString() {
    return '$name , $age';
  }
}

void main() {
  final cat = new Cat();
  cat.name = 'steve';
  cat.age = 10;

  print(cat.toString());
}

생성자를 바로 입력도 가능하다.

class Cat {
  String name;
  int age;

  //이 부분 살펴보자. 
  Cat(this.name, this.age);   

 // 또는 타입 지정도 가능하다. 
  Cat(String this._name, int this._age); 

  @override
  String toString() {
    return '$name , $age';
  }
}

void main() {
  final cat = new Cat('steve', 10);  

  print(cat.toString());
}

Try / Catch

기본적으로 예외를 잡는 부분

void main() {

  try {
    String userInput = '3,14';

    double doubleNum = double.parse(userInput);

    print(doubleNum);  
  } catch (e) {
    print(e);
  }  
}

.................
FormatException: Invalid double
3,14

특정 예외를 잡고 싶다면

void main() {

  try {
    String userInput = '3,14';

    double doubleNum = double.parse(userInput);

    print(doubleNum);  
  } on FormatException catch (e) {
    print("FormatException inside => $e");   
  } catch (e) {
    print("Global Exception => $e");
  }  
}

..................
FormatException inside => FormatException: Invalid double
3,14

Async Request

비동기 요청에 대해서 알아보자.

import "dart:html";

void handleSuccess(String response) {
  print('Request was ok');
  print(response);
}

void handleError(String error) {
  print('The request was not ok');
  print(error);
}

void main() {

  var result = HttpRequest.getString('https://rebounce.online/api/time');
  result.then(handleSuccess);
  result.catchError(handleError);

  print('Main function finshed');
}

.............
Main function finshed //비동기로 실행된 부분 체크하자...
Request was ok
{"time":"2018-05-01T05:06:35+02:00"}

체인 형태로도 가능하다.

var result = HttpRequest
    .getString('https://rebounce.online/api/time')
    .then((String response) {
      print(response);
    })
    .catchError( (dynamic error) {
      print(error);
    });

동기적으로 바꿀수도 있다.

Future, Async, Await 를 유의해서 보자.

import "dart:async"; //이 부분 추가됨
import "dart:html";

//Future 확인
 Future main() async {

  try {
      final response = await HttpRequest.getString('https://rebounce.online/api/time');   
      print('Request was ok => $response');   
  } catch (e) {
    print('Request error => + $e');
  }

  print('Main function has ended');

}
..........................

Request was ok => {"time":"2018-05-01T05:13:52+02:00"}
Main function has ended


Java for Dart Codelab

다트는 타입이 있는 언어입니다.

온라인에서 에디터를 실행 후 바로 테스팅이 가능합니다.

https://dartpad.dartlang.org/

  • 다트를 특별하게 만드는 이유
  • 생성자를 만드는 방법
  • 매개 변수를 지정하는 다양한 방법
  • getter , setter 를 만드는 방법 및 시기
  • 다트가 privacy 를 처리하는 방법
  • 팩토리를 만드는 방법
  • 다트에서 함수형 언어가 동작되는 방법
  • 다른 다트 콘셉

그럼 시작해보자.

class Bicycle {
  int cadence;
  int speed;
  int gear;
}

void main() {

}

main 함수로 실행한다.

  • 만약 argument를 가지고 싶다면 main(List<String> args) 를 사용할 수 있다.
  • 기본적으로 접근 제어자는 가지고 있지 않다. 예를 들어 public, private, protected
  • 다트는 기본적으로 2칸을(보통 4칸) 띄우고 사용한다. 만약 툴을 이용해서 reformat을 하고 싶은 경우 dartfmt를 이용한다.

생성자

클래스 생성자 지정이 가능하다.

생성시 바로 this 로 지정해서 내부 변수로 접근이 가능하다.

class Bicycle {  
  int cadence;
  int speed;
  int gear;

  Bicycle(this.cadence, this.speed, this.gear);
}

void main() {
  var bike = new Bicycle(2, 0, 1); //초기화
  print(bike);
}

...........................
Instance of 'Bicycle' // 결과

초기화

일반 클래스 초기화를 하는 것처럼 New 를 붙여서 한다.

오버라이드 함수

내부적으로 함수를 넣을 수 있다.

class Bicycle {
  int cadence;
  int speed;
  int gear;

  Bicycle(this.cadence, this.speed, this.gear);

  @override
  String toString() => 'Bicycle: $speed mph'; // 자바에서 toString과 유사하다.
}

void main() {
  var bike = new Bicycle(2, 100, 1);
  print(bike);
}

Getter 와 Setter

다트에선 각각의 변수에 대해 Getter 와 Setter를 제공한다. 그러기 위해선

다트에선 자바와 조금 다르게 처리를 한다.

Getter / Setter 지정하길 원하면 제어자를 붙이면 된다.

Setter를 따로 지정하지 않아서 컴파일 시 오류가 발생을 한다.

Setter를 붙이는 경우

class Bicycle {
  int cadence;
  int _speed;
  int gear;

  Bicycle(this.cadence, this._speed, this.gear);

  int get speed => _speed;
  set speed(int speedNum) {
    _speed = speedNum;
  }

  void applyBrake(int decrement) {
    _speed -= decrement;
  }

  void speedUp(int increment) {
    _speed += increment;
  }

  @override
  String toString() => 'Bicycle: $_speed mph';
}

void main() {
  var bike = new Bicycle(2, 100, 1);
//   bike.applyBrake(10);
  print(bike._speed);
  bike.speed = 10;
  print(bike._speed);
}

------------------------------------------------
100
10

Optional 파라미터

파라미터 지정시 선택적으로 가능하다.

import 'dart:math';

class Rectangle {
  int width;
  int height;
  Point origin;

  Rectangle({this.origin = const Point(0,0), this.width = 0, this.height = 0});

  @override
  String toString() => 'Origin: (${origin.x}, ${origin.y}), width: $width, height: $height';
}

main() {
  print(new Rectangle(origin: const Point(10, 20), width: 100, height: 200));
  print(new Rectangle(origin: const Point(10, 10)));
  print(new Rectangle(width: 200));
  print(new Rectangle());
}

...................................
Origin: (10, 20), width: 100, height: 200
Origin: (10, 10), width: 0, height: 0
Origin: (0, 0), width: 200, height: 0
Origin: (0, 0), width: 0, height: 0

Factory를 이용해서 생성하는 방법

아래와 같이 Circle, Square 클래스가 있다고 가정하자.

그리고 생성시 각자 공통적으로 묶을수 있다고 한다.

import 'dart:math';

abstract class Shape {
  num get area;
}

class Circle implements Shape {
  final num radius;
  Circle(this.radius);
  num get area => PI * pow(radius, 2);
}

class Square implements Shape {
  final num side;
  Square(this.side);
  num get area => pow(side, 2);
}

main() {
  var circle = new Circle(2);
  var square = new Square(2);
  print(circle.area);
  print(square.area);
}

................................
12.566370614359172
4

우선 최상위 함수로 올려보자. 유의해서 볼껀 Shape 클래스를 제어자 쪽으로 뺀 것이다.

import 'dart:math';

abstract class Shape {
  num get area;
}

class Circle implements Shape {
  final num radius;
  Circle(this.radius);
  num get area => PI * pow(radius, 2);
}

class Square implements Shape {
  final num side;
  Square(this.side);
  num get area => pow(side, 2);
}

//Shape 제어자를 눈여겨 보자.
Shape shapeFactory(String type) {
  if (type == 'circle') return new Circle(2);
  if (type == 'square') return new Square(2);
  throw 'Can\'t create $type'; 
}

main() {
  var circle = shapeFactory('circle');
  var square = shapeFactory('square');

  print(circle.area);
  print(square.area);
}
..........................................
12.566370614359172
4

두번째 방법은 Shape클래스 안에 factory생성자를 만드는 것이다.

 import 'dart:math';

abstract class Shape {
  //팩토리 함수를 정의
  factory Shape(String type) {
      if (type == 'circle') return new Circle(2);
    if (type == 'square') return new Square(2);
    throw 'Can\'t create $type';   
  }

  num get area;
}

class Circle implements Shape {
  final num radius;
  Circle(this.radius);
  num get area => PI * pow(radius, 2);
}

class Square implements Shape {
  final num side;
  Square(this.side);
  num get area => pow(side, 2);
}

main() {
  var circle = new Shape('circle');
  var square = new Shape('square');  

  print(circle.area);
  print(square.area);
}

상속의 개념

다트에서는 모든 클래스를 인터페이스 형태로 상속이 가능하다.

class CircleMock implements Circle {

}

상속을 하고 비어있는 상태일 경우 Missing concrete implementations오류가 발생될 수 있다.

그래서 상속을 할 경우 getter 변수를 다 적어줘야 한다.

class CircleMock implements Circle {
  num get radius;
  num get area;
}

함수형 언어 지원

자바스크립트 처럼 함수형태로 활용이 가능하다.

String scream(int length) {
  return "A${'a' * length}h!";
}

main() {
  var values = [1, 2, 3, 5, 10, 50];
  for (var length in values) {
    print(scream(length));
  }

  //함수형으로 바꾸는 경우
  values.map(scream).forEach(print);
  values.skip(1).take(3).map(scream).forEach(print); //이런식으로 가능하다. 
}

더 배우기 위해선

In completing this codelab, you've gained knowledge on some differences between Java and Dart. Dart is easy to learn and, in addition, itscore librariesandrich set of available packagesincreases your productivity. Dart scales well to large applications. Hundreds of Google engineers use Dart to write mission critical apps that bring in much of Google's revenue.

Next steps

A 20-minute codelab isn't long enough to show you all of the differences between Java and Dart. For example, this codelab hasn't covered:

If you are interested in seeing Dart technologies in action, try these codelabs:

You can learn much more about Dart with the following articles, resources, and websites.

Articles

Resources

Websites


'링크모음 > BlockChain News' 카테고리의 다른 글

[GETH] GETH 명령어 모음  (0) 2018.05.10
블록체인 공부 모음 링크  (0) 2018.04.13
SMT 백서  (0) 2018.04.12
블록체인 관련 참조 사이트 모음  (0) 2018.02.12


Geth 설치 및 로컬에 세팅 (윈도우 기준)

로컬 테스트넷에서 Geth 를 가동하기 위해선 두가지를 준비해야함

  1. 데이터 디렉터리 ( chaindata )
  2. Genesis.json 파일

윈도우 기반에서 진행한다.

  1. 윈도우로 GETH 설치를 진행하자. https://geth.ethereum.org/downloads/
  2. genesis.json 을 만들자.
  3. {
      "coinbase"   : "0x0000000000000000000000000000000000000001",
      "difficulty" : "0x20000",
      "extraData"  : "",
      "gasLimit"   : "0x8000000",
      "nonce"      : "0x0000000000000042",
      "mixhash"    : "0x0000000000000000000000000000000000000000000000000000000000000000",
      "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
      "timestamp"  : "0x00",
      "alloc": {},
      "config": {
            "chainId": 15,
            "homesteadBlock": 0,
            "eip155Block": 0,
            "eip158Block": 0
        }
    }
    
  4. 하위에 chaindata 폴더를 만들어서 저장할 곳을 만들자.

그리고 geth로 초기화를 진행한다.

geth --datadir=chaindata/ init genesis.json

//macos
geth --datadir=./chaindata/ init ./genesis.json

그러면 chaindata 디렉토리 아래에는 블록에 대한 정보가 보이며

keystore 아래에는 계정에 관한 정보가 보일것이다.

-geth - chinadata, lightchaindata
-keystore

그럼 실행해보자.

geth --networkid 4649 --nodiscover --maxpeers 0 --datadir chaindata console 2>> chaindata/geth.log

-- networkdid : 네트워크 식별자로 쓰인다. 0~3까지는 예약어이다.

0 = onlympic, 1= Frontier, 2=morden(disused), 3=Ropsten 기본값은 1이다.

-- nodiscover : 생성자의 노드를 다른 노드에서 검색할 수 없게 하는 옵션이다. 노드 추가는 수동으로 해야함,

-- maxpeers 0 : 생성자의 노드에 연결할 수 있는 노드의 수를 지정함, 0은 다른 노드뢍 연결안함

-- datadir 데이터 디렉토리 저정

console 콘솔로 진입한다.

2>> 데이터 디렉토리/geth.log 로그 파일 만들때 사용하는 옵션 리눅스 셀 명령어

이더리움에서는 계정이 두가지로 나뉜다.

  • EOA (Externally Owned Account) 일반 사용자가 사용하는 계정이고 Ether를 송금하거나 계약 실행시 필요한 계정
  • Contract 계정은 계약을 배포시 만들어지는 나오는 계정으로 블록체인에 존재함

EOA 계정생성 (콘솔에서)

> personal.newAccount("pass0")
"0x295e3893ed0cd5fb04fbfb4bba656f509ac21aff" //계정 주소

계정 정보 확인

> eth.accounts
["0x295e3893ed0cd5fb04fbfb4bba656f509ac21aff"]

exit를 하면 geth 가 자동 중지가 된다.

> exit

그럼 채굴을 해보자.

우선 다시 콘솔로 진입해보자.

geth --networkid 4649 --nodiscover --maxpeers 0 --datadir chaindata console 2>> chaindata/geth.log
> eth.coinbase
"0x295e3893ed0cd5fb04fbfb4bba656f509ac21aff"

coinbase는 채굴에 성공시 보상을 받는 계정을 조회하는 명령어이다.

만약 다른 계정으로 하고 싶을땐

miner.setEtherbase 로 가능하다.

> eth.accounts
["0x295e3893ed0cd5fb04fbfb4bba656f509ac21aff", "0x65682c210e9229e5616f1a49f710ce1b4577688b", "0xa817f884ebc1d181dbb3c35c
1cbdeae9b36221c5"]
> eth.coinbase
"0x295e3893ed0cd5fb04fbfb4bba656f509ac21aff"
> miner.setEtherbase(eth.accounts[1])
true // 성공됨
> eth.coinbase
"0x65682c210e9229e5616f1a49f710ce1b4577688b" //2번째 계정으로 지정됨

다시 첫번째 계정으로 돌려 놓자.

> miner.setEtherbase(eth.accounts[0])
true

잔고확인도 해보자.

> eth.getBalance(eth.accounts[0])
0
> eth.getBalance(eth.accounts[1])
0
> eth.getBalance(eth.accounts[2])
0

블록 수 확인도 가능하다. 아직 블록을 생성하지 않았으므로 0 이다.

> eth.blockNumber
0

그러면 채굴을 시작해보자.

miner.start(threadnum) 로 명령어 사용가능하다. 여기에서 thread_num은 채굴시 사용하는 쓰레드 수이다. 우선 1로 설정

> miner.start(1)
null or true
> miner.mining //마이닝 되고 있는 지 체크
true
> eth.hashreate
1086190 or 0
> eth.blockNumber
61

그리고 miner.stop 을 해보자.

> miner.stop()
//계좌 확인
> eth.getBalance(eth.coinbase)
125000000000000000000
> eth.getBalance(eth.accounts[1]) //현재 1로 설정되어 있는 상태입니다.
125000000000000000000
> eth.getBalance(eth.accounts[0])
95000000000000000000

0이 엄청 많아 보이지만 최소 단위인 wei 로 보여서 그렇다. 10^18승이 1이더이다. 그럼 이더로 변환하면

> web3.fromWei(eth.getBalance(eth.accounts[1]),"ether")
125 // 이더로 변환

다시 한번 블록 갯수 체크해본다.

> eth.blockNumber
44

블록당 보상금액이 5ether이다. 그래서 계정 2개 보상 금액 합치면 220 ( 125 + 95 ) 이더이다. 즉 220 = 5 * 44 로 맞아떨어진다.

이렇게 보상금액을 계산을 가능하다.

안녕하세요. 수지(수아지아를 줄여서) 아빠입니다. 

작년 11월 27일부터 시작된 영어회화 하루에 6문장씩 외우는 모임을 시작을 했었습니다. 

그리고 일요일 ( 2018년 4월 15일 ) 에 100일 완성을 했습니다. 주말은 쉬고 평일만 했습니다. 

대체로 외워서 손으로 작성하거나 삼성노트로 작성해서 여러명 같이 공부하는 카톡방에 인증하는 방식을 취했습니다.

그 중 몇개를 정리한 사진입니다.


영어 회화 외우게 된 계기

영어는 세계 공용어가 된 지 오래입니다. . 어느 나라를 가든 영어는 기본으로 해야 하는데 늘 영어에 대한 두려움을 가지고 살아야 했었습니다.. 몇십년 영어를 봐도 막상 외국인 앞에 서면 헬로우 하아유? 밖에 잘 안나오는 팩트도 한심했었습니다. 

그래서 한번 도전해보자 라는 생각을 하게 되었습니다. 매일 같이 아침에 출근길에 외우고 저녁에 집에서 자기전에 외우고 자고 하는 걸 반복했습니다. 

그래서 영어 좀 좀 늘었나?

사실 일상생활에서 원어민 만나서 말할 기회는 잘 없습니다. 그래서 말할 기회도 없죠. 금방 까먹고 하지만 일단 영어를 하루에 6문장씩 100일 해서 600 문장을 한번 외워본것에 의미를 두고 싶습니다. 다시 1일 부터 해서 반복해서 복습을 하는 걸로 감을 잃어버리지 않는 게 중요하다고 생각합니다. 

외우는 데 보통 시간은 얼마나?

처음 시작시 솔직히 하루종일 외웠습니다. 아침에 보고 점심때 또 보고 저녁때 보고 외워서 카톡방에 인증하고...

그러다가 한 20일쯤 되니 아침 출근길에 30분정도 보니 외워지더군요.. 그래도 주말에 쉬고 다시 월요일부터 외우면 다소 오래걸리긴 합니다. 아마 1시간정도 외우는 것 같아요. 

무엇을 얻었나?

개발자인 제 직업 특성상 하루에 영어 기술 문서를 상당히 자주 접하게 됩니다. 번역해서 자주 보는 편이지만 되도록 번역안하고 읽어볼려고 노력합니다. 예전엔 상당히 고역이었는데 지금은 문맥 흐름이 조금 보이는 정도? 인것 같아요. 

겨우 100일 가지고 많이 좋아지진 않았지만 계속 하다보면 말문이 트일것 같고 영어에 대한 자신감이 조금 생긴것 같아서 상당히 만족합니다. 

다음 도전은?

다시 1일부터 하루에 두개씩 진행할 예정이며 영어 원서를 매일 15분이상 진행도 하는 중입니다. 

이전 100일 책읽기를 성공함으로써 얻은 자신감과 또 한번의 100일 영어 외우기 자신감으로 새로운 도전을 성공적으로 할 수 있다는 자신감이 생긴것 같습니다. 

진심으로 한번 도전해보시길 바랍니다. 


현재 진행중인 도전

  • 매일 2시간이상 블록체인관련 공부하기 
  • 매일 15분이상 원서읽기
  • 매일 전공 공부하기
  • 기본 알고리즘 책 하나 떼기
  • 매일 15분이상 200일 도전중



+ Recent posts