๐ฅ ์ด๋ป๊ฒ ์์ ํ๋ฆ์์ ์ฝ๋ ํ์ง ๊ฒ์ฌ๋ฅผ ์๋์ผ๋ก ์คํํฉ๋๊น?โ
์นดํ๋ก๊ทธ
How to embed code analysis tools in your workflowโ
This article is not particularly focused on PHP, but on controlling the quality of your codebase at every stage of your workflow (editing => versioning => building). Thus, it can be helpful for any kind of project (front or back, Go or JS, ...). You just have to find the right tools for your language.
For the most impatient of you, I created a template project on
gitlab.com
to allow you to quickly bootstrap a PHP project with ready-to-use quality tools.
์ด๋ป๊ฒ ์์ ํ๋ฆ์ ์ฝ๋ ๋ถ์ ๋๊ตฌ๋ฅผ ์ฝ์ ํฉ๋๊นโ
Using the CLI to manually check your code is cool (really? ๐ค), but not very productive. Let's automatize โ that a bit!
๐ ํธ์ง๊ธฐ ๋๋ IDE์์
Personally, I use Atom๊ณผ Neovim.๋ ๋ค ๋ง์ ๊ณ ํ์ง ๋๊ตฌ์ ํ๋ฌ๊ทธ์ธ์ ์ ๊ณตํฉ๋๋ค.๊ทธ๋ฌ๋ ๋ชจ๋ ๊ธฐ์กด ํธ์ง๊ธฐ(Emacs, Sublimitext, VSCode...)๋ฐ IDE(Intellij, PhpStorm...)์ด ๋ชฉ์ ์ ์ํ ํ๋ฌ๊ทธ์ธ๋ ์์ต๋๋ค.๐ก Atom์ ํ๋ฌ๊ทธ์ธ ์ค์น:
apm install linter-phpmd \
linter-phpcs \
linter-php \
php-cs-fixer
Installing linter-phpmd to /home/boris/.atom/packages โ
Installing linter-phpcs to /home/boris/.atom/packages โ
Installing linter-php to /home/boris/.atom/packages โ
Installing php-cs-fixer to /home/boris/.atom/packages โ
๊ทธ๋ฐ ๋ค์ ๊ด๋ จ ๋๊ตฌ๋ฅผ ์ฐพ์ ์ ์๋๋ก ํ๋ฌ๊ทธ์ธ์ ๊ตฌ์ฑํด์ผ ํฉ๋๋ค(์: linter-phpcs
).โ ./vendor/bin/phpcs
).Composer(
composer global require xx/xx
)๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ธ๊ณ์ ์ค์นํ๋ค๋ฉด ~/.config/composer/vendor/bin
์ $PATH
์ ๋ฃ์ผ๋ฉด ๋ฉ๋๋ค.Atom์์ ๊ตฌ์ฑํ ํ์๊ฐ ์์ต๋๋ค.ํ๋ก์ ํธ ๋ฃจํธ ๋๋ ํฐ๋ฆฌ์์ PHPC(
phpcs.xml.dist
), phpmd(phpmd.xml.dist
), phpcsfixer(.php_cs.dist
)์ ํ์ค ํ์ผ ์ด๋ฆ์ ์ฌ์ฉํ์ฌ ๊ท์น ์งํฉ์ ์ ์ํ๋ฉด Atom์ ํ๋ฌ๊ทธ์ธ์ ์ํด ์๋์ผ๋ก ๋ถ๋ฌ์ต๋๋ค.Atom์ ๋ชจ์์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์ด ์ธ ๊ฐ์ง ๋๊ตฌ(
phpcs
, phpmd
๋ฐ php-cs-fixer
)๋ฅผ ์กฐํฉํ์ฌ ํ์ฌ ํ์ผ์ ๋ํ ์ค์๊ฐ ์ง๋จ์ ์ค์ํ๊ณ , ์จ๋ผ์ธ์ผ๋ก ๊ฒ์ถ๋ ์๋ฐ ํ์๋ฅผ ๊ฐ์กฐ ํ์ํ ์ ์์ต๋๋ค(์ค๋ฅ๋ ๋ฐ์ค์ ๊ธ๊ณ , ๋ง์ฐ์ค๊ฐ ๋ฉ์ถ๋ฉด ๋๊ตฌ ์๋ฆผ์ด ๋ํ๋๋ฉฐ, ๊ด๋ จ ์ค์ ์ฌ๋ฐฑ์ ๋ํ๊ฐ ํ์๋จ). php-cs-fixer
์ ์ ์ฅํ ๋ ์๋์ผ๋ก ์ค๋ฅ๋ฅผ ๋ณต๊ตฌํฉ๋๋ค.nvim์์๋ ํ์ฌ ํ์ผ ์๋์ ์ ์ฉ ๋ฒํผ์ ์ค๋ฅ๊ฐ ํ์๋ฉ๋๋ค. ํ์ผ ์์ฒด์ ์ํ๋ฌธ ์ ๋ณด๊ฐ ํฌํจ๋์ด ์์ต๋๋ค.
๋ง์ฝvim/neovim์ ๊ฐ๋ฐ ์ฒดํ์ ๊ฐ์ ํ๊ธฐ ์ํด ๊ธฐ์กด์ ํด๊ฒฐ ๋ฐฉ์์ ์ฐพ๊ณ ์๋ค๋ฉด ์ด ์ข์ ํด๊ฒฐ ๋ฐฉ์์ ๋ณด์ญ์์ค๐ ํญ๋ชฉ:
SpaceVim ํ์ฌ / SpaceVim ํ์ฌ
์ง์ญ์ฌํ ๊ตฌ๋์ ๋ชจ๋ํvim ๋ถํฌ - ์ต์ข vim ์ค์
Wiki |
Community |
Sponsors |
|
Gitter Chat |
ไธญๆๅฎ็ฝ
SpaceVim์ ์ง์ญ ์ฌํ๊ฐ ๊ตฌ๋ํ๋ ๋ชจ๋ํ๋ Vim ๋ถ๋ฐฐ์ด๋ค.๋ชจ์ ๊ด๋ฆฌ
ํ๋ฌ๊ทธ์ธ์ ๊ณ์ธตํ. ์ด๋ ๊ด๋ จ ํจํค์ง๋ฅผ ํ๋ฐ ๋ชจ์ IDE์ ์ ์ฌํ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ๋ฐ ๋์์ด ๋๋ค.
๋ง์ง๋ง ๋ฒ์ ์ v1.6.0์ ๋๋ค. following-HEAD ํ์ด์ง๋ฅผ ๋ณด๊ณ ์ง๋๋ฒ ๋ฐํ ์ดํ ๋ฐ์ํ ์ผ์ ์์๋ณด์ญ์์ค.
์์ธํ ๋ด์ฉ์ ๋ค์์ ์ฐธ์กฐํ์ญ์์ค.
Quick Start Guide: ์ด๋ณด์์ ๊ฐ๋จํ ์๋ด์.
Documentation: SpaceVim ์ฌ์ฉ์ ๋ํ ์ ์ฒด ๋ฌธ์
Available Layers: SpaceVim์ ํฌํจ๋ ๋ชจ๋ ์ฌ์ฉ ๊ฐ๋ฅํ ๋ ์ด์ด์ ๋ชฉ๋ก์ ๋๋ค.
SpaceVim ์ง์
์ด ํ๋ก์ ํธ์ ์กด์ฌ์ ๊ฐ์ฌ ๋ชจ๋ contributed
์ฐ๋ฆฌ๋ ์ง์ญ ์ฌํ์ ์ด๋ค ๊ณตํ์๋ ๊ฐ์ฌํ๋ค.
SpaceVim์ ์ง์ํ๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ์ค๋ฅ๋ฅผ ๋ณด๊ณ ํ์ฌ ํ์ ๊ธฐ์ฌํ๋ ๊ฒ์ ๋๋ค.
Gitter Chat์์ ์ง์ญ ์ฌํ๋ฅผ ๋๊ฑฐ๋pull ์์ฒญ์ ๋ณด๋ ๋๋ค.
์์ธํ ๋ด์ฉ์ development guidelines์ ์ฐธ์กฐํ์ญ์์ค.
SpaceVim์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ...
View on GitHub
๐ฑ git ์ฐ๊ฒฐ
Check the code in the editor is good, but do it before pushing to git is better!
Git comes with a set of hooks that you can use at many steps of the workflow (pre-commit, pre-push, post-update...). A git hook is just a script that will be executed before or after a particular event. It can be a shell script, a PHP script, a perl script, a python script or whatever scripting language. It can even be a binary. It just needs to be an executable.
Here is the list of all available hooks:
์ฐ๋ฆฌ๋
pre-commit
๊ฐ๊ณ ๋ฆฌ๋ฅผ ์ฃผ๋ชฉํ ๊ฒ์ด๋ค.์ฐ๋ฆฌ์ ์๊ฐ์
pre-commit
๊ฐ๊ณ ๋ฆฌ์ ํ์ง ๋๊ตฌ๋ฅผ ์คํํ์ฌ ๊ทํ๊ฐ ํ๋ก์ ํธ์ ์ ์ํ ํ์ค์ ๋ถํฉ๋๋์ง ํ์ธํ๋ ๊ฒ์
๋๋ค.๋ฐ๋ผ์ ์ค๋ฅ ์ฝ๋๋ฅผ ์ ์ถํ์ง ์๋๋ก ํ์ญ์์ค.โ ๏ธ
pre-commit
์คํฌ๋ฆฝํธ๋ฅผ ํธ์งํ๊ธฐ ์ ์ ์์์ผ ํ ๊ฒ์ ์ผ๋ถ ๋๊ตฌ๊ฐ ์ค๋ฅ ์ฝ๋๋ฅผ ๋๋๋ ค์ฃผ๋ฉด ์ ์ถ ๊ณผ์ ์ ์ค๋จํ๋ค๋ ๊ฒ์ด๋ค.์ด๊ฒ์ด ๋ฐ๋ก ์ฐ๋ฆฌ๊ฐ ์ํ๋ ๊ฒ์ด๋ค.๐ ๋ค์์ ๊ฐ์ธ์ ์ผ๋ก ์ฌ์ฉํ๋ ๋ ๊ฐ์ง ๊ท์น์ ๋๋ค.
pre-commit
๊ฐ๊ณ ๋ฆฌ๋ ์ฌ์ฉ์๊ฐ ์ ์ถํ ํ์ผ๋ง ๊ฒ์ฌํ๊ณ ๋ณต๊ตฌํด์ผ ํฉ๋๋ค.์ ์ฒด ์ฝ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ฒ์ฌ/๋ณต๊ตฌํด์ผ ํ๋ค๋ฉด, ํฉ๋ณ ์ง์ฅ์ด ๋ฐ์ํ์ง ์๋๋ก ํ์ ์๋์ผ๋ก ์คํํ๊ณ ํต์งํ์ญ์์ค..git/hooks/pre-commit.sample
์์ .git/hooks/pre-commit
์ ํ์ผ ์ด๋ฆ์ ๋ณ๊ฒฝํด์ผ ํฉ๋๋ค.๊ทธ๋ฆฌ๊ณ git ์ธ๋ฑ์ค์ ์ถ๊ฐ๋ ํ์ผ ๋ชฉ๋ก์ ๊ฒ์ํ๊ณ ํ์ํ ํ์ผ ํ์ฅ์ (.php,.go,.py...) ๋ฅผ ํํฐํด์ผ ํฉ๋๋ค.
#!/bin/bash
STAGED_FILES_CMD=`git diff --cached --name-only --diff-filter=ACMR HEAD | grep \\\\.php`
์ฌ๊ธฐ์์ ๋๋ ๋ชจ๋ ์ปดํจํฐ์์ ์คํํ ์ ์๋ ์ด์ ๊ฐ๋ฅํ ์คํฌ๋ฆฝํธ๋ฅผ ๊ฐ์ง๊ธฐ ์ํด bash
์ ์ฌ์ฉํ๋ค.๊ทธ๋ฌ๋ ๋ชจ๋ ์คํฌ๋ฆฝํธ ์ธ์ด๋ ๋ฐ์๋ค์ผ ์ ์๋ค.์ด์ ๊ฐ ํ์ง ๋๊ตฌ์ ์์ ์ ์ฅ ํ์ผ ๋ชฉ๋ก์ ์ ๊ณตํ์ฌ ์๋์ ํธ์ถ์ ์ถ๊ฐํ๊ณ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ ๋ 1๋ก ์ข ๋ฃํ์ฌ ์ ์ถ์ ์ค๋จํฉ๋๋ค.
#!/bin/bash
echo "Running pre-commit hook"
PROJECT=`php -r "echo dirname(dirname(dirname(realpath('$0'))));"`
STAGED_FILES_CMD=`git diff --cached --name-only --diff-filter=ACMR HEAD | grep \\\\.php`
echo "Checking PHP Lint..."
for FILE in $STAGED_FILES_CMD
do
php -l -d display_errors=0 $PROJECT/$FILE
if [ $? != 0 ]
then
echo "Fix the error before(s) commit."
exit 1
fi
FILES="$FILES $PROJECT/$FILE"
done
echo "Running PHP Code Beautifier and Fixer (phpcbf)..."
phpcbf --standard=phpcs.xml.dist $STAGED_FILES_CMD --colors --report=summary
if [ $? != 0 ]
then
echo "Fix the error before(s) commit."
exit 1
fi
echo "Running PHP-CS-FIXER..."
PHP_CS_STATUS=0
for FILE in $STAGED_FILES_CMD
do
php-cs-fixer fix $FILE
PHP_CS_STATUS=$(( $PHP_CS_STATUS + $? ))
done
if [ $PHP_CS_STATUS != 0 ]
then
echo "Fix the error(s) before commit."
fi
echo "End of pre-commit hook"
exit $PHP_CS_STATUS
์ฌ๊ธฐ์์ ๋๋ phpcs
๊ณผ phpmd
์ ์คํํ์ง ์๋๋ค. ์๋ํ๋ฉด ๊ทธ๊ฒ๋ค์ ๊ณ ๋์ ๋ง์ถคํ์ด ์์ด์ผ๋ง git ๊ฐ๊ณ ๋ฆฌ์์ ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.๊ทธ๋ ์ง ์์ผ๋ฉด ๋๋์ ์ค๋ฅ/๊ฒฝ๊ณ ๊ฐ ๋ฐ์ํ๊ณ ์ ์ถ์ ๋ง์ ์ ์์ต๋๋ค.๋์ ๋์ ๋๋ฃ๊ฐ ์ค๋น๊ฐ ๋ค ๋์์ ๋๋ง ํ ์ ์๋ค.๋ง์ฝ ๋ค๊ฐ ๋๋ฌด ์ผ์ฐ ํ๋ค๋ฉด, ๋์ ๋์ ํ์ ๋๋ด์ํฌ ์๋ ์๋ค.๋ง์ฝ ๋ค๊ฐ ์ค๋น๊ฐ ๋๋ค๋ฉด, ์ด phpmd file์ ์ข์ ์์์ด ๋ ๊ฒ์ด๋ค.
๋๋ ๋ํ PHP linter(
php -l
)๋ฅผ ์ฌ์ฉํ์ฌ ๋์ ๋ชจ๋ PHP ํ์ผ์ด ๋ฌธ๋ฒ์ ์ผ๋ก ์ ํํ๋ค๋ ๊ฒ์ ํ๋ณดํ๋ค.phpunit
์ ๋ํ ํธ์ถ๋ ์ถ๊ฐํ ์ ์์ง๋ง, ์ ์ถ์ด ๋นจ๋ผ์ผ ํ๊ธฐ ๋๋ฌธ์ ๋ช ์ด ์ด์ ์ง์๋ ์ ์์ต๋๋ค.git ๊ฐ๊ณ ๋ฆฌ์ ํ๊ณ๋ ๋จ์ง ๋์ ์์ ์ค์ ํ๋์ผ ๋ฟ์ด๋ค.๋๋ ๊ทธ๊ฒ์ผ๋ก ๋์ ๋ง์ ํ๋ก์ ํธ ํ์ผ์ lintํ๋ค: JSON, XML, swagger ์คํ, ๋งํฌ๋ค์ด, ์ ธ ์คํฌ๋ฆฝํธ...
swagger-cli:lint ๋น์ ์ ํ๋ค๋ฆผ ํ์ผ!
dockerlint: lint ๋น์ ์ Dockerfile!
shellcheck:lint ๋น์ ์ ์ ธ ์คํฌ๋ฆฝํธ!
๋ง์ง๋ง์ผ๋กgit ์ธ๋ฑ์ค์ ํ์ผ์ ์ถ๊ฐํ๊ณ ์ ์ถํด์ ๊ฐ๊ณ ๋ฆฌ๋ฅผ ํ ์คํธํ ์ ์์ต๋๋ค.
pre-commit
์คํฌ๋ฆฝํธ๊ฐ ์๋์ผ๋ก ํฐ์น๋ฉ๋๋ค.์์ผ๋ฉด ์คํ ์์น๊ฐ ์๋์ง ํ์ธํ์ญ์์ค.๊ทธ๋ ์ง ์์ผ๋ฉดchmod +x .git/hooks/pre-commit
โ Composer๋ฅผ ํตํ ์๋ํ
In , I introduced three tools and how to automatize their installation within Composer. This way, each developer can install them just by running composer install
at the project's root.
But how to ensure that each of them will use them each time they modify a single line of code? Fortunately, Composer comes also with a set of hooks allowing you to automatize some of your tasks.
Thus, instead of manually creating a pre-commit
script for every developers, the idea is to put the script somewhere in your codebase (e.g. in /contrib
), and to ask Composer to install it automatically when installing or updating your project.
Just add a new section in your composer.json
:
{
"scripts": {
"post-update-cmd": [
"mv .git/hooks/pre-commit .git/hooks/pre-commit.bak",
"cp contrib/pre-commit .git/hooks/pre-commit",
"chmod a+x .git/hooks/pre-commit"
],
"post-install-cmd": [
"mv .git/hooks/pre-commit .git/hooks/pre-commit.bak",
"cp contrib/pre-commit .git/hooks/pre-commit",
"chmod a+x .git/hooks/pre-commit"
]
}
}
That way, anytime a dev will be running composer install
or composer update
, the script will be installed.
๐ CI/CD ํ์ดํ์์
The goal of the quality control in the CI/CD pipeline is twofold:
- first check the whole codebase against your project's quality rules, and break the build in case of any error (like a unit test would do)
- (optionnally) perform a deeper analysis and publish a detailed build report that can be consulted by the devs at any time
Of course, it doesn't make sense to use a fixer ( phpcbf
, php-cs-fixer
) in the pipeline as it would modify the code after it has been pulled from the repo, and we don't want the code to be modified without any control of the devs.
โ Checking your whole codebase will have a significant impact on the build time. It can vary from few seconds to few minutes, depending on your code size.
For your information, on a 40 000 LoC project, it takes approximately 5 seconds for phpcs
and 40 seconds for phpmd
, with a relatively ยซlightยป analysis.
Regarding the deeper analysis, we'll use phpcs
and phpmd
to raise errors/warnings and to publish the results, either in ยซhuman-readableยป reports for devs (e.g. on a static website) with a notification in Slack, or in a standard format ( junit
, checkstyle
, other...) to be integrated in a statistics tool like Sonar
or PhpMetrics
.
Here is a simple example of a gitlab-ci's pipeline allowing to build, test & check a PHP app and to publish the reports to gitlab pages:
image: composer
stages:
- test
- deploy
test:app:
stage: test
script:
- apk add --no-cache $PHPIZE_DEPS
- pecl install xdebug-2.6.0
- docker-php-ext-enable xdebug
- composer install
- ./vendor/bin/phpunit --testsuite=unit --coverage-text --colors=never --log-junit reports/phpunit-junit.log --testdox-html reports/phpunit-report.html
- ./vendor/bin/phpcs -sw --standard=phpcs_squiz.xml.dist src --basepath=. --report=full --report-file=reports/phpcs-report.log || echo "ok"
- ./vendor/bin/phpmd src html phpmd.xml.dist --reportfile reports/phpmd-report.html --ignore-violations-on-exit
artifacts:
paths:
- reports
expire_in: 30m
pages:
stage: deploy
dependencies:
- test:app
script:
- mkdir public
- cp ci/pages/index.html public/
- cp reports/* public/
artifacts:
paths:
- public
only:
- master
์ฐธ๊ณ ๋ก ํ๋ก์ ํธ์
Gitlab Pages
์ ์ฌ์ฉํ๋ ค๋ฉด ํ์ดํ์ pages
์ด๋ผ๋ ์์
์ ๋ง๋ญ๋๋ค./public
์ ์
๋ ฅํ ๋ชจ๋ ๋ด์ฉ์ ๋ค์ URL์ ํตํด ํ๋ก์ ํธ ์ ์ ์ฌ์ดํธ์์ ์ ๊ทผํ ์ ์์ต๋๋ค: https://<group-or-username>.pages.forge.orange-labs.fr/<project-name>
.Gitlab Pages
์ ๋ํด ์ด์ผ๊ธฐํ ์ด์ API ๋ฌธ์ (PHPDoc, JavaDoc ๋๋ ๊ธฐํ), ์ฝ๋ ๋ฎ์ด์ฐ๊ธฐ๊ฐ ์๋ ํ
์คํธ ๋ณด๊ณ ์, Swagger
๋ฌธ์๋ฅผ ํธ์คํ
ํ ์ ์์ต๋๋ค.โญ ์ง์ผ๋ณดํ๋ค
There are many frameworks to manage the git hooks. Some of them are language specific (Node.js, PHP, Go, ...), and some others are language agnostic. They support many types of stacks. Just pick yours!
If you're interested in this topic, you can have a look at the Python pre-commit ์ด๊ฒ์ ๋งค์ฐ ๊ฐ๋ ฅํ๋ค.๊ทธ๋ฌ๋ ๊ฐ๋จํ ํ๋กํ์ ํตํด ๋ฏธ๋ฆฌ ์ ์ถํ ๋จ๊ณ๋ฅผ ์ผ๋ จ์ ์ฐ๊ฒฐ๋ก ์ ํํ ์ ์๊ธฐ ๋๋ฌธ์ ๋ณผ ๋งํ๋ค.์์ ์ ํ๋ฌ๊ทธ์ธ์ ์์ฑํด์ ๊ธฐ๋ฅ์ ํ์ฅํ ์๋ ์์ต๋๋ค.PHP์ ๊ฒฝ์ฐ DigitalPulp plugins์ ์ฐธ์กฐํ์ญ์์ค.
๐ ๋ง์ฝ ๋น์ ์ด ํ์ํ๋ค๋ฉด, ๋๋ ๊ธฐ๊บผ์ด ๋น์ ์๊ฒ ๋ ๋ง์ ์ธ๋ถ ์ฌํญ์ ์ค ๊ฒ์ ๋๋ค. ๊ทธ๋ฌ๋ ๋ง์ค์ด์ง ๋ง์ธ์!
Reference
์ด ๋ฌธ์ ์ ๊ดํ์ฌ(๐ฅ ์ด๋ป๊ฒ ์์ ํ๋ฆ์์ ์ฝ๋ ํ์ง ๊ฒ์ฌ๋ฅผ ์๋์ผ๋ก ์คํํฉ๋๊น?โ), ์ฐ๋ฆฌ๋ ์ด๊ณณ์์ ๋ ๋ง์ ์๋ฃ๋ฅผ ๋ฐ๊ฒฌํ๊ณ ๋งํฌ๋ฅผ ํด๋ฆญํ์ฌ ๋ณด์๋ค https://dev.to/biros/-how-to-master-your-code-through-your-project-lifecycle-22-2pejํ ์คํธ๋ฅผ ์์ ๋กญ๊ฒ ๊ณต์ ํ๊ฑฐ๋ ๋ณต์ฌํ ์ ์์ต๋๋ค.ํ์ง๋ง ์ด ๋ฌธ์์ URL์ ์ฐธ์กฐ URL๋ก ๋จ๊ฒจ ๋์ญ์์ค.
์ฐ์ํ ๊ฐ๋ฐ์ ์ฝํ ์ธ ๋ฐ๊ฒฌ์ ์ ๋ (Collection and Share based on the CC Protocol.)
์ข์ ์นํ์ด์ง ์ฆ๊ฒจ์ฐพ๊ธฐ
๊ฐ๋ฐ์ ์ฐ์ ์ฌ์ดํธ ์์ง
๊ฐ๋ฐ์๊ฐ ์์์ผ ํ ํ์ ์ฌ์ดํธ 100์ ์ถ์ฒ ์ฐ๋ฆฌ๋ ๋น์ ์ ์ํด 100๊ฐ์ ์์ฃผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์ ํ์ต ์ฌ์ดํธ๋ฅผ ์ ๋ฆฌํ์ต๋๋ค