├── .gitignore ├── README.md ├── eng ├── README.md ├── android │ ├── code-style │ │ ├── eclipse_codestyle.xml │ │ └── studio_codestyle.jar │ ├── coding_convention_android_kotlin.md │ ├── codingstyleguide.md │ ├── others.md │ └── standard.md ├── git │ └── flow.md ├── html_css │ └── standard.md ├── java │ ├── coding-standard.md │ └── java-formatter.xml ├── php │ ├── cakephp.md │ ├── others.md │ ├── phalcon.md │ ├── standard.md │ ├── symphony.md │ └── zend.md ├── rails │ ├── gems.md │ ├── references.md │ ├── standard.md │ └── test.md ├── ruby │ ├── references.md │ └── standard.md ├── swift │ └── coding_convention.md └── typescript │ └── standard.md ├── ja ├── README.md ├── android │ ├── codingstyleguide.md │ ├── others.md │ └── standard.md ├── git │ ├── flow.md │ └── references.md ├── javascript │ ├── references.md │ └── standard.md ├── rails │ ├── gems.md │ ├── references.md │ ├── standard.md │ └── test.md └── ruby │ ├── references.md │ └── standard.md ├── rubocop ├── .rubocop.yml ├── .rubocop_disabled.yml └── .rubocop_enabled.yml └── vn ├── README.md ├── android ├── coding_convention_android_kotlin.md ├── codingstyleguide.md ├── others.md └── standard.md ├── git └── flow.md ├── php ├── PSR-1.md ├── PSR-2.md └── others.md ├── rails ├── gems.md ├── references.md ├── standard.md └── test.md ├── ruby ├── references.md └── standard.md └── typescript └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea/vcs.xml 3 | .idea/coding-standards.iml 4 | .idea/modules.xml 5 | .idea/workspace.xml 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Framgia's coding standard 2 | 3 | ### [日本語](./ja/README.md) 4 | 5 | - [Ruby](./ja/README.md#ruby) 6 | - [Ruby on Rails](./ja/README.md#ruby-on-rails) 7 | - [Javascript](./ja/README.md#javascript) 8 | - [git](./ja/README.md#git) 9 | 10 | ### [Tiếng Việt](./vn/README.md) 11 | 12 | - [Android](./vn/README.md#android) 13 | - [PHP](./vn/README.md#php) 14 | - [Ruby](./vn/README.md#ruby) 15 | - [Ruby on Rails](./vn/README.md#ruby-on-rails) 16 | - [git](./vn/README.md#git) 17 | 18 | ### [English](./eng/README.md) 19 | 20 | - [Android](./eng/README.md#android) 21 | - [PHP](./eng/README.md#php) 22 | - [Ruby](./eng/README.md#ruby) 23 | - [Ruby on Rails](./eng/README.md#ruby-on-rails) 24 | - [Swift](./eng/README.md#swift) 25 | - [HTML-CSS](./eng/html_css/standard.md) 26 | -------------------------------------------------------------------------------- /eng/README.md: -------------------------------------------------------------------------------- 1 | # Framgia Coding Standard 2 | 3 | ## Android 4 | 5 | #### [Project structure](./android/standard.md) 6 | #### [Coding Style Guide](./android/codingstyleguide.md) 7 | #### [Others](./android/others.md) 8 | 9 | ## PHP 10 | 11 | #### [PSR-1 Basic Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md) 12 | #### [PSR-2 Coding Style Guide](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) 13 | #### [Others](./php/others.md) 14 | 15 | ## Ruby 16 | 17 | #### [Standard](./ruby/standard.md) 18 | #### [References](./ruby/references.md) 19 | 20 | ## Ruby on Rails 21 | 22 | #### [Standard](./rails/standard.md) 23 | #### [Test](./rails/test.md) 24 | #### [Gems](./rails/gems.md) 25 | #### [References](./rails/references.md) 26 | 27 | ## Swift 28 | 29 | #### [Coding convention](./swift/coding_convention.md) 30 | 31 | ## [HTML-CSS](html_css/standard.md) 32 | 33 | ## [TypeScript] 34 | 35 | #### [Standard](./typescript/standard.md) 36 | 37 | 38 | -------------------------------------------------------------------------------- /eng/android/code-style/studio_codestyle.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/framgia/coding-standards/145f855b0f7f37fee4fd7d37f6c5deb0f87cfbc6/eng/android/code-style/studio_codestyle.jar -------------------------------------------------------------------------------- /eng/android/others.md: -------------------------------------------------------------------------------- 1 | # Some other rules 2 | 3 | Here some other rules 4 | 5 | ### 1. Use Short IF 6 | 7 | Bad: 8 | 9 | ```java 10 | public boolean isEmulator(){ 11 | if(someThing){ 12 | return true; 13 | }else{ 14 | return false; 15 | } 16 | } 17 | ``` 18 | 19 | Good: 20 | 21 | ```java 22 | public boolean isEmulator(){ 23 | return someThing ? true : false; 24 | } 25 | ``` 26 | -------------------------------------------------------------------------------- /eng/android/standard.md: -------------------------------------------------------------------------------- 1 | # Project structure 2 | 3 | #### Base Application 4 | * ui 5 | * fragment 6 | * activity 7 | * dialog 8 | * widget 9 | * adapter 10 | * service 11 | * data 12 | * remote 13 | * local 14 | * model 15 | * util 16 | 17 | ## 1. Naming files 18 | 19 | ### 1.1 Class files 20 | 21 | Class name must be written in [UpperCamelCase](https://en.wikipedia.org/wiki/CamelCase) 22 | 23 | For class that extended in Andoid, class name should end with the name of the component 24 | 25 | For example: LoginActivity, MainActivity, UserController, WeatherService, SiginInDialog.... 26 | 27 | ### 1.2 Resources files 28 | 29 | Resources file names are written in lowercase_underscore 30 | 31 | #### 1.2.1 Drawable files 32 | 33 | Rule for naming Drawables: 34 | 35 | 36 | | Type | Prefix | Example | 37 | |--------------| ------------------|-----------------------------| 38 | | Action bar | `ab_` | `ab_stacked.9.png` | 39 | | Button | `btn_` | `btn_send_pressed.9.png` | 40 | | Dialog | `dialog_` | `dialog_top.9.png` | 41 | | Divider | `divider_` | `divider_horizontal.9.png` | 42 | | Icon | `ic_` | `ic_star.png` | 43 | | Menu | `menu_ ` | `menu_submenu_bg.9.png` | 44 | | Notification | `notification_` | `notification_bg.9.png` | 45 | | Tabs | `tab_` | `tab_pressed.9.png` | 46 | 47 | Rule for naming Icon (Theo [Android iconography guidelines](http://developer.android.com/design/style/iconography.html)): 48 | 49 | | Type | Prefix | Example | 50 | | --------------------------------| ---------------- | ---------------------------- | 51 | | Icons | `ic_` | `ic_star.png` | 52 | | Launcher icons | `ic_launcher` | `ic_launcher_calendar.png` | 53 | | Menu icons and Action Bar icons | `ic_menu` | `ic_menu_archive.png` | 54 | | Status bar icons | `ic_stat_notify` | `ic_stat_notify_msg.png` | 55 | | Tab icons | `ic_tab` | `ic_tab_recent.png` | 56 | | Dialog icons | `ic_dialog` | `ic_dialog_info.png` | 57 | 58 | Naming selector states: 59 | 60 | | State | Suffix | Example | 61 | |--------------|-----------------|-----------------------------| 62 | | Normal | `_normal` | `btn_order_normal.9.png` | 63 | | Pressed | `_pressed` | `btn_order_pressed.9.png` | 64 | | Focused | `_focused` | `btn_order_focused.9.png` | 65 | | Disabled | `_disabled` | `btn_order_disabled.9.png` | 66 | | Selected | `_selected` | `btn_order_selected.9.png` | 67 | 68 | 69 | #### 1.2.2 Layout files 70 | 71 | Apply Type _object _ purpose structure. Layout file names should match the name of Android component, and put at the beginning of the Files. For example, file layout name of `LoginActivity` will be `activity_login.xml`. 72 | 73 | | Component | Class name | Layout name | 74 | | ---------------- | ---------------------- | ----------------------------- | 75 | | Activity | `UserProfileActivity` | `activity_user_profile.xml` | 76 | | Fragment | `SignUpFragment` | `fragment_sign_up.xml` | 77 | | Dialog | `ChangePasswordDialog` | `dialog_change_password.xml` | 78 | | AdapterView item | --- | `item_person.xml` | 79 | | Partial layout | --- | `partial_stats_bar.xml` | 80 | 81 | #### 1.2.3 Menu files 82 | 83 | Because menu doesn't include Android component, naming Menu should follow name of screen. 84 | For example, in `MainActivity`, file manu name will be `activity_main.xml` 85 | 86 | Naming file should not include `menu` because files already is in `menu` folder. 87 | 88 | #### 1.2.4 Values files 89 | 90 | Resources files in valus should be in __plural__. For example `strings.xml`, `styles.xml`, `colors.xml`, `dimens.xml`, `attrs.xml` 91 | -------------------------------------------------------------------------------- /eng/git/flow.md: -------------------------------------------------------------------------------- 1 | ## Framgia Git flow 2 | 3 | Reference flow: [A successful Git branching model](http://nvie.com/posts/a-successful-git-branching-model/) 4 | 5 | ### Precondition 6 | * Already created central repository on Github (or Bitbucket) 7 | * Default branch of central repository is master 8 | * New member will fork central reposity 9 | * Decided reviewer and person who will merge pull request 10 | 11 | ### Principle 12 | * Each pull request will match with only 1 redmine ticket and have only 1 commit. 13 | * Title of commit will be `refs [tracker of ticket] #[number of ticket] [title of ticket]`. (For example: `refs bug #1234 Can not remove cache`). 14 | * Updating code of master branch on local is prohibited, please create a new branch to do your task. 15 | 16 | ### Prepare 17 | 18 | 1. Fork central repository to your account on Github (Bitbucket) 19 | 20 | 2. Clone forked repository to local. At this time, forked repository will be automatically registered as `origin` on local. 21 | ```sh 22 | $ git clone [URL of forked repository] 23 | ``` 24 | 25 | 3. Enter the directory created by `clone` command, register central repository as `upstream`. 26 | ```sh 27 | $ cd [created directory] 28 | $ git remote add upstream [URL of central repository] 29 | ``` 30 | 31 | ### Develop 32 | 33 | From now, we will call central repository as `upstream`, forked repository as `origin`. 34 | 35 | 1. Sync local's master branch with upstream's master branch. 36 | ```sh 37 | $ git checkout master 38 | $ git pull upstream master 39 | ``` 40 | 41 | 2. Create new branch to do task from master branch on local. Name of branch should be number of that task.(For example: `task/1234`) 42 | ```sh 43 | $ git checkout master # <--- unnecessary in case already on master branch 44 | $ git checkout -b task/1234 45 | ``` 46 | 47 | 3. Do your task (Freedomly create multiple commits). 48 | 49 | 4. If you created multiple commits when doing task, please use `rebase i` command to group them into 1 commit before moving to step 5. 50 | ```sh 51 | $ git rebase -i [hash value of the commit before the first commit you created or the number of commits needs to be grouped] 52 | ``` 53 | 54 | 5. Move to local's master branch and update to latest version. 55 | ```sh 56 | $ git checkout master 57 | $ git pull upstream master 58 | ``` 59 | 60 | 6. Move back to your task branch, rebase this branch with master branch. 61 | ```sh 62 | $ git checkout task/1234 63 | $ git rebase master 64 | ``` 65 | **If conflict error occurs when rebasing, please refer to "fix conflict error when rebasing" procedure.** 66 | 67 | 7. Push to `origin` 68 | 69 | ```sh 70 | $ git push origin task/1234 71 | ``` 72 | 73 | 8. On Github (Bitbucket), create pull request from origin's `task/1234` to upstream's `master` branch. 74 | 75 | 9. Paste pull request page's URL to chatwork group, ask reviewer to have code-review. 76 | 77 | 9.1. If reviewer asks you to fix something, do 3. ~ 6. step. 78 | 79 | 9.2. Use `push -f` command to force push to the same remote branch. 80 | ```sh 81 | $ git push origin task/1234 -f 82 | ``` 83 | 84 | 9.3. Repaste pull request page's URL to chatwork group, ask reviewer to have code-review. 85 | 86 | 10. When more than 2 reviewers gave you OK comment, reviewer who gave the final OK comment will merge that pull request. 87 | 11. Back to 1 step. 88 | 89 | ### Fix conflict error when rebasing 90 | 91 | If conflict error occurs when rebasing, it will be displayed as below (at this moment, you will be moved to anonymous branch automatically). 92 | ```sh 93 | $ git rebase master 94 | First, rewinding head to replay your work on top of it... 95 | Applying: refs #1234 Can not remove cache 96 | Using index info to reconstruct a base tree... 97 | Falling back to patching base and 3-way merge... 98 | Auto-merging path/to/conflicting/file 99 | CONFLICT (add/add): Merge conflict in path/to/conflicting/file 100 | Failed to merge in the changes. 101 | Patch failed at 0001 refs #1234 Can not remove cache 102 | The copy of the patch that failed is found in: 103 | /path/to/working/dir/.git/rebase-apply/patch 104 | 105 | When you have resolved this problem, run "git rebase --continue". 106 | If you prefer to skip this patch, run "git rebase --skip" instead. 107 | To check out the original branch and stop rebasing, run "git rebase --abort". 108 | ``` 109 | 110 | 1. Fix all the conflicts manually (code which is surrounded by <<< an >>>) 111 | Use `git rebase --abort` if you want to abort rebase process. 112 | 113 | 2. After fixing all conflicts, continue your rebase process. 114 | 115 | ```sh 116 | $ git add . 117 | $ git rebase --continue 118 | ``` -------------------------------------------------------------------------------- /eng/html_css/standard.md: -------------------------------------------------------------------------------- 1 | # Framgia HTML-CSS Coding Standard 2 | 3 | ## Indentation 4 | * Same as in PHP, please use 4 spaces for indentation. DO NOT USE HARD Tab. 5 | * Use lowercase for element names, attributes, attributes values (unless text/CDATA), CSS selectors, properties, property values. 6 | * Remove trailing white spaces. 7 | 8 | ## HTML 9 | * Use ```
```, not ```
``` 10 | * When quoting attributes, please use double quotation marks 11 | ```html 12 | Link to google 13 | ``` 14 | ## CSS 15 | * Omit unit specification after “0” values 16 | ```css 17 | margin: 0; 18 | padding: 0; 19 | ``` 20 | * Omit leading “0”s in values. 21 | ```css 22 | font-size: .8em; 23 | ``` 24 | * Separate words in ID and class names by a hyphen. 25 | ```css 26 | #video-id {} 27 | .ads-sample {} 28 | ``` 29 | * Put declarations in alphabetical order. Ignore vendor-specific prefixes for sorting purposes. 30 | ```css 31 | background: fuchsia; 32 | border: 1px solid; 33 | -moz-border-radius: 4px; 34 | -webkit-border-radius: 4px; 35 | border-radius: 4px; 36 | color: black; 37 | text-align: center; 38 | text-indent: 2em; 39 | ``` 40 | * Use a space between the last selector and the declaration block. 41 | Use a space after a property name’s colon. 42 | ```css 43 | h3 { 44 | font-weight: bold; 45 | } 46 | ``` 47 | 48 | ## References 49 | * [Google HTML/CSS Style Guide](https://google-styleguide.googlecode.com/svn/trunk/htmlcssguide.xml). 50 | -------------------------------------------------------------------------------- /eng/java/java-formatter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 32 | -------------------------------------------------------------------------------- /eng/php/cakephp.md: -------------------------------------------------------------------------------- 1 | Please refer to the following document: 2 | [CakePHP Coding Standards](http://book.cakephp.org/2.0/en/contributing/cakephp-coding-conventions.html) 3 | -------------------------------------------------------------------------------- /eng/php/others.md: -------------------------------------------------------------------------------- 1 | Some other conventions 2 | ===================== 3 | 4 | The following are some other conventions that are not defined clearly in PSR. 5 | 6 | - Use the newest PHP version if possible. 7 | - When declaring array, item list can be split across multiple lines. Then the following rules must be followed: 8 | - The first item must be put in a new line. 9 | - There must be only one item per line. Each subsequent line is indented once. 10 | - There must be a comma at the last line. 11 | - The mark of ending array declaration (`]` for `[]` or `)` for `array()`) must be put in a new line. 12 | 13 | ```php 14 | // Bad 15 | $a = [$foo, 16 | $bar 17 | ]; 18 | 19 | // Bad 20 | $a = [ 21 | $foo, $bar, 22 | $baz, 23 | ]; 24 | 25 | // Bad 26 | $a = [ 27 | $foo, 28 | $bar 29 | ]; 30 | 31 | // Bad 32 | $a = [ 33 | $foo, 34 | $bar,]; 35 | 36 | // Bad 37 | $a = [$foo, $bar,]; 38 | 39 | // Good 40 | $a = [ 41 | $foo, 42 | $bar, 43 | ]; 44 | 45 | $a = [$foo, $bar]; 46 | ``` 47 | 48 | - When using PHP >= 5.4, use array short syntax. (`[]` instead of `array()`) 49 | ```php 50 | // Good 51 | $a = []; 52 | $b = [ 53 | $key => $value, 54 | $key2 => $value2, 55 | ]; 56 | 57 | // Bad 58 | $a = array(); 59 | $b = array( 60 | $key => $value, 61 | $key2 => $value2, 62 | ); 63 | ``` 64 | 65 | - Variables MUST be written in `camelCase`. However, Model's properties can be written in `snake_case` so they can be the same with columns name in table in database. 66 | - Use `'` for normal string. Only use `"` when you have PHP variables inside. 67 | ```php 68 | $normalString = 'A String'; 69 | $specialString = "This is {$normalString}"; 70 | ``` 71 | - There MUST be one space before and after each operator (such as `+`, `-`, `*`, `/`, `.`, `>`, `<`, `==` ...) 72 | - To format the year part of a date as `yyyy`, use `Y`. 73 | -------------------------------------------------------------------------------- /eng/php/phalcon.md: -------------------------------------------------------------------------------- 1 | # Framgia Phalcon Coding Standard 2 | 3 | This documentation was created based on [Framgia Hyakkaten Project - Coding Standard(Vietnamese)](https://github.com/framgia/hkt/blob/master/docs/coding_standard.md). 4 | 5 | ## 1. PHP Version 6 | 7 | * PHP 5.4 or higher. 8 | 9 | ## 2. Naming rule 10 | 11 | * Class's name should be written in UpperCamelCase. Function's name should be written in LowerCamelCase. Private function name should be started with ```_```. 12 | 13 | Class example: ```MailSender```, ```UserIdentity```. 14 | 15 | Function example: ```addCondition```, ```sendMail```, ```_checkMail```. 16 | 17 | * Variable's name should be written in snake_case. Private variable should start with ```_```. 18 | 19 | Variable example: ```$user_id```, ```$is_admin```, ```private $_status```. 20 | 21 | * Constant variable name should be in capital case, separated by ```_``` 22 | 23 | Sample: ```A_CONSTANT_VARIABLE``` 24 | 25 | #### 3. Indentation 26 | 27 | Use 4 spaces for indentation. (DO NOT USE HARD Tab) 28 | 29 | ## 4. String 30 | 31 | Use single quote for normal string, double quotes for string which contain php variable. 32 | ```php 33 | $str = 'This is a string'; 34 | echo "result = {$result}"; 35 | ``` 36 | 37 | ## 5. Control Structures 38 | Control structures contain ```if```, ```for```, ```foreach```, ```while```, ```switch```,... 39 | Below is an example of ```if```. 40 | ```php 41 | if ((expr_1) || (expr_2)) { 42 | // action_1; 43 | } elseif (!(expr_3) && (expr_4)) { 44 | // action_2; 45 | } else { 46 | // default_action; 47 | } 48 | ``` 49 | Some notes: 50 | * Use one space before the first parenthesis, one space between the last parenthesis and the opening bracket. 51 | * Always use curly bracket even if the are not needed. 52 | * Opening curly bracket should be placed in the same line as the control structure. 53 | * Inline assignment should not be used inside of the control structure. 54 | * In case of ```switch``` control structure, ```case``` must have the same indentation level as the control structure. 55 | 56 | ## 6. Function 57 | * Do not use space between function name and the open parenthesis. 58 | * Do not use space between the open parenthesis and the first variable. 59 | * Use space between comma and next varialbe. 60 | * Do not use space between the last variable and the close parenthesis. 61 | * Do not use space between the close parenthesis and semicolon. 62 | 63 | ```php 64 | $var = foo($bar, $baz, $quux); 65 | ``` 66 | 67 | In case of using multiple parameters when calling function: 68 | * Parameters placed in new line should be indented by 4 spaces in comparison to function call line. 69 | * The close parenthesis should be placed in new line. 70 | 71 | ```php 72 | $this->someObject->subObject->callThisFunctionWithALongName( 73 | $this->someOtherFunc( 74 | $this->someEvenOtherFunc( 75 | 'Help me!', 76 | [ 77 | 'foo' => 'bar', 78 | 'spam' => 'eggs', 79 | ], 80 | 23 81 | ), 82 | $this->someEvenOtherFunc() 83 | ), 84 | $this->wowowowowow(12) 85 | ); 86 | ``` 87 | 88 | ## 7. Class 89 | * Opening curly bracket ```{``` must be placed in new line 90 | ```php 91 | class FooBar 92 | { 93 | //... code goes here 94 | } 95 | ``` 96 | 97 | ## 8. Function declaration 98 | * Opening curly bracket ```{``` must be placed in new line. 99 | * Try to make your function return something. 100 | ```php 101 | function fooBar() 102 | { 103 | // ... code goes here 104 | return true; 105 | } 106 | ``` 107 | 108 | ## 9. Array 109 | * Do not use ```array()```, use ```[]``` instead. 110 | 111 | When dividing array to multiple lines, you can place ```,``` in the final line 112 | 113 | ```php 114 | $some_array = [ 115 | 'key' => 'val', 116 | 'foo' => 'bar', 117 | ]; 118 | ``` 119 | 120 | ## 10. PHP Code Tags 121 | * Always you long tags ``````, instead of short tag ``````. 122 | * You can use ``````. 123 | * If your file contains only php code, do not use close tag ```?>```. 124 | 125 | ## 11. Comments 126 | * Use comment style of C (```/* */```) or C++ (```//```). 127 | * DO NOT use Perl/Shell style (```#```). 128 | 129 | ## 12. Class comment 130 | * Write comment for each variable declared inside class. Comment should be placed righ before declaring variable. 131 | 132 | Structure: ```@var ClassName (VariableName) Your comment here``` 133 | 134 | Example: 135 | ```php 136 | /** 137 | * @var ActiveRecord the currently loaded data model instance. 138 | */ 139 | 140 | private $_model; 141 | ``` 142 | * Write comment for each function declared inside class. Comment should be place right before declaring function. 143 | 144 | Structure: 145 | ```php 146 | @param ClassName VariableName 147 | @return ClassName VariableName 148 | ``` 149 | 150 | Example: 151 | ```php 152 | /** 153 | * Returns the static model of the specified AR class. 154 | * @param string $className active record class name. 155 | * @return User the static model class 156 | */ 157 | public static function model($className = __CLASS__) 158 | { 159 | return parent::model($className); 160 | } 161 | ``` 162 | 163 | # MVC 164 | 165 | ## 13. Model and Database 166 | 167 | * Table name should be plural and underscored. For examples: ```users```, ```big_people```, ```news```. 168 | * All tables should have primary key named ```id```. 169 | * Foreign key is named by "singular" name of related table and followed by ```_id```. For examle, if you want to add a field of your table which related to ```id``` of table ```users```, you should name it as ```user_id```. 170 | * Join table should be named by the two related table, seperated by underscored. For example: ```students_subjects``` 171 | * Model class corresponding to table should be plural and CameCased. For example: ```Users```, ```BigPeople```, ```News```. 172 | 173 | ## 14. Controller 174 | 175 | * Controller which corresponding to a model, should be named same as model's name, followed by Controller. For example: ```UsersController```. 176 | * Action name should be cameBack and followed by Action. For example: ```indexAction```. 177 | 178 | 179 | ## 15. View 180 | 181 | * File name should be correspond to action name, and written in ```snake_case``` 182 | * Use Volt template engine. 183 | 184 | If you aren't familiar with Volt, please read the following documents. 185 | 186 | Phalcon: Volt Template Engine 187 | http://docs.phalconphp.com/en/latest/reference/volt.html 188 | 189 | Jinja2: Template Designer Documentation 190 | http://jinja.pocoo.org/docs/templates/ 191 | -------------------------------------------------------------------------------- /eng/php/standard.md: -------------------------------------------------------------------------------- 1 | # Framgia PHP Coding Standard 2 | 3 | With PHP, we have a lot of Frameworks, each framework has its own coding standards. 4 | 5 | In the following links, we wrote out the coding standards for each PHP Framework. 6 | 7 | Sometimes, we only folow official documentation of the framework. 8 | 9 | [Phalcon](phalcon.md) 10 | 11 | [CakePHP](cakephp.md) 12 | 13 | [Symphony](symphony.md) 14 | 15 | [Zend](zend.md) -------------------------------------------------------------------------------- /eng/php/symphony.md: -------------------------------------------------------------------------------- 1 | Please refer to the following document: 2 | [Symphony Coding Standards](http://symfony.com/doc/current/contributing/code/standards.html) 3 | -------------------------------------------------------------------------------- /eng/php/zend.md: -------------------------------------------------------------------------------- 1 | Please refer to the following document: 2 | [Zend Framework Coding Standard](http://framework.zend.com/manual/1.10/en/coding-standard.html) 3 | -------------------------------------------------------------------------------- /eng/rails/gems.md: -------------------------------------------------------------------------------- 1 | # List of standardized gems in Ruby on Rails 2 | 3 | One of the principles of software development is DRY - Don't Repeat Yourself. 4 | When facing with a problem, before trying to solve it by yourself, first researching if there are any existing solutions. 5 | Below is a list of valuable gems which have proved to be useful in many Rails projects. 6 | All gems work with Rails 3.1. 7 | 8 | ## Creating admin panel 9 | 10 | * [active_admin](https://github.com/gregbell/active_admin) - Help creating admin panel in a simple way. It can quickly create CRUD functions of models and give a flexible customization. 11 | 12 | ## Development environment, test environment improvement 13 | 14 | **These are not suitable for production environment** 15 | 16 | * [capybara](https://github.com/jnicklas/capybara) - Easily implement integration test for web frameworks using Rack such as Rails, Sinatra, Merb. Help simulating users' interactions with web application. Built-in support for Rack::Test and Selenium. Using of HtmlUnit, Webkit, env.js can be done by installing extra gems. RSpec and Cucumber can be used simultaneously is also a plus. 17 | 18 | * [better_errors](https://github.com/charliesome/better_errors) - Replace Rails default error pages with a more convenient error pages. It can also be used as Rack Middleware in other Rack applications outside of Rails. 19 | 20 | * [cucumber-rails](https://github.com/cucumber/cucumber-rails) - A helpful tool to implement integration test in Rails. Using it allow us to use Cucumber in Rails. 21 | 22 | * [factory_girl](https://github.com/thoughtbot/factory_girl) - Help creating objects for test actions. 23 | 24 | * [ffaker](https://github.com/EmmanuelOga/ffaker) - Help creating sample data easily. 25 | 26 | * [guard](https://github.com/guard/guard) - Can monitoring changes made to files and do automated tasks. Used in many tools. 27 | 28 | * [spork](https://github.com/sporkrb/spork) - A DRb server for testing frameworks such as RSpec or Cucumber. By pre-populating test environment, it helps shorten time spent on testing. 29 | 30 | * [simplecov](https://github.com/colszowka/simplecov) - Analyze overall information about code. Can be used with Ruby 1.9. 31 | 32 | * [rspec-rails](https://github.com/rspec/rspec-rails) - For using RSpec in Rails. 33 | 34 | ## Performance improvement 35 | 36 | * [bullet](https://github.com/flyerhzm/bullet) - Improve performance of application by reducing number of queries. It monitors your queries and notify you where you should add eager loading (n + 1 queries), where eager loading is unnecessary or where you should use counter cache. 37 | 38 | ## Upload file 39 | 40 | * [Paperclip](https://github.com/thoughtbot/paperclip) - File attachment library that works with ActiveRecord. 41 | 42 | ## Search 43 | 44 | * [sunspot](https://github.com/sunspot/sunspot) - A library for using Solr search engine. 45 | 46 | ## Authorization management 47 | 48 | * [cancan](https://github.com/ryanb/cancan) - Can restrict users' access to resources. All authorities are managed in one place and can be checked across the application. 49 | 50 | * [devise](https://github.com/plataformatec/devise) - Give you all necessary features for an application. 51 | 52 | ## View template 53 | 54 | * [haml-rails](https://github.com/indirect/haml-rails) - Help using HAML in Rails. 55 | 56 | * [haml](http://haml-lang.com) - HAML is a shorter template language than ERB. 57 | 58 | * [slim](http://slim-lang.com) - Slim is considered better than ERB and HAML. Slim also has good performance. The main reason for not using Slim is it isn't widely supported by many editors or IDE. 59 | 60 | ## Client side support 61 | 62 | * [client_side_validations](https://github.com/bcardarella/client_side_validations) - Automatically create Javascript validations which run on client side based on validations defined in models in server. 63 | 64 | ## SEO 65 | 66 | * [friendly_id](https://github.com/norman/friendly_id) - Help identify objects by friendly-reading attributes instead of id of models. 67 | 68 | ## Pagination 69 | 70 | * [kaminari](https://github.com/amatsuda/kaminari) - For flexible pagination. 71 | 72 | ## Image manipulation 73 | 74 | * [minimagick](https://github.com/probablycorey/mini_magick) - Ruby wrapper of ImageMagick 75 | 76 | ## These gems should be standard or not is undecided 77 | 78 | * [simplecov-rcov](https://github.com/fguillen/simplecov-rcov) - RCov format for SimpleCov. Useful for using SimpleCov with Hudson continuous integration server. 79 | 80 | * [carrierwave](https://github.com/jnicklas/carrierwave) - Help with uploading files in Rails. Support local storage and cloud storage for uploaded files (and many other features). Integrated with ImageMagick helps us with image manipulation. 81 | 82 | * [compass-rails](https://github.com/chriseppstein/compass) - Support for some css frameworks. Include collections of sass mixin which helps shorten css code and dealt with incompatible browsers. 83 | 84 | * [fabrication](http://fabricationgem.org/) - A good replacement for fixtures. 85 | 86 | * [feedzirra](https://github.com/pauldix/feedzirra) - Analyze RSS/Atom faster and easier. 87 | 88 | * [globalize3](https://github.com/svenfuchs/globalize3.git) - Globalize3 is the next version of Globalize in Rails, target ActiveRecord version 3.x. It is compatible and is built on top of the new I18n API of Ruby on Rails and add translations into ActiveRecord. 89 | 90 | * [machinist](https://github.com/notahat/machinist) - Easily create objects for testing purposes. 91 | 92 | * [simple_form](https://github.com/plataformatec/simple_form) - Once you use simple form, you will never want to use Rails default forms again. It has good DSL for creating forms and no options on markup. 93 | 94 | * [email-spec](https://github.com/bmabey/email-spec) - Easily testing email with RSpec and Cucumber. 95 | 96 | ## Gems which are not recommended 97 | 98 | These gems have errors or there are better gems. You shouldn't use these if possible. 99 | 100 | * [rmagick](http://rmagick.rubyforge.org/) - We shouldn't use this because it uses memory wastefully. Use minimagick instead. 101 | 102 | * [autotest](http://www.zenspider.com/ZSS/Products/ZenTest/) - An automation test tool. Use guard instead. 103 | 104 | * [rcov](https://github.com/relevance/rcov) - Does not support Ruby 1.9. Use simplecov instead. 105 | 106 | * [therubyracer](https://github.com/cowboyd/therubyracer) - It uses too much memory. Use Node.js instead. 107 | -------------------------------------------------------------------------------- /eng/rails/references.md: -------------------------------------------------------------------------------- 1 | ## Rules about writing Ruby on Rails code (Reference links) 2 | -------------------------------------------------------------------------------- /eng/rails/test.md: -------------------------------------------------------------------------------- 1 | # Rules about writing Ruby on Rails code (test) 2 | 3 | Best practice to add a new feature maybe BDD. Usually when use Cucumber, start with writing test in high level, then adjust code following test specification. 4 | First write specification of views related to feature, then create related view following this specification. 5 | Next write specification of controller to pass needed data to above views, then create controller following this specification. 6 | Last write specification and create model. 7 | 8 | ## Cucumber 9 | 10 | * Incompleted scenarios should be tagged `@wip` (work in progress). Those scenarios will not be counted and will not display error. When the feature is created and run, if you want to test these scenarios, you can remove tag `@wip`. 11 | 12 | * Can setup default profile to exclude scenarios with tag ` @javascript `. Those are used for testing in browsers, so it is recommend to exclude them to speed up other scenarios. 13 | 14 | * Can create a separate profile to for scenarios with tag ` @javascript `. 15 | * Profile can be defined in ` cucumber.yml ` file. 16 | 17 | ```Ruby 18 | # definition of a profile: 19 | profile_name: --tags @tag_name 20 | ``` 21 | * Run profile by command: 22 | 23 | ``` 24 | cucumber -p profile_name 25 | ``` 26 | * Check for existence of text elements such as link or button by checking for text, not by checking for ID. This will help finding errors with i18n. 27 | 28 | * Object which has many features should be separated by features: 29 | ```Ruby 30 | # bad 31 | Feature: Articles 32 | # ... feature implementation ... 33 | 34 | # good 35 | Feature: Article Editing 36 | # ... feature implementation ... 37 | 38 | Feature: Article Publishing 39 | # ... feature implementation ... 40 | 41 | Feature: Article Search 42 | # ... feature implementation ... 43 | 44 | ``` 45 | 46 | * Each feature has 3 important elements 47 | * Title 48 | * Description - short explanation about feature 49 | * Content - Collection of scenarios with steps 50 | 51 | * Usually use Connextra format 52 | 53 | ```Ruby 54 | In order to [benefit] ... 55 | A [stakeholder]... 56 | Wants to [feature] ... 57 | ``` 58 | 59 | This format should be used but not enforced. You can freely describe feature depend on its complexity. 60 | 61 | * Use outline to ensure DRY. 62 | 63 | ```Ruby 64 | Scenario Outline: User cannot register with invalid e-mail 65 | When I try to register with an email "" 66 | Then I should see the error message "" 67 | 68 | Examples: 69 | |email |error | 70 | | |The e-mail is required| 71 | |invalid email |is not a valid e-mail | 72 | ``` 73 | 74 | * Steps of each scenario is written in ` .rb ` files in `step_definitions` folder. File name follows format `[description]_steps.rb`. 75 | We can separate steps into files using standard type. We can separate each feature into 1 file such as `home_page_steps.rb`, or separate based on object, and all related features will be in 1 file like `articles_steps.rb`. 76 | 77 | * To avoid duplications, preparing arguments into multiple lines. 78 | 79 | ```Ruby 80 | Scenario: User profile 81 | Given I am logged in as a user "John Doe" with an e-mail "user@test.com" 82 | When I go to my profile 83 | Then I should see the following information: 84 | |First name|John | 85 | |Last name |Doe | 86 | |E-mail |user@test.com| 87 | 88 | # the step: 89 | Then /^I should see the following information:$/ do |table| 90 | table.raw.each do |field, value| 91 | find_field(field).value.should =~ /#{value}/ 92 | end 93 | end 94 | ``` 95 | 96 | * To ensure DRY for scenarios, grouping multiple steps to use. 97 | 98 | ```Ruby 99 | # ... 100 | When I subscribe for news from the category "Technical News" 101 | # ... 102 | 103 | # the step: 104 | When /^I subscribe for news from the category "([^"]*)"$/ do |category| 105 | steps %Q{ 106 | When I go to the news categories page 107 | And I select the category #{category} 108 | And I click the button "Subscribe for this category" 109 | And I confirm the subscription 110 | } 111 | end 112 | ``` 113 | * Matcher of Capybara does not use ``` should_not ``` in positive but use in negative matcher. So scenarios will be executed in timeout of ajax action. [You can find more information in README of Capybara.](https://github.com/jnicklas/capybara) 114 | 115 | ## RSpec 116 | 117 | * Expect only 1 result for 1 example 118 | 119 | ```ruby 120 | # bad 121 | describe ArticlesController do 122 | describe "GET new" do 123 | before {get :new} 124 | it do 125 | assigns[:article].is_expected.to be_a_new Article 126 | response.is_expected.to render_template :new 127 | end 128 | end 129 | end 130 | 131 | # good 132 | describe ArticlesController do 133 | describe "GET new" do 134 | before {get :new} 135 | subject {response} 136 | it {is_expected.to render_template :new} 137 | end 138 | end 139 | ``` 140 | 141 | * Use `describe` and `context` freely when needed. 142 | * Use `describe` to group by class, module, method (or action of controller). You don't have to follow this rule with view. 143 | * Use `context` to group conditions of example. 144 | 145 | * Name block of `describe` like the following 146 | * Write explanation in case of non-method. 147 | * In case of instance method add "#" like "#method" 148 | * In case of class method add "." like ".method" 149 | 150 | ```ruby 151 | class Article 152 | def summary 153 | #... 154 | end 155 | 156 | def self.latest 157 | #... 158 | end 159 | end 160 | 161 | # the spec... 162 | describe Article do 163 | describe "#summary" do 164 | #... 165 | end 166 | 167 | describe ".latest" do 168 | #... 169 | end 170 | end 171 | ``` 172 | 173 | * Use [factory_girl](https://github.com/thoughtbot/factory_girl) to create object for testing purpose. 174 | * Use mock or stub if needed. 175 | * When creating mock of model use `as_null_object` method. When we use this method, we can output expected messages only, all other messages will be ignored. 176 | 177 | ```ruby 178 | # mock of model 179 | article = mock_model(Article).as_null_object 180 | 181 | # stub of method 182 | Article.stub(:find).with(article.id).and_return(article) 183 | ``` 184 | 185 | * When create data for example, use `let` for lazy evaluation. Do not use instance variable instead of `let`. 186 | 187 | ```ruby 188 | # use this 189 | let(:article) {FactoryGirl.create :article} 190 | 191 | # instead of this 192 | before(:each) {@article = FactoryGirl.create :article} 193 | ``` 194 | 195 | * Must use `expect` or `is_expected` with `subject`. 196 | 197 | ```ruby 198 | describe Article do 199 | subject {FactoryGirl.create :article} 200 | it {is_expected.to be_published} 201 | end 202 | ``` 203 | 204 | * Inside `it` we can use `expect` and `is_expected`. Do not use `specify` or `should`. 205 | * Do not use strings to be parameters of `it`. Write spec self explanatory. 206 | 207 | ```ruby 208 | # bad 209 | describe Article do 210 | subject {FactoryGirl.create :article} 211 | it "is an Article" do 212 | subject.is_expected.to be_an Article 213 | end 214 | end 215 | 216 | # good 217 | describe Article do 218 | subject {FactoryGirl.create :article} 219 | it {is_expected.to be_an Article} 220 | end 221 | ``` 222 | * Do not use `its`. 223 | 224 | ```ruby 225 | # bad 226 | describe Article do 227 | subject {FactoryGirl.create :article} 228 | its(:created_at) {is_expected.to eq Date.today} 229 | end 230 | 231 | # good 232 | describe Article do 233 | subject {FactoryGirl.create :article} 234 | it {expect(subject.created_at).to eq Date.today} 235 | end 236 | ``` 237 | 238 | * Use method chain only once with argument of `expect`. 239 | 240 | * Use `shared_examples` in case of grouping spec shared by multiple tests. 241 | 242 | ```ruby 243 | # bad 244 | describe Array do 245 | subject {Array.new [7, 2, 4]} 246 | context "initialized with 3 items" do 247 | it {expect(subject.size).to eq 3 } 248 | end 249 | end 250 | 251 | describe Set do 252 | subject {Set.new [7, 2, 4]} 253 | context "initialized with 3 items" do 254 | it {expect(subject.size).to eq 3} 255 | end 256 | end 257 | 258 | # good 259 | shared_examples "a collection" do 260 | subject {described_class.new([7, 2, 4])} 261 | context "initialized with 3 items" do 262 | it {expect(subject.size).to eq 3} 263 | end 264 | end 265 | 266 | describe Array do 267 | it_behaves_like "a collection" 268 | end 269 | 270 | describe Set do 271 | it_behaves_like "a collection" 272 | end 273 | ``` 274 | 275 | ### Models 276 | * Do not mock model in its own model spec. 277 | * Use factory_girl to create object without mock. 278 | * Can mock other models, or children objects. 279 | * Create examples to check validity of model which has been `factoried`. 280 | 281 | ```ruby 282 | describe Article do 283 | subject {FactoryGirl :article} 284 | it {is_expected.to be_valid} 285 | end 286 | ``` 287 | 288 | * Do not use `.not_to be_valid` to check validation. Use `have(x).errors_on` method to identify which errors occur. 289 | 290 | ```ruby 291 | # bad 292 | describe "#title" do 293 | subject {FactoryGirl.create :article} 294 | before {subject.title = nil} 295 | it {is_expected.not_to be_valid} 296 | end 297 | 298 | # good 299 | describe "#title" do 300 | subject {FactoryGirl.create :article} 301 | before {subject.title = nil} 302 | it {is_expected.to have(1).error_on(:title)} 303 | end 304 | ``` 305 | 306 | * Add separate `describe` for attributes need to validate. 307 | * When test for object is unique or not, use `another_[tên object]` to name the other objects. 308 | 309 | ```ruby 310 | describe Article do 311 | describe "#title" do 312 | subject {FactoryGirl.build :article} 313 | before {@another_article = FactroyGirl.create :article} 314 | it {is_expected.to have(1).error_on(:title)} 315 | end 316 | end 317 | ``` 318 | 319 | ###Views 320 | 321 | * The structure of `spec/views` folder should be the same as `app/views` folder. For example, spec files of view in `app/views/users` folder will be in corresponding `spec/views/users` folder. 322 | * Spec file naming rule is adding `_spec.rb` after view's name. For example, corresponding spec file of `_form.html.haml` is `_form.html.haml_spec.rb`. 323 | * In `spec_helper.rb` only write necessary code for other specs. 324 | * With the outermost `describe` block, defining path to view file should exclude the `app/views` part. This is not defining parameters but being used when calling `render` method. 325 | 326 | ```ruby 327 | # spec/views/articles/new.html.haml_spec.rb 328 | require "spec_helper" 329 | 330 | describe "articles/new.html.haml" do 331 | # ... 332 | end 333 | ``` 334 | 335 | * Models in spec of view are usually created by mock. View is for presentation purpose only. 336 | * Use `assign` method to define instance variables used in view which are defined in controller. 337 | 338 | ```ruby 339 | # spec/views/articles/edit.html.haml_spec.rb 340 | describe "articles/edit.html.haml" do 341 | subject {rendered} 342 | let(:article) {mock_model(Article).as_new_record.as_null_object} 343 | before do 344 | assign :article, article 345 | render 346 | end 347 | it do 348 | is_expected.to have_selector "form", method: "post", action: articles_path do |form| 349 | form.is_expected.to have_selector "input", type: "submit" 350 | end 351 | end 352 | ``` 353 | 354 | * Do not combine positive declaration of Capybara with `.not_to`, use `.to` with negative declaration. 355 | 356 | ```ruby 357 | # bad 358 | page.is_expected.not_to have_selector "input", type: "submit" 359 | page.is_expected.not_to have_xpath "tr" 360 | 361 | # good 362 | page.is_expected.to have_no_selector "input", type: "submit" 363 | page.is_expected.to have_no_xpath "tr" 364 | ``` 365 | 366 | * Use stub for helper method in spec of view. Stub helper method on `template` object. 367 | 368 | ```ruby 369 | # app/helpers/articles_helper.rb 370 | class ArticlesHelper 371 | def formatted_date date 372 | # ... 373 | end 374 | end 375 | 376 | # app/views/articles/show.html.haml 377 | = "Published at: #{formatted_date @article.published_at}" 378 | 379 | # spec/views/articles/show.html.haml_spec.rb 380 | describe "articles/show.html.haml" do 381 | subject {rendered} 382 | before do 383 | article = mock_model Article, published_at: Date.new(2012, 01, 01) 384 | assign :article, article 385 | template.stub(:formatted_date).with(article.published_at).and_return("01.01.2012") 386 | render 387 | end 388 | it {is_expected.to have_content "Published at: 01.01.2012"} 389 | end 390 | ``` 391 | 392 | * Put spec of helper in `spec/helpers`. 393 | 394 | ### Controllers 395 | 396 | * Use mock for instance of model class. Use stub for model's methods. This is to avoid results of controller spec affecting implementation of model. 397 | * Controller should only test below behaviors 398 | * If methods are executed or not. 399 | * Data, instance variables returned from action are assigned or not. 400 | * Result of action: render correct template or not, redirect correctly or not. 401 | 402 | ```ruby 403 | # Example of a commonly used controller spec 404 | # spec/controllers/articles_controller_spec.rb 405 | # We are interested only in the actions the controller should perform 406 | # So we are mocking the model creation and stubbing its methods 407 | # And we concentrate only on the things the controller should do 408 | 409 | describe ArticlesController do 410 | # The model will be used in the specs for all methods of the controller 411 | let(:article) {mock_model Article} 412 | let(:input) {"The New Article Title"} 413 | 414 | describe "POST create" do 415 | before do 416 | Article.stub(:new).and_return(article) 417 | article.stub(:save) 418 | post :create, message: {title: input} 419 | end 420 | 421 | it do 422 | expect(Article).to receive(:new).with(title: input).and_return article 423 | end 424 | 425 | it do 426 | expect(article).to receive(:save) 427 | end 428 | 429 | it do 430 | expect(response).to redirect_to(action: :index) 431 | end 432 | end 433 | end 434 | ``` 435 | 436 | * If behavior of action changes based on parameters, use context. 437 | 438 | ```ruby 439 | # A classic example for use of contexts in a controller spec is creation or update when the object saves successfully or not. 440 | 441 | describe ArticlesController do 442 | let(:article) {mock_model Article} 443 | let(:input) {"The New Article Title"} 444 | 445 | describe "POST create" do 446 | before do 447 | Article.stub(:new).and_return(article) 448 | post :create, article: {title: input} 449 | end 450 | 451 | it do 452 | expect(Article).to receive(:new).with(title: input).and_return(article) 453 | end 454 | 455 | it do 456 | expect(article).to receive :save 457 | end 458 | 459 | context "when the article saves successfully" do 460 | before do 461 | article.stub(:save).and_return(true) 462 | end 463 | 464 | it {expect(flash[:notice]).to eq("The article was saved successfully.")} 465 | it {expect(response).to redirect_to(action: "index")} 466 | end 467 | 468 | context "when the article fails to save" do 469 | before do 470 | article.stub(:save).and_return(false) 471 | end 472 | 473 | it {expect(assigns[:article]).to be article} 474 | it {expect(response).to render_template("new")} 475 | end 476 | end 477 | end 478 | ``` 479 | 480 | ### Mailers 481 | 482 | * Inside spec for mailer, all models should be mocked. Mailer does not depend on model. 483 | * In spec of mailer, test for the below behaviors 484 | * Title is correct or not 485 | * Recipient is correct or not 486 | * Sender is correct or not 487 | * Mail content is correct or not 488 | 489 | ```ruby 490 | describe SubscriberMailer do 491 | let(:subscriber) {mock_model(Subscription, email: "johndoe@test.com", name: "John Doe")} 492 | 493 | describe "successful registration email" do 494 | subject(:mail) {SubscriptionMailer.successful_registration_email(subscriber)} 495 | 496 | it {expect(mail.subject).to eq "Successful Registration!"} 497 | it {expect(mail.from).to eq ["info@your_site.com"]} 498 | it {expect(mail.to).to eq [subscriber.email]} 499 | end 500 | end 501 | ``` 502 | -------------------------------------------------------------------------------- /eng/ruby/references.md: -------------------------------------------------------------------------------- 1 | ## Rules about writing Ruby on Rails code (Reference links) 2 | 3 | * [Ruby Styleguide](https://github.com/styleguide/ruby) 4 | * [Prelude](https://github.com/bbatsov/ruby-style-guide) 5 | * [Summary of rules about writing Ruby code - bojovs::blog](http://bojovs.github.com/2012/04/24/ruby-coding-style/) 6 | -------------------------------------------------------------------------------- /eng/typescript/standard.md: -------------------------------------------------------------------------------- 1 | # Sun* TypeScript Coding Standard 2 | 3 | ## For TypeScript we follow the coding style defined by Google. Please follow the following links 4 | 5 | > refer: 6 | > - https://google.github.io/styleguide/tsguide.html 7 | 8 | ## For checking the coding style please use below Eslint config 9 | > refer: 10 | > - https://github.com/typescript-eslint/typescript-eslint 11 | 12 | 13 | -------------------------------------------------------------------------------- /ja/README.md: -------------------------------------------------------------------------------- 1 | # Framgia コーディング規約 2 | 3 | ## Ruby 4 | 5 | - [標準スタイル](./ruby/standard.md) 6 | - [参考サイト](./ruby/references.md) 7 | 8 | ## Ruby on Rails 9 | 10 | #### [標準スタイル](./rails/standard.md) 11 | #### [テスト編](./rails/test.md) 12 | #### [標準gem](./rails/gems.md) 13 | #### [参考サイト](./rails/references.md) 14 | 15 | ## HTML 16 | 17 | ## CSS 18 | 19 | ## Javascript 20 | 21 | #### [標準スタイル](./javascript/standard.md) 22 | #### [参考サイト](./javascript/references.md) 23 | 24 | ## git 25 | 26 | #### [標準フロー](./git/flow.md) 27 | #### [参考サイト](./git/references.md) 28 | -------------------------------------------------------------------------------- /ja/android/codingstyleguide.md: -------------------------------------------------------------------------------- 1 | # Coding Style Guide 2 | This document is based on other reference documents and [Android Code Style Guidelines](https://source.android.com/source/code-style.html) 3 | 4 | ## 1. Java language rules 5 | 6 | ### 1.1 Don't ignore Exception 7 | 8 | 以下のようにしないでください: 9 | 10 | ```java 11 | void setServerPort(String value) { 12 | try { 13 | serverPort = Integer.parseInt(value); 14 | } catch (NumberFormatException e) { } 15 | } 16 | ``` 17 | どのExceptionでも対応しないといけない。 18 | 19 | * メソッドの呼び出し側でThrow Expectionする。 20 | ```java 21 | void setServerPort(String value) throws NumberFormatException { 22 | serverPort = Integer.parseInt(value); 23 | } 24 | ``` 25 | * 抽象化の程度に合って新しいExceptionをThrowする。 26 | ```java 27 | void setServerPort(String value) throws ConfigurationException { 28 | try { 29 | serverPort = Integer.parseInt(value); 30 | } catch (NumberFormatException e) { 31 | throw new ConfigurationException("Port " + value + " is not valid."); 32 | } 33 | } 34 | ``` 35 | * Catch{} ブロックで適当な値を差し替える。 36 | ```java 37 | void setServerPort(String value) { 38 | try { 39 | serverPort = Integer.parseInt(value); 40 | } catch (NumberFormatException e) { 41 | serverPort = 80; // default port for server 42 | } 43 | } 44 | ``` 45 | 46 | * ExceptionをCatchし、RuntimeExceptionをthrowする。クラッシュを発生する可能性があるので、危険である。 47 | 48 | ```java 49 | void setServerPort(String value) { 50 | try { 51 | serverPort = Integer.parseInt(value); 52 | } catch (NumberFormatException e) { 53 | throw new RuntimeException("port " + value " is invalid, ", e); 54 | } 55 | } 56 | ``` 57 | * なんでも大丈夫の自信を持ったら無視できるけど、適当な理由をコメントしないといけない。 58 | 59 | ```java 60 | void setServerPort(String value) { 61 | try { 62 | serverPort = Integer.parseInt(value); 63 | } catch (NumberFormatException e) { 64 | // Method is documented to just ignore invalid user input. 65 | // serverPort will just be unchanged. 66 | } 67 | } 68 | ``` 69 | 70 | ### 1.2 Don't Catch Generic Exception 71 | 72 | 以下のようにしないべきである 73 | 74 | ```java 75 | try { 76 | someComplicatedIOFunction(); // may throw IOException 77 | someComplicatedParsingFunction(); // may throw ParsingException 78 | someComplicatedSecurityFunction(); // may throw SecurityException 79 | // phew, made it all the way 80 | } catch (Exception e) { // I'll just catch all exceptions 81 | handleError(); // with one generic handler! 82 | } 83 | ``` 84 | 85 | [詳細](https://source.android.com/source/code-style.html#dont-catch-generic-exception) について 86 | 87 | ### 1.3 Don't Use finalizers 88 | 89 | [Android code style guidelines](https://source.android.com/source/code-style.html#dont-use-finalizers)への参考 90 | 91 | ### 1.4 Fully qualify imports 92 | 93 | 良くない : `import foo.*;` 94 | 95 | 良い : `import foo.Bar;` 96 | 97 | 詳細については [click here](https://source.android.com/source/code-style.html#fully-qualify-imports) 98 | 99 | ## 2 Java style rules 100 | 101 | ### 2.1 Java Style Rules 102 | 103 | フィールド名は最初に定義され、下のコンベンションに従うことが必要である。 104 | 105 | * Non-public, non-static フィールドには `m` から名付ける。 106 | * Static フィールドには `s` から名付ける。 107 | * 他のフィールドはローワーケース文字から名付ける。 108 | * Public static final フィールド (constants) は ALL_CAPS_WITH_UNDERSCORES. 109 | 110 | 例: 111 | 112 | ```java 113 | public class MyClass { 114 | public static final int SOME_CONSTANT = 42; 115 | public int publicField; 116 | private static MyClass sSingleton; 117 | int mPackagePrivate; 118 | private int mPrivate; 119 | protected int mProtected; 120 | } 121 | ``` 122 | 123 | ### 2.2 Treat Acronyms as Words 124 | 125 | 以下のように変数、メソッド、クラスに名付ける 126 | 127 | | 良い | 良くない | 128 | | -------------- | -------------- | 129 | | `XmlHttpRequest` | `XMLHTTPRequest` | 130 | | `getCustomerId` | `getCustomerID` | 131 | | `String url` | `String URL` | 132 | | `long id` | `long ID` | 133 | 134 | ### 2.3 Use Spaces for Indentation 135 | 136 | ブロックは四つのスペースインデントを使う 137 | 138 | ```java 139 | if (x == 1) { 140 | x++; 141 | } 142 | ``` 143 | 144 | ラインラップは八つのスペースインデントを使う, 変数への割り当てや関数呼び出しを含める 145 | ```java 146 | Instrument i = 147 | someLongExpression(that, wouldNotFit, on, one, line); 148 | ``` 149 | 150 | ### 2.4 Use Standard Brace Style in Java 151 | 152 | 中括弧は前のコードと同じ行に書かれる 153 | ```java 154 | class MyClass { 155 | int func() { 156 | if (something) { 157 | // ... 158 | } else if (somethingElse) { 159 | // ... 160 | } else { 161 | // ... 162 | } 163 | } 164 | } 165 | ``` 166 | 167 | 条件文は一行で書けたら、一行にすべきである。 168 | 169 | ```java 170 | if (condition) body(); 171 | ``` 172 | 173 | 以下のようにしないべきである 174 | ```java 175 | if (condition) 176 | body(); // bad! 177 | ``` 178 | 179 | ### 2.5 Use Standard Java Annotations 180 | 181 | Android code style guideによりますと、Annotationsの標準は: 182 | 183 | * `@Override`: メソッドは親クラスからdeclarationかimplementationをオーバーライドする時、このannotationを使わないといけないである。例えば、ActivityクラスからのonCreateを使用したら、メソッドが親クラスから@Overrideすることは注釈を付けないと。 184 | 185 | * `@ SuppressWarnings `: warningが取り除けない時、このannotationが使われる。 186 | 187 | ### 2.6 Limit Variable Scope 188 | 189 | ローカル変数の範囲はできるだけ最小を保つ。そうすると、コードは明らかに、読みやすく、修正しやすく、維持しやすくなりつつ不具合を減らす。変数はアプリケーションが使えるように最も内側のブロックに宣言すべきである。 190 | 191 | ローカル変数は初めての使用される時に宣言すべきである。変数を初期化するための情報が不足なら、十分の情報があるまで待つべきだ。[具体的に](https://source.android.com/source/code-style.html#limit-variable-scope) 192 | 193 | ### 2.7 How to Log 194 | 195 | `Log`は問題を特定できるためにエラーメッセージをprint outするクラスである。 196 | 197 | * `Log.v(String tag, String msg)` (verbose) 198 | * `Log.d(String tag, String msg)` (debug) 199 | * `Log.i(String tag, String msg)` (information) 200 | * `Log.w(String tag, String msg)` (warning) 201 | * `Log.e(String tag, String msg)` (error) 202 | 203 | 一般的なルールによる、ファイルごとにクラス名はTAGとして使われるべきである: 204 | 205 | ```java 206 | public class MyClass { 207 | private static final String TAG = "MyClass"; 208 | 209 | public myMethod() { 210 | Log.e(TAG, "Error message"); 211 | } 212 | } 213 | ``` 214 | 215 | `Debug`で表示する、`Release`で表示しない場合は 216 | 217 | ```java 218 | if (BuildConfig.DEBUG) Log.d(TAG, "Xの値は" + x); 219 | ``` 220 | 221 | ### 2.8 Class member ordering 222 | 223 | こちらは解決策のみではないけど、以下の順番でおすすめだ: 224 | 225 | 1. Constants 226 | 2. Fields 227 | 3. Constructors 228 | 4. Override methods and callbacks (public or private) 229 | 5. Public methods 230 | 6. Private methods 231 | 7. Inner classes or interfaces 232 | 233 | 例: 234 | 235 | ```java 236 | 237 | public class MainActivity extends Activity { 238 | 239 | private String mTitle; 240 | private TextView mTextViewTitle; 241 | 242 | public void setTitle(String title) { 243 | mTitle = title; 244 | } 245 | 246 | @Override 247 | public void onCreate() { 248 | ... 249 | } 250 | 251 | private void setUpView() { 252 | ... 253 | } 254 | 255 | static class AnInnerClass { 256 | 257 | } 258 | 259 | } 260 | 261 | 262 | ``` 263 | 264 | コンポーネントのlifecycleは以下の順に従って並んだほうが良い 265 | 266 | ```java 267 | public class MainActivity extends Activity { 268 | 269 | //Order matches Activity lifecycle 270 | @Override 271 | public void onCreate() {} 272 | 273 | @Override 274 | public void onResume() {} 275 | 276 | @Override 277 | public void onPause() {} 278 | 279 | @Override 280 | public void onDestory() {} 281 | 282 | } 283 | ``` 284 | 285 | ### 2.9 Parameter ordering in methods 286 | 287 | Androidで、メソッドは常に`Context`がパラメーターとして使う。`Context`は最初、`callback`は最後のパラメーターにすべきである。 288 | 289 | 例: 290 | 291 | ```java 292 | // Context always be first 293 | public User loadUser(Context context, int userId); 294 | 295 | // Callbacks always be last 296 | public void loadUserAsync(Context context, int userId, UserCallback callback); 297 | ``` 298 | 299 | ### 2.10 String constants, naming and values 300 | 301 | Androidの色んな素子はkey-value型を使う。例:SharedPreferences、Bundle、Intent。 302 | 303 | 以上のコンポーネントを仕様したら、keysを`static final`として定義しないといけない: 304 | 305 | | 素子 | フィールド名の接頭辞 | 306 | | ----------------- | ----------------- | 307 | | SharedPreferences | `PREF_` | 308 | | Bundle | `BUNDLE_` | 309 | | Fragment Arguments | `ARGUMENT_` | 310 | | Intent Extra | `EXTRA_` | 311 | | Intent Action | `ACTION_` | 312 | 313 | 例: 314 | 315 | ```java 316 | // Value of the field is the same as the name to avoid duplication 317 | static final String PREF_EMAIL = "PREF_EMAIL"; 318 | static final String BUNDLE_AGE = "BUNDLE_AGE"; 319 | static final String ARGUMENT_USER_ID = "ARGUMENT_USER_ID"; 320 | 321 | // Intent should use full package name as value 322 | static final String EXTRA_SURNAME = "com.myapp.extras.EXTRA_SURNAME"; 323 | static final String ACTION_OPEN_USER = "com.myapp.action.ACTION_OPEN_USER"; 324 | ``` 325 | 326 | ### 2.11 Argument in Activity and Fragment 327 | 328 | `Intent`か`Bundle`で`Activity`または`Framgment`にデートを渡す時、keysはルールに従わないといけない __[2.10](#210-string-constants-naming-and-values)__ 。そして、 `public static`で宣言することが必要である。 329 | 330 | ユーザーをactivityに渡す場合、`getProfileIntent()`を呼ぶ 331 | 332 | ```java 333 | public static Intent getProfileIntent(Context context, User user) { 334 | Intent intent = new Intent(context, ProfileActivity.class); 335 | intent.putParcelableExtra(EXTRA_USER, user); 336 | return intent; 337 | } 338 | ``` 339 | 340 | fragmentを使用する場合 341 | 342 | ```java 343 | public static UserFragment newInstance(User user) { 344 | UserFragment fragment = new UserFragment; 345 | Bundle args = new Bundle(); 346 | args.putParcelable(ARGUMENT_USER, user); 347 | fragment.setArguments(args) 348 | return fragment; 349 | } 350 | ``` 351 | 352 | ### 2.12 Line length limit 353 | 354 | コード行は__100文字__を超えないべきである。超えた場合、減らす仕方が二つあり: 355 | 356 | * ローカル変数かメソッドを使う。 357 | * line-wrappingを使って複数の行に分割する。 358 | 359 | 100文字以上を使える例外が以下のようになる 360 | 361 | * 行が分割できない。例:URLs 362 | * `package` や `import` ステートメント 363 | 364 | #### 2.12.1 Line-wrapping strategies 365 | 366 | line-wrapのルールがないけど、共通のケースにおいてルールがある。 367 | 368 | __Method chain case__ 369 | 370 | 色んなメソッドが一行でつなぐ時、メソッドごとに一行で呼ばれるつつ`.`の前に改行する。 371 | 372 | 例: 373 | 374 | ```java 375 | 376 | Picasso.with(context).load("https://farm6.staticflickr.com/5595/14899879106_f5028bd19d_k.jpg").into(imageView); 377 | 378 | 379 | ``` 380 | 381 | Become 382 | 383 | ```java 384 | 385 | Picasso.with(context) 386 | .load("https://farm6.staticflickr.com/5595/14899879106_f5028bd19d_k.jpg") 387 | .into(imageView); 388 | 389 | 390 | ``` 391 | 392 | __Long parameters case__ 393 | 394 | メソッドは複数のパラメーターがあり、パラメーターも長い時、`,`改行すべきである。 395 | 396 | ```java 397 | loadPicture(context, "https://farm6.staticflickr.com/5595/14899879106_f5028bd19d_k.jpg", mImageViewProfilePicture, clickListener, "Title of the picture"); 398 | ``` 399 | 400 | ```java 401 | loadPicture(context, 402 | "https://farm6.staticflickr.com/5595/14899879106_f5028bd19d_k.jpg", 403 | mImageViewProfilePicture, clickListener, 404 | "Title of the picture"); 405 | ``` 406 | 407 | ### 2.13 RxJava chains styling 408 | 409 | Rx`operator`は新しい行にしないといけない、`.`の前に改行する。 410 | 411 | ```java 412 | public Observable syncLocations() { 413 | return mDatabaseHelper.getAllLocations() 414 | .concatMap(new Func1>() { 415 | @Override 416 | public Observable call(Location location) { 417 | return mConcurService.getLocation(location.id); 418 | } 419 | }) 420 | .retry(new Func2() { 421 | @Override 422 | public Boolean call(Integer numRetries, Throwable throwable) { 423 | return throwable instanceof RetrofitError; 424 | } 425 | }); 426 | } 427 | ``` 428 | 429 | ## 3 XML style rules 430 | 431 | ### 3.1 Use self closing tags 432 | 433 | WHen an XML element doesn't have any content, you must use self closing tags. 434 | 435 | XML素子は内容がない場合、`/>`タグを使用すべきである。 436 | 437 | 良い: 438 | 439 | ```xml 440 | 441 | 445 | 446 | ``` 447 | 448 | 良くない: 449 | 450 | ```xml 451 | 452 | 456 | 457 | 458 | ``` 459 | 460 | ### 3.2 Naming resources 461 | 462 | Resource IDs や Resource名はlowercase_underscoreで宣言されることが必要である。 463 | 464 | #### 3.2.1 Naming ID 465 | 466 | ID should be prefixed with name of element and use underscore. For example : 467 | 468 | IDの接頭辞は素子名のアンダースコアにすべきである。例: 469 | 470 | | 素子 | 接頭辞 | 471 | | ----------------- | ----------------- | 472 | | `TextView` | `text_` | 473 | | `ImageView` | `image_` | 474 | | `Button` | `button_` | 475 | | `Menu` | `menu_` | 476 | | `RelativeLayout` | `relative_` | 477 | | `LinearLayout ` | `linear_` | 478 | 479 | 480 | ImageViewの例: 481 | 482 | ```xml 483 | 484 | 488 | 489 | 490 | ``` 491 | 492 | `annotation` libraryを使用する場合は、変数のように宣言できる。 493 | 494 | ```xml 495 | 496 | 500 | 501 | 502 | ``` 503 | 504 | 特別なケースにおいて、__Action and Object Name__をスキップできる。 505 | 506 | 例えば、リストのアイテムである。 507 | 508 | ```java 509 | 510 | 521 | 532 | 533 | 542 | ``` 543 | 544 | 545 | #### 3.2.2 Strings 546 | 547 | String名は接頭辞からである。例:`registration_email_hint` or `registration_name_hint`。 548 | Stringがどのセクションに属しなかったら、以下のルールに従う: 549 | 550 | | 接頭辞 | 説明 | 551 | | ----------------- | --------------------------------------| 552 | | `error_` | エーらーメッセージ | 553 | | `msg_` | 情報メッセージ | 554 | | `title_` | タイトル。例: dialog, activity | 555 | | `action_` | アクション `Save`, `Edit` , `Delete` | 556 | 557 | #### 3.2.3 Styles and Themes 558 | 559 | __UpperCamelCase__ で宣言 560 | 561 | #### 3.2.4 Attributes ordering 562 | 563 | As a common rules you should group similar attributes together. 564 | 565 | 一般的なルールにより、同様のattributesをグループすべきである。 566 | 567 | 1. View Id 568 | 2. Style 569 | 3. Layout width and layout height 570 | 4. Other layout attributes, sorted alphabetically 571 | 5. Remaining attributes, sorted alphabetically -------------------------------------------------------------------------------- /ja/android/others.md: -------------------------------------------------------------------------------- 1 | # Some other rules 2 | 3 | 他のルール 4 | 5 | ### 1. Use Short IF 6 | 7 | 良い: 8 | 9 | ```java 10 | public boolean isEmulator(){ 11 | if(someThing){ 12 | return true; 13 | }else{ 14 | return false; 15 | } 16 | } 17 | ``` 18 | 19 | 良くない: 20 | 21 | ```java 22 | public boolean isEmulator(){ 23 | return someThing ? true : false; 24 | } 25 | ``` 26 | -------------------------------------------------------------------------------- /ja/android/standard.md: -------------------------------------------------------------------------------- 1 | # プロジェクト構成 2 | 3 | #### Base Application 4 | * ユーザーインターフェース 5 | * fragment 6 | * activity 7 | * dialog 8 | * widget 9 | * adapter 10 | * サビース 11 | * データ 12 | * remote 13 | * local 14 | * model 15 | * ユーティリティ 16 | 17 | ## 1. ファイルに名付ける 18 | 19 | ### 1.1 クラスファイル 20 | 21 | クラス名は[アッパーキャメルケース](https://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A3%E3%83%A1%E3%83%AB%E3%82%B1%E3%83%BC%E3%82%B9)で書かれないといけない。 22 | 23 | Androidで拡張されるクラスについてクラス名はコンポーネント名で終わるべきである。 24 | 25 | 例:LoginActivity, MainActivity, UserController, WeatherService, SiginInDialog.... 26 | 27 | ### 1.2 リソースファイル 28 | 29 | リソースファイル名はローワーケース_アンダースコアで書かれる。 30 | 31 | #### 1.2.1 Drawable ファイル 32 | 33 | Drawableファイルに名付ける規則: 34 | 35 | 36 | | タイプ | 接頭辞 | 例 | 37 | |--------------| ------------------|-----------------------------| 38 | | Action bar | `ab_` | `ab_stacked.9.png` | 39 | | Button | `btn_` | `btn_send_pressed.9.png` | 40 | | Dialog | `dialog_` | `dialog_top.9.png` | 41 | | Divider | `divider_` | `divider_horizontal.9.png` | 42 | | Icon | `ic_` | `ic_star.png` | 43 | | Menu | `menu_ ` | `menu_submenu_bg.9.png` | 44 | | Notification | `notification_` | `notification_bg.9.png` | 45 | | Tabs | `tab_` | `tab_pressed.9.png` | 46 | 47 | Iconファイルに名付ける規則 ([Android iconography guidelines](http://developer.android.com/design/style/iconography.html)により): 48 | 49 | | タイプ | 接頭辞 | 例 | 50 | | --------------------------------| ---------------- | ---------------------------- | 51 | | Icons | `ic_` | `ic_star.png` | 52 | | Launcher icons | `ic_launcher` | `ic_launcher_calendar.png` | 53 | | Menu icons and Action Bar icons | `ic_menu` | `ic_menu_archive.png` | 54 | | Status bar icons | `ic_stat_notify` | `ic_stat_notify_msg.png` | 55 | | Tab icons | `ic_tab` | `ic_tab_recent.png` | 56 | | Dialog icons | `ic_dialog` | `ic_dialog_info.png` | 57 | 58 | セレクターステートに名づける: 59 | 60 | | ステート | 接尾辞 | 例 | 61 | |--------------|-----------------|-----------------------------| 62 | | Normal | `_normal` | `btn_order_normal.9.png` | 63 | | Pressed | `_pressed` | `btn_order_pressed.9.png` | 64 | | Focused | `_focused` | `btn_order_focused.9.png` | 65 | | Disabled | `_disabled` | `btn_order_disabled.9.png` | 66 | | Selected | `_selected` | `btn_order_selected.9.png` | 67 | 68 | 69 | #### 1.2.2 レイアウトファイル 70 | 71 | object_purposeの構造を使う。レイアウトファイル名はAndroidコンポーネント名に合わせるべきである。例えば、`LoginActivity`のレイアウトファイル名は`activity_login.xml`になる。 72 | 73 | | コンポーネント | クラス名 | レイアウトファイル | 74 | | ---------------- | ---------------------- | ----------------------------- | 75 | | Activity | `UserProfileActivity` | `activity_user_profile.xml` | 76 | | Fragment | `SignUpFragment` | `fragment_sign_up.xml` | 77 | | Dialog | `ChangePasswordDialog` | `dialog_change_password.xml` | 78 | | AdapterView item | --- | `item_person.xml` | 79 | | Partial layout | --- | `partial_stats_bar.xml` | 80 | 81 | #### 1.2.3 メニューファイル 82 | 83 | メニューはAndroidコンポーネントを含めないので、画面に従ってメニューファイルに名付けるべきである。例えば、`MainActivity`で、メニューファイル名は`activity_main.xml`になる。 84 | 85 | ファイルは`menu`フォルダにおけるので、ファイル名は`menu`を含めないべきである。 86 | 87 | #### 1.2.4 Value ファイル 88 | 89 | Valueフォルダでリソースファイルは__複数__になるべきである。例えば、`strings.xml`, `styles.xml`, `colors.xml`, `dimens.xml`, `attrs.xml` 90 | -------------------------------------------------------------------------------- /ja/git/flow.md: -------------------------------------------------------------------------------- 1 | ## Framgia Git flow 2 | 3 | 参考フロー: [A successful Git branching model](http://nvie.com/posts/a-successful-git-branching-model/) 4 | 5 | ### 前提 6 | * Github(または Bitbucket)上にセントラルリポジトリを作成済である。 7 | * セントラルリポジトリのデフォルトブランチが master になっている。 8 | * 各開発者が、セントラルリポジトリを Fork できる。 9 | * レビュワーとマージ権限を持つ人が決まっている。 10 | 11 | ### 原則 12 | * 1プルリクエストにつき、1チケットとする。 13 | * 1プルリクエストでのコミット回数は自由。 14 | * プルリクエストのタイトルをチケットのタイトルに合わせる。 `refs [チケットのトラッカー] #[チケット番号] [チケットのタイトル]` とする(例: `refs bug #1234 キャッシュが落ちない`)。\ 15 | コミットのタイトルに関しては、プルリクに一つしかない場合はコミットタイトルを上記のプルリクエストのタイトル同じように`refs [チケットのトラッカー] #[チケット番号] [チケットのタイトル]` としても良い。(例: `refs bug #1234 キャッシュが落ちない`)。\ 16 | 複数のコミットがある場合はコミットタイトルはそのチケットでやるべきことのうち、何を対応したものか、を記載する必要があります。 17 | * 例: 18 | 1. プルリクエストのタイトル:`refs bug #1234 キャッシュが落ちない` 19 | 2. それに含まれるコミットのタイトルは下記のようになります。この場合は1プルリクエストに2コミットがあるとする。 20 | * `キャッシュをクリアするメソッドをモデルへ実装する` 21 | * `該当の controller のアクションでキャッシュをクリアするメソッドを呼ぶようにする` 22 | 23 | * 2018/03/28以前存在していた、1プルリクエストにつき1コミットというルールは廃止。ただ、10人以上が稼動する大きなプロジェクト等、マージされた各ブランチを確認しやすくしたいケースではSquash and mergeを推奨。 24 | * 2018/03/28以前存在していた、force pushは履歴を消すため非推奨。force pushをする際にはチームのコンセンサスを得てから行うこと。 25 | * ローカルの master ブランチでコードを変更してはいけない。必ず作業ブランチ上で行うこと。 26 | 27 | ### 準備 28 | 29 | 1. Github(Bitbucket)上で、セントラルリポジトリを自分のアカウントに Fork する(この節では、Fork によって作成されたリポジトリを Forkedリポジトリ と呼ぶ)。 30 | 31 | 2. Forkedリポジトリをローカルに clone する。このとき、Forkedリポジトリが `origin` という名前で自動的に登録される。 32 | ```sh 33 | $ git clone [ForkedリポジトリのURL] 34 | ``` 35 | 36 | 3. clone によって作成されたディレクトリに入り、セントラルリポジトリを `upstream` という名前で登録する。 37 | ```sh 38 | $ cd [作成されたディレクトリ] 39 | $ git remote add upstream [セントラルリポジトリのURL] 40 | ``` 41 | 42 | ### 開発 43 | 44 | 以降、セントラルリポジトリ を `upstream`、 Forkedリポジトリを `origin` と呼ぶ。 45 | 46 | 1. ローカルの master ブランチを upstream の master ブランチと同期する。 47 | ```sh 48 | $ git checkout master 49 | $ git pull upstream master 50 | ``` 51 | 52 | 2. ローカルで master ブランチから作業ブランチを作成する。ブランチ名はタスク番号(例: `task/1234`)などにする。 53 | ```sh 54 | $ git checkout master # <--- 既に master ブランチ上にいれば不要 55 | $ git checkout -b task/1234 56 | ``` 57 | 58 | 3. 作業する。自由に commit して良い。そのcommitの内容を示すcommit messageをちゃんと書く。 59 | 60 | 4. origin に push する。 61 | 62 | ```sh 63 | $ git push origin task/1234 64 | ``` 65 | 66 | 5. Github(Bitbucket)上で、origin に push済の `task/1234` ブランチから、upstream の `master` ブランチ に pull request を送る。 67 | 68 | 6. pull request の ページの URLをチャットワークに貼り、レビュワーにコードレビューを依頼する。 69 | 70 | 6.1. レビュワーから修正依頼を出されたら、3. 〜 5. の作業を行う。 71 | 72 | 6.2. 再度チャットワークに同じURLを貼り付け、レビューを依頼する。 73 | 74 | 7. 2人以上のレビュワーのOKが出たら、最後にOKを出したレビュワーがマージする。 75 | 8. 1に戻る。 76 | 77 | ### 1プルリクエストにつき1コミットの開発 78 | 79 | 以降、セントラルリポジトリ を `upstream`、 Forkedリポジトリを `origin` と呼ぶ。 80 | 81 | 1. ローカルの master ブランチを upstream の master ブランチと同期する。 82 | ```sh 83 | $ git checkout master 84 | $ git pull upstream master 85 | ``` 86 | 87 | 2. ローカルで master ブランチから作業ブランチを作成する。ブランチ名はタスク番号(例: `task/1234`)などにする。 88 | ```sh 89 | $ git checkout master # <--- 既に master ブランチ上にいれば不要 90 | $ git checkout -b task/1234 91 | ``` 92 | 93 | 3. 作業する(自由に commit して良い)。 94 | 95 | 4. 作業中に複数回 commit していたら、5.で push する前に rebase -i でコミットをひとつにまとめる。 96 | ```sh 97 | $ git rebase -i [作業内での最初のコミットよりひとつ前のハッシュ値] 98 | ``` 99 | 最初のコミットよりひとつ前のハッシュ値を指定するのは本質的な理由は 100 | master ブランチ以降のcommitを一つにまとめたいのでmasterと指定することで同様に実現できる。 101 | ```sh 102 | $ git rebase -i master 103 | ``` 104 | コミットのタイトルは `refs [チケットのトラッカー] #[チケット番号] [チケットのタイトル]` とする(例: `refs bug #1234 キャッシュが落ちない`)。 105 | 106 | 5. ローカルの master ブランチに移動し、このブランチを最新にする 107 | ```sh 108 | $ git checkout master 109 | $ git pull upstream master 110 | ``` 111 | 112 | 6. 作業ブランチに戻り、作業ブランチを master ブランチにリベースする。 113 | ```sh 114 | $ git checkout task/1234 115 | $ git rebase master 116 | ``` 117 | **リベース中にコンフリクトのエラーが発生した場合には、後述の「リベース中にコンフリクトが発生したとき」の手順を実行する。** 118 | 119 | 7. origin に push する。 120 | 121 | ```sh 122 | $ git push origin task/1234 123 | ``` 124 | 125 | 8. Github(Bitbucket)上で、origin に push済の `task/1234` ブランチから、upstream の `master` ブランチ に pull request を送る。 126 | 127 | 9. pull request の ページの URLをチャットワークに貼り、レビュワーにコードレビューを依頼する。 128 | 129 | 9.1. レビュワーから修正依頼を出されたら、3. 〜 6. の作業を行う。 130 | 131 | 9.2 同じリモートブランチに push -f (強制 push) する。 132 | ```sh 133 | $ git push origin task/1234 -f 134 | ``` 135 | 136 | 9.3 再度チャットワークに同じURLを貼り付け、レビューを依頼する。 137 | 138 | 10. 2人以上のレビュワーのOKが出たら、最後にOKを出したレビュワーがマージする。 139 | 11. 1に戻る。 140 | 141 | #### リベース中にコンフリクトが発生したとき 142 | 143 | リベース中にコンフリクトが発生すると、以下のように表示される(このとき、無名ブランチに自動的に移動している)。 144 | ```sh 145 | $ git rebase master 146 | First, rewinding head to replay your work on top of it... 147 | Applying: refs #1234 キャッシュが落ちない 148 | Using index info to reconstruct a base tree... 149 | Falling back to patching base and 3-way merge... 150 | Auto-merging path/to/conflicting/file 151 | CONFLICT (add/add): Merge conflict in path/to/conflicting/file 152 | Failed to merge in the changes. 153 | Patch failed at 0001 refs #1234 キャッシュが落ちない 154 | The copy of the patch that failed is found in: 155 | /path/to/working/dir/.git/rebase-apply/patch 156 | 157 | When you have resolved this problem, run "git rebase --continue". 158 | If you prefer to skip this patch, run "git rebase --skip" instead. 159 | To check out the original branch and stop rebasing, run "git rebase --abort". 160 | ``` 161 | 162 | 1. 手動ですべてのコンフリクト(コード中で <<< と >>> に囲まれている部分)を解消する。 163 | リベースを中止したいときには、`git rebase --abort` する。 164 | 165 | 2. すべてのコンフリクトを解消できたら、リベースを続行する。 166 | 167 | ```sh 168 | $ git add . 169 | $ git rebase --continue 170 | ``` 171 | -------------------------------------------------------------------------------- /ja/git/references.md: -------------------------------------------------------------------------------- 1 | ## git 利用規約(参考サイト) 2 | 3 | * [A successful Git branching model » nvie.com](http://nvie.com/posts/a-successful-git-branching-model/) 4 | -------------------------------------------------------------------------------- /ja/javascript/references.md: -------------------------------------------------------------------------------- 1 | ## Javascript コーデング規約(参考サイト) 2 | 3 | * [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) 4 | * [Google JavaScript Style Guide 和訳](http://cou929.nu/data/google_javascript_style_guide/) 5 | -------------------------------------------------------------------------------- /ja/javascript/standard.md: -------------------------------------------------------------------------------- 1 | # Javascript コーディング規約(標準スタイル編) 2 | 3 | ## 基本ルール 4 | ### コードレイアウト 5 | * インデントはホワイトスペース2個。 6 | * ハードタブは使用しない。 7 | * 1行の文字数は80文字以下にする。 8 | * 行末には空白を含めない。 9 | * カンマの直前にはスペースを挿入しない。 10 | * 演算子の前後、カンマの後ろにホワイトスペースを1個置く。 11 | * ()の内側にスペースを挿入しない。 12 | 13 | ### var 14 | 15 | * 変数は必ず `var` を付けて宣言する。 16 | 17 | **理由** 18 | 19 | `var` を付けないと、その変数はグローバル変数として扱われ、既に定義されている変数を上書きする危険性もある。また、もし宣言をしなければ、その変数のスコープがどの位広いのかが非常に分かりづらい。 20 | 21 | ### 定数 22 | 23 | * 定数は`NAME_LIKE_THIS`のような名前にする。 24 | * オーバーライドできない変数や属性を指定するために `@const` アノテーションを使う。 25 | * Internet Explorer がサポートしていない `const` キーワードは使ってはいけない。 26 | 27 | #### 定数値 28 | 29 | 変数を定数、または変更不可にする場合、`CONSTANT_VALUE_CASE.ALL_CAPS` のような名前にし、`@const` (値が上書き不可能であるという)アノテーションを使う。 30 | プリミティブ値(`number` 、`string`、`boolean`)は定数値である。 31 | `Object` が不変であるかどうかは、厳密に定義されていない。第三者が見て、状態変化が分からないのであれば、不変と言えるが、コンパイラーがこれを定義しているわけではない。 32 | 33 | ### セミコロン 34 | 35 | 行末には必ず付ける。 36 | 37 | 38 | ### 関数のネスト 39 | 40 | してもよい。 41 | 42 | ### ブロック内での関数宣言 43 | 44 | してはいけない。 45 | 46 | ### 例外の利用 47 | 48 | してもよい。 49 | 50 | ### 独自の例外の利用 51 | 52 | してもよい。 53 | 54 | ### 標準的に提供される機能 55 | 56 | 標準の機能で要件を満たせるのであれば、それを使う。 57 | 58 | ### プリミティブ型のラッパーオブジェクト 59 | 60 | 利用してはいけない。 61 | 62 | ### 階層型のプロトタイプ 63 | 64 | なるべく利用しない。 65 | 66 | ### メソッドとプロパティの定義 67 | 68 | ```javascript 69 | /** @constructor */ 70 | function SomeConstructor() { this.someProperty = 1; } 71 | Foo.prototype.someMethod = function() { ... }; 72 | ``` 73 | 74 | ### オブジェクトの削除 75 | 76 | ```null```を代入する。 77 | 78 | ```javascipt 79 | this.foo = null 80 | ``` 81 | 82 | ### クロージャー 83 | 84 | 利用しても良いが、慎重に検討する。 85 | 86 | ### ```eval()``` の利用 87 | 88 | デシリアライズする時のみ利用可。 89 | 90 | ### ```with(){}``` の利用 91 | 92 | 使ってはいけない。 93 | 94 | ### ```this``` の利用 95 | 96 | コンストラクター、メソッド、クロージャーの作成時にのみ利用して良い。 97 | 98 | ### ```for ... in``` のループ 99 | 100 | object / map / hash のキーを用いたイテレーションにのみ利用可能。 101 | 102 | ### 連想配列 103 | 104 | 配列を object / map / 連想配列として利用してはいけない。 105 | 106 | ### 複数行文字列 107 | 108 | 使ってはいけない。 109 | 110 | ### 配列・オブジェクトリテラルの利用 111 | 112 | しても良い。 113 | 114 | ### 組み込みオブジェクトのプロトタイプのオーバーライド 115 | 116 | 禁止。 117 | 118 | ### Internet Explorer 向けの条件コメント 119 | 120 | 使用禁止。 121 | 122 | ### 動的な DOM の構築 123 | 124 | Javascriptの関数内で DOM を新規に構築してはいけない。HTML 内に予め `display:none` 等にして DOM を構築しておき、それをコピーする等する。 125 | 126 | ## 文法 127 | 128 | ### 命名規則 129 | 130 | ### `toString()`メソッドの変更 131 | 132 | ### 遅延初期化 133 | 134 | してもよい。 135 | 136 | ### スコープの明示化 137 | 138 | 常にする。 139 | 140 | ### フォーマット 141 | 142 | このようにする。 143 | (これから書く) 144 | 145 | ### (括弧)の利用 146 | 147 | 必要とされるところのみに利用する。 148 | 149 | ### 文字列 150 | 151 | 使えるのであれば`"`ではなく`'`を使う。 152 | 153 | ### アクセス制限(private / protected) 154 | 155 | JSDoc アノテーション(`@private` と `@protected`)を使って記述する。 156 | 157 | ### 型 158 | 159 | コンパイラーで定義されるものを利用する。 160 | 161 | ### コメント 162 | 163 | JSDocで記載する 164 | 165 | ### goog.provide を利用した依存関係の管理 166 | 167 | トップレベルでのみ利用する 168 | 169 | ### コンパイル 170 | 171 | 利用する 172 | 173 | ### 小技集 174 | 175 | (あとで書く) 176 | -------------------------------------------------------------------------------- /ja/rails/gems.md: -------------------------------------------------------------------------------- 1 | # Ruby on Rails 標準 gem 一覧 2 | 3 | 最も大事なプログラミングの原則の1つに"Don't Repeat Yourself!"がある。もし、何か必要な作業に直面したら、それを自力で解決する前に何か解決方法が存在しないかを探すべきである。これは「とても価値のある」 gem の一覧で、多くの Rails プロジェクトで有意義なものだろう。全て Rails 3.1 で動作する。 4 | 5 | ## 管理画面作成 6 | 7 | * [active_admin](https://github.com/gregbell/active_admin) - 簡単に管理画面を作成できる。各モデルのCRUD処理も簡単に作成でき、カスタマイズも柔軟にできる。 8 | 9 | ## 開発環境、テスト環境改善 10 | 11 | **注意:これらは production に適用してはならない** 12 | 13 | * [capybara](https://github.com/jnicklas/capybara) - Capybara は Rails や Sinatra、 Merb といった Rack アプリケーションの統合テストを簡単にできるようにするものである。Webアプリケーションでの実際のユーザーの操作をシミュレーションする。現在ビルトインされた Rack::Test と Selenium をサポートしていて、テストを走らせるドライバーとして使える。HtmlUnit や Webkit、env.js も gem を導入することで利用可能になる。RSpec と Cucmber と共に用いると非常に有用である。 14 | 15 | * [better_errors](https://github.com/charliesome/better_errors) - 標準のエラーページを、より使いやすいものに差し替える。Rack ミドルウエアとして Rails 以外の Rack アプリケーションで利用できる。 16 | 17 | * [cucumber-rails](https://github.com/cucumber/cucumber-rails) - Ruby で結合テストを行うための非常に優れたツールである。cucumber-rails を導入すると Cucumber を Rails で利用できるようになる。 18 | 19 | * [factory_girl](https://github.com/thoughtbot/factory_girl) - テスト等のためのオブジェクト生成を助けてくれる。 20 | 21 | * [ffaker](https://github.com/EmmanuelOga/ffaker) - 簡単にダミーデータを作成してくれる。 22 | 23 | * [guard](https://github.com/guard/guard) - ファイルの変更を監視してタスクを自動実行することができる。様々な有用なツールに利用されている。 24 | 25 | * [spork](https://github.com/sporkrb/spork) - Rspec や Cucumber などのテストフレームワークのための DRb サーバーで、綺麗な状態でテストができるように準備してくれる。テストの実行環境を先読みすることで、テストの実行時間を大幅に削減してくれる。 26 | 27 | * [simplecov](https://github.com/colszowka/simplecov) - Ruby 1.9 で利用できるコードカバレッジツール。 28 | 29 | * [rspec-rails](https://github.com/rspec/rspec-rails) - Rails で RSpec を利用しやすくする。 30 | 31 | ## パフォーマンス改善 32 | 33 | * [bullet](https://github.com/flyerhzm/bullet) - 発行するクエリの数を減らすことでアプリケーションのパフォーマンスを向上するように設計されている。アプリケーションを監視して、先読み(N+1 queries)すべきところや、不要なのに先読みしているところ、カウンターキャッシュを利用すべきところを教えてくれる。 34 | 35 | ## ファイルアップロード 36 | 37 | * [Paperclip](https://github.com/thoughtbot/paperclip) - ActiveRecord にファイルを添付することができる。 38 | 39 | ## 全文検索 40 | 41 | * [sunspot](https://github.com/sunspot/sunspot) - SOLR を利用した全文検索システム。 42 | 43 | ## 権限管理 44 | 45 | * [cancan](https://github.com/ryanb/cancan) - ユーザーがリソースにアクセスすることを制限することができるようになる。全ての権限を一つのファイルで管理して、アプリケーション全体で認証を利用可能にする。 46 | 47 | * [devise](https://github.com/plataformatec/devise) - ほぼ全ての機能を備えた認証ソリューション。 48 | 49 | ## ビューテンプレート 50 | 51 | * [haml-rails](https://github.com/indirect/haml-rails) - Rails で HAML を利用できるようにする。 52 | 53 | * [haml](http://haml-lang.com) - HAML は ERB より圧倒的に優れているとみなされている簡潔なテンプレート言語である。 54 | 55 | * [slim](http://slim-lang.com) - Slim は ERB はもとより、HAML よりも優れていると言われるテンプレート言語である。Slim の使用をためらう理由があるとしたら、メジャーなエディターや IDE が十分にサポートしていない位である。また、パフォーマンスが著しく良い。 56 | 57 | ## クライアントサイドサポート 58 | 59 | * [client_side_validations](https://github.com/bcardarella/client_side_validations) - サーバーサイドに実装したモデルのバリデーションからクライアントサイドで動く Javascript のバリデーションを自動生成する。 60 | 61 | ## SEO対策 62 | 63 | * [friendly_id](https://github.com/norman/friendly_id) - モデルの id の代わりに人が理解しやすい、記述的な属性でオブジェクトを指定刷ることができる。 64 | 65 | ## ページネーション 66 | 67 | * [kaminari](https://github.com/amatsuda/kaminari) - 柔軟なページネーションが可能。 68 | 69 | ## 画像編集 70 | 71 | * [minimagick](https://github.com/probablycorey/mini_magick) - ImageMagick の Ruby ラッパー。 72 | 73 | ##(標準にするか未定) 74 | 75 | * [simplecov-rcov](https://github.com/fguillen/simplecov-rcov) - RCov formatter 76 | for SimpleCov. Useful if you're trying to use SimpleCov with the Hudson 77 | contininous integration server. 78 | 79 | * [carrierwave](https://github.com/jnicklas/carrierwave) - the ultimate file 80 | upload solution for Rails. Support both local and cloud storage for the 81 | uploaded files (and many other cool things). Integrates great with 82 | ImageMagick for image post-processing. 83 | 84 | * [compass-rails](https://github.com/chriseppstein/compass) - Great gem that 85 | adds support for some css frameworks. Includes collection of sass mixins that 86 | reduces code of css files and help fight with browser incompatibilities. 87 | 88 | * [fabrication](http://fabricationgem.org/) - a great fixture replacement 89 | (editor's choice). 90 | 91 | * [feedzirra](https://github.com/pauldix/feedzirra) - Very fast and flexible 92 | RSS/Atom feed parser. 93 | 94 | * [globalize3](https://github.com/svenfuchs/globalize3.git) - Globalize3 is 95 | the successor of Globalize for Rails and is targeted at ActiveRecord 96 | version 3.x. It is compatible with and builds on the new I18n API in Ruby 97 | on Rails and adds model translations to ActiveRecord. 98 | 99 | * [machinist](https://github.com/notahat/machinist) - Fixtures aren't fun. 100 | Machinist is. 101 | 102 | * [simple_form](https://github.com/plataformatec/simple_form) - once you've 103 | used simple_form (or formtastic) you'll never want to hear about Rails's 104 | default forms. It has a great DSL for building forms and no opinion on 105 | markup. 106 | 107 | * [email-spec](https://github.com/bmabey/email-spec) - RSpec や Cucumber で email のテストを行いやすくする。 108 | 109 | ## 非推奨 gem 110 | 111 | これらの gem は問題を抱えているか、他に優れた代替 gem があるものである。これらの gem の使用は避けるべきである。 112 | 113 | * [rmagick](http://rmagick.rubyforge.org/) - メモリーを無駄に使うので利用すべきでない。代わりに minimagick を利用すべきである。 114 | 115 | * [autotest](http://www.zenspider.com/ZSS/Products/ZenTest/) - 自動テストツール。さらに優れている guard を利用すべきである。 116 | 117 | * [rcov](https://github.com/relevance/rcov) - Ruby 1.9 に対応していない。simplecov を利用すべき。 118 | 119 | * [therubyracer](https://github.com/cowboyd/therubyracer) - メモリーを非常に多く使うので利用すべきではない。Node.js をインストールすべきである。 120 | -------------------------------------------------------------------------------- /ja/rails/references.md: -------------------------------------------------------------------------------- 1 | ## Ruby on Rails コーデング規約(参考サイト) 2 | 3 | * [Ruby on Rails Guides](http://guides.rubyonrails.org/contributing_to_ruby_on_rails.html#follow-the-coding-conventions) 4 | * [bbatsov / rails-style-guide](https://github.com/bbatsov/rails-style-guide) 5 | * [コーディング規約をまとめてみた (Rails編) | bojovs.com](http://bojovs.com/2012/10/16/rails-coding-style) 6 | -------------------------------------------------------------------------------- /ja/rails/standard.md: -------------------------------------------------------------------------------- 1 | # Ruby on Rails コーデング規約(標準スタイル編) 2 | 3 | ## 設定 4 | 5 | * アプリケーション固有の設定は ``` config/initializers ``` に置く。ここに置いたcodeはアプリケーションが起動するときに実行される。 6 | 7 | * 初期化のcodeは``` carierwave.rb ``` や ``` active_admin.rb ``` のようにgemごとにgemと同じ名前でファイルを作成する。 8 | 9 | * development、test、productionで環境ごとに異なるものは``` config/environments ``` にファイルを切り出す等して調整する。 10 | 11 | * 全ての環境で有効にするものは ``` config/application.rb ``` に記載する。 12 | 13 | * stagingのような新しい環境を作成した場合は、なるべく production と近づけるようにする。 14 | 15 | ## ルーティング 16 | 17 | * RESTfulなリソースにactionを追加する必要があるときは、``` member ``` と ``` collection ``` を使う。 18 | 19 | ```ruby 20 | # bad 21 | get 'subscriptions/:id/unsubscribe' 22 | resources :subscriptions 23 | 24 | # good 25 | resources :subscriptions do 26 | get 'unsubscribe', on: :member 27 | end 28 | 29 | # bad 30 | get 'photos/search' 31 | resources :photos 32 | 33 | # good 34 | resources :photos do 35 | get 'search', on: :collection 36 | end 37 | ``` 38 | 39 | * 複数の ``` member/collection ``` がある時はblockで記述する。 40 | 41 | ```ruby 42 | resources :subscriptions do 43 | member do 44 | get 'unsubscribe' 45 | get 'subscribe' 46 | end 47 | end 48 | 49 | resources :photos do 50 | collection do 51 | get 'search' 52 | get 'trashes' 53 | end 54 | end 55 | ``` 56 | 57 | * ActiveRecord のモデルの relation を表現するために nested routesを利用する。 58 | 59 | ```ruby 60 | class Post < ActiveRecord::Base 61 | has_many :comments 62 | end 63 | 64 | class Comments < ActiveRecord::Base 65 | belongs_to :post 66 | end 67 | 68 | # routes.rb 69 | resources :posts do 70 | resources :comments 71 | end 72 | ``` 73 | 74 | * 関係するactionをグループ化するために、namespace を利用する。 75 | 76 | ```ruby 77 | namespace :admin do 78 | # Directs /admin/products/* to Admin::ProductsController 79 | # (app/controllers/admin/products_controller.rb) 80 | resources :products 81 | end 82 | ``` 83 | 84 | * 旧型のwild controller route は使ってはいけない。 85 | 86 | **理由** 87 | 88 | この書き方をすると全ての controller の action が GET リクエストでアクセスできてしまうため。 89 | 90 | ```ruby 91 | # very bad 92 | match ':controller(/:action(/:id(.:format)))' 93 | ``` 94 | 95 | ## コントローラー 96 | 97 | * コントローラーはギリギリまで中身を削ること。view が必要とするデータの取得のみを行うべきで、決してビジネスロジックを記載してはいけない。(それはモデルで行うべきである) 98 | 99 | * コントローラーの action はそれぞれ、モデルを初期化したり検索する他は1メソッドのみを実行する位が理想的である。 100 | 101 | * 2個以上のインスタンス変数をコントローラーとviewの間で共有してはいけない。 102 | 103 | * コントローラにおけるメインのリソースを示すインスタンス変数には、そのリソースのオブジェクトをアサインすること。例えば、ArticlesController内の `@article` には `Article` クラスのインスタンスをアサインする。 `@articles` には、そのコレクションをアサインする。 104 | 105 | ```ruby 106 | # bad 107 | class ArticlesController < ApplicationController 108 | def index 109 | @articles = Article.all.pluck [:id, :title] 110 | end 111 | 112 | def show 113 | @article = "This is an article." 114 | end 115 | end 116 | 117 | # good 118 | class ArticlesController < ApplicationController 119 | def index 120 | @articles = Article.all 121 | end 122 | 123 | def show 124 | @article = Article.find params[:id] 125 | end 126 | end 127 | ``` 128 | 129 | * モデル等が発生させた Exception はコントローラーが必ず処理をする。コントローラーは Exception を受け取ったらステータスコード 400 以上をクライアントに通知することで、 Exception の発生を通知しなければならない。 130 | 131 | * render の引数は シンボルとする。 132 | 133 | ```ruby 134 | render :new 135 | ``` 136 | 137 | * 処理を行わず、View を表示するだけのアクションも省略しない。 138 | 139 | ```ruby 140 | class HomeController < ApplicationController 141 | 142 | def index 143 | end 144 | 145 | end 146 | ``` 147 | 148 | * GET 以外の HTTP メソッドでアクセスされる action は必ず、処理完了後、 GET メソッドでアクセスされる action へリダイレクトさせる。ただし、直接人がアクセスするものではない、 json を返却する API のようなものはその必要はない。 149 | 150 | **理由** 151 | 152 | ユーザーのリフレッシュ操作による多重処理を防止するため。 153 | 154 | * コールバックの記述には、メソッド名か ```lambda``` を使うこと。ここにブロックを使ってはいけない。 155 | 156 | ```ruby 157 | # bad 158 | 159 | before_action{@users = User.all} # brock 160 | 161 | # good 162 | 163 | before_action :methodname # method name 164 | 165 | # also good 166 | 167 | before_action ->{@users = User.all} # lambda 168 | ``` 169 | 170 | ## モデル 171 | 172 | * ActiveRecord 以外のモデルも自由に利用して良い。 173 | 174 | * 短縮や省略を用いることなく、分かり易く、でも短い名前を付けるようにする。 175 | 176 | * validation など ActiveRecord の振る舞いをモデルに持たせる必要があるとき、[ActiveAttr](https://github.com/cgriego/active_attr) gem を利用する。 177 | 178 | ```ruby 179 | class Message 180 | include ActiveAttr::Model 181 | 182 | attribute :name 183 | attribute :email 184 | attribute :content 185 | attribute :priority 186 | 187 | attr_accessible :name, :email, :content 188 | 189 | validates_presence_of :name 190 | validates_format_of :email, :with => /\A[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}\z/i 191 | validates_length_of :content, :maximum => 500 192 | end 193 | ``` 194 | 195 | ### ActiveRecord 196 | 197 | * 既存のデータベースを利用しなければならない、等の正当な理由が無い場合はテーブル名やプライマリーキー等、ActiveRecordのデフォルトを変更してはいけない。 198 | 199 | ```ruby 200 | # bad - don't do this if you can modify the schema 201 | class Transaction < ActiveRecord::Base 202 | @table_name = :order 203 | ... 204 | end 205 | ``` 206 | 207 | * どうしても必要で ``` primary_key ``` や ``` table_name ``` を明示的に指定するときは、クラス変数を直接書き換える。これらの定義はマクロメソッドの前に記述する。 208 | 209 | ```ruby 210 | class Transaction < ActiveRecord::Base 211 | @primary_key= :order_id 212 | @table_name = :order 213 | ... 214 | end 215 | ``` 216 | 217 | **理由** 218 | クラスのプロパティを書き換えていることを明示的に示すため。本来行うべきでない処理を行っていることを明示的に示すため。 219 | 220 | * マクロメソッドはまとめてクラス定義の初期に書く。同種のマクロメソッド( belongs_to と has_many 等)や同じマクロメソッドで種々の引数を持つものの引数( validates 等)は辞書順に並べる。callback は時系列に並べる。 221 | 222 | * マクロメソッド等の記述順は、 223 | * 定数 224 | * attr_ 系メソッド 225 | * 関連 226 | * バリデーション 227 | * callback 228 | * その他 229 | 230 | の順に記載する。 231 | 232 | #### Scope 233 | * scope の命名には、レコードデータの集合に対する子集合を表す名前を付ける。 234 | * `[モデル名の複数形] which are [scope名]` として自然言語として読めるようにする。 235 | * 引数がある場合にも、引数を含めて自然言語のように読めるようにする。 236 | * モデルを表す単語(Userモデルのスコープだったら "user")をできるだけ含まないようにする。 237 | 238 | ```ruby 239 | # bad 240 | class User < ActiveRecord::Base 241 | scope :active_users, ->{where activated: true} 242 | end 243 | class Post < ActiveRecord::Base 244 | scope :by_author, ->author{where author_id: author.id} 245 | end 246 | 247 | # good 248 | class User < ActiveRecord::Base 249 | scope :active, ->{where activated: true} 250 | end 251 | class Post < ActiveRecord::Base 252 | scope :posted_by, ->author{where author_id: author.id} 253 | end 254 | ``` 255 | 256 | * scope は lambda の省略記法で記述する。この場合も1行の長さが80文字以上になる場合は適宜改行する等して、80文字以内に納めるようにする。 257 | 258 | ```ruby 259 | class User < ActiveRecord::Base 260 | # constants come up next 261 | GENDERS = %w(male female) 262 | 263 | # afterwards we put attr related macros 264 | attr_accessor :formatted_date_of_birth 265 | 266 | attr_accessible :login, :first_name, :last_name, :email, :password 267 | 268 | # followed by association macros 269 | belongs_to :country 270 | 271 | has_many :authentications, dependent: :destroy 272 | 273 | # and validation macros 274 | validates :email, presence: true 275 | validates :password, format: {with: /\A\S{8,128}\z/, allow_nil: true} 276 | validates :username, format: {with: /\A[A-Za-z][A-Za-z0-9._-]{2,19}\z/} 277 | validates :username, presence: true 278 | validates :username, uniqueness: {case_sensitive: false} 279 | # email -> password -> username, format -> presence -> uniqueness 280 | 281 | # next we have callbacks, callbaks should be sorted by chronological order: before -> after 282 | before_save :cook 283 | before_save :update_username_lower 284 | 285 | after_save :serve 286 | 287 | # scopes 288 | scope :active, ->{where(active: true)} 289 | 290 | # other macros (like devise's) should be placed after the callbacks 291 | 292 | ... 293 | end 294 | ``` 295 | 296 | * ``` default_scope ``` は論理削除状態を表現する以外の目的で使ってはならない。また、その時も ``` order ``` を使ってはいけない。 297 | 298 | * `has_many` または `has_one` で指定されたモデルは必ず相手を `belongs_to` で指定する。 299 | 300 | 301 | ## ActiveResource 302 | 303 | * XML や JSON (もちろん HTML も)以外の既存のフォーマット以外のレスポンスを返す必要があるときは、下記のように独自のカスタムフォーマットを作成して利用する。カスタムフォーマットを実装するには、``` extension ```、``` mime_type ```、``` encode ```、``` decode ``` の4つのメソッドを定義する必要がある。 304 | 305 | ```ruby 306 | module ActiveResource 307 | module Formats 308 | module Extend 309 | module CSVFormat 310 | extend self 311 | 312 | def extension 313 | "csv" 314 | end 315 | 316 | def mime_type 317 | "text/csv" 318 | end 319 | 320 | def encode(hash, options = nil) 321 | # Encode the data in the new format and return it 322 | end 323 | 324 | def decode(csv) 325 | # Decode the data from the new format and return it 326 | end 327 | end 328 | end 329 | end 330 | end 331 | 332 | class User < ActiveResource::Base 333 | self.format = ActiveResource::Formats::Extend::CSVFormat 334 | 335 | ... 336 | end 337 | ``` 338 | 339 | * もしリクエストが拡張子無しで送られるようにするのであれば、``` ActiveResource::Base ``` の ``` element_path ``` と ``` collection_path ``` の2つのメソッドをオーバーライドして、extension の部分を削除すれば良い。 340 | 341 | ```ruby 342 | class User < ActiveResource::Base 343 | ... 344 | 345 | def self.collection_path(prefix_options = {}, query_options = nil) 346 | prefix_options, query_options = split_options(prefix_options) if query_options.nil? 347 | "#{prefix(prefix_options)}#{collection_name}#{query_string(query_options)}" 348 | end 349 | 350 | def self.element_path(id, prefix_options = {}, query_options = nil) 351 | prefix_options, query_options = split_options(prefix_options) if query_options.nil? 352 | "#{prefix(prefix_options)}#{collection_name}/#{URI.parser.escape id.to_s}#{query_string(query_options)}" 353 | end 354 | end 355 | ``` 356 | 357 | ## マイグレーション 358 | 359 | ======= 360 | * ``` schema.rb ``` (または ``` structure.sql ```)はバージョン管理する 361 | 362 | * テスト用のデータベースを作成するために ``` rake db:test:prepare ``` を用いること 363 | 364 | * デフォルト値を設定する必要があるならば、アプリケーションレイヤーではなくマイグレーションで対応すること。 365 | 366 | ```ruby 367 | # bad - application enforced default value 368 | def amount 369 | self[:amount] or 0 370 | end 371 | ``` 372 | 373 | Rails 内でのみテーブルのデフォルト値を強制するのは、とても脆弱なアプローチで、アプリケーションのバグを引き起こし兼ねないと多くの開発者に指摘されている。また、非常に小さいアプリケーション以外の殆どはデータベースを他のアプリケーションと共有しており、 Rails アプリケーションからだけにデータ整合性を負わせるのは不可能である、という事実を頭に入れておく必要がある。 374 | 375 | * 外部キー制約を強制すること。ActiveRecordは素の状態ではそれをサポートしていないが、[schema_plus](https://github.com/lomba/schema_plus)のような優れたサードパーティ製のgemがある。 376 | 377 | * テーブルやカラムを追加するよな、構成を変更する処理の記述には Rails 3.1 記法を用いること。つまり、``` up ``` や ``` down ``` メソッドではなく、``` change ``` メソッドを使うこと。 378 | 379 | ```ruby 380 | # the old way 381 | class AddNameToPerson < ActiveRecord::Migration 382 | def up 383 | add_column :persons, :name, :string 384 | end 385 | 386 | def down 387 | remove_column :person, :name 388 | end 389 | end 390 | 391 | # the new prefered way 392 | class AddNameToPerson < ActiveRecord::Migration 393 | def change 394 | add_column :persons, :name, :string 395 | end 396 | end 397 | ``` 398 | 399 | * モデルのクラスをマイグレーション内で使ってはいけない。モデルのクラスは常に進化するので、モデルを使っている箇所の変更により、将来のある時点でマイグレーション処理が止まってしまう可能性がある。 400 | 401 | ## ビュー 402 | 403 | * ビューの中でモデルを直接呼んではいけない。コントローラーにインスタンス化させるか、ヘルパー内で利用する。 404 | 405 | * select タグなどのためのマスターとして View の中でモデルを直接呼ぶのは例外的に許可することとする。 406 | 407 | * ビュー内で複雑な処理を記載しない。複雑な処理が必要であればビューヘルパーに切り出すか、モデル内で処理させる。 408 | 409 | * 同じコードを記述することを避けるために、パーシャルやレイアウトを利用する。 410 | 411 | * form は helper を用いて記述しなければならない。リンクや外部ファイルの読み込み等、ロジックや設定が含まれるものの記述も helper を使う。 412 | 413 | * form_for が利用できる時は form_tag を用いてはいけない。 414 | 415 | * ``` <% ``` 、 ``` <%= ``` と ``` %> ``` の内側にホワイトスペースを1つ入れる。 416 | 417 | ```ruby 418 | # bad 419 | <%foo%> 420 | <% bar%> 421 | <%=bar%> 422 | <%=bar %> 423 | 424 | # good 425 | <% foo %> 426 | <%= bar %> 427 | ``` 428 | 429 | 430 | * [client side validation](https://github.com/bcardarella/client_side_validations)の利用を検討する。使い方は下記のとおり。 431 | * ``` ClientSideValidations::Middleware::Base ``` を継承したカスタムバリデーターを宣言する。 432 | 433 | ```ruby 434 | module ClientSideValidations::Middleware 435 | class Email < Base 436 | def response 437 | if request.params[:email] =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i 438 | self.status = 200 439 | else 440 | self.status = 404 441 | end 442 | super 443 | end 444 | end 445 | end 446 | ``` 447 | 448 | * ``` public/javascripts/rails.validations.custom.js.coffee ``` ファイルを作成して、``` application.js.coffee ``` ファイルに参照を追加する。 449 | 450 | ```coffee 451 | # app/assets/javascripts/application.js.coffee 452 | #= require rails.validations.custom 453 | ``` 454 | 455 | * クライアント側のバリデーターを追加する。 456 | 457 | ```coffee 458 | #public/javascripts/rails.validations.custom.js.coffee 459 | clientSideValidations.validators.remote['email'] = (element, options) -> 460 | if $.ajax({ 461 | url: '/validators/email.json', 462 | data: { email: element.val() }, 463 | async: false 464 | }).status == 404 465 | return options.message || 'invalid e-mail format' 466 | ``` 467 | 468 | ## 国際化 469 | 470 | * モデル、ビュー、コントローラーいずれの中でも特定の言語や国に依存した設定を含めてはいけない。それらの文章等は ``` config/locales ``` ディレクトリ内のロケールファイルに記述すること。 471 | 472 | * ActiveRecord モデルのラベルを翻訳する必要があるときは、 ``` activerecord ``` スコープに記載する。 473 | 474 | ```yaml 475 | ja: 476 | activerecord: 477 | models: 478 | user: メンバー 479 | attributes: 480 | user: 481 | name: 姓名 482 | ``` 483 | 484 | その時、``` User.model_name.human ``` は"メンバー"と返し、``` User.human_attribute_name("name") ``` は"姓名"と返す。このような翻訳はビューの中でも使うことができる。 485 | 486 | * ActiveRecord の属性を翻訳したものと、ビューの中で使われるものとはファイルを分ける。モデルに利用するファイルは ``` models ``` フォルダーにおいて、ビューに利用するものは ``` views ``` フォルダーに保存する。 487 | * ファイルを追加したらロケールファイルが読み込まれるディレクトリを ``` application.rb ``` に追加する。 488 | 489 | ```ruby 490 | # config/application.rb 491 | config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s] 492 | ``` 493 | 494 | * 日付や通貨のフォーマットのように共通で使うものは ``` locales ``` ディレクトリ直下に保存する。 495 | 496 | * 短縮表記のメソッドを使うようにする。 ``` I18n.t ``` を ``` I18n.translate ``` の代わりに使い、``` I18n.l ``` を ``` I18n.localize ``` の代わりに使う。 497 | 498 | * ビューの中では Lazy lookup を使う。このような構造のとき、 499 | ```yaml 500 | ja: 501 | users: 502 | show: 503 | title: "ユーザー情報" 504 | ``` 505 | ``` users.show.title ``` は ``` app/views/users/show.html.haml ``` 内では 506 | ```ruby 507 | = t '.title' 508 | ``` 509 | で取得できる。 510 | 511 | * コントローラーやモデルの中では ``` :scope ``` 指定では無く、ドット区切りのキーで値を取得する。ドット区切りの方が簡単に呼べ、階層を追いやすい。 512 | 513 | ```ruby 514 | # use this call 515 | I18n.t 'activerecord.errors.messages.record_invalid' 516 | 517 | # instead of this 518 | I18n.t :record_invalid, :scope => [:activerecord, :errors, :messages] 519 | ``` 520 | 521 | * 詳細は [RailsGuide](http://guides.rubyonrails.org/i18n.html)に従う。 522 | 523 | ## アセット 524 | 525 | asset pipeline を利用する 526 | 527 | * アプリケーション固有のスタイルシートやJavascript、画像等は ``` app/assets ``` へ入れる。 528 | 529 | * ``` lib/assets ``` はライブラリ的なファイルを入れる。ライブラリでも、アプリケーション固有に調整したものは入れない。 530 | 531 | * jQuery や bootstrap のようなサードパーティ製品は ``` vendor/asstes ``` に保存する。 532 | 533 | * 可能であれば、gem 化されたアセットを利用する。(例:[jquery-rails](https://github.com/rails/jquery-rails))。 534 | 535 | * CSS の中に url を記載するときは asset_url を使うこと。 536 | 537 | ## メイラー 538 | 539 | * メイラーは ``` SomethingMailer ``` のような名前にする。Mailerという接尾語を外せば、それがどのようなメールを送ってどのviewが関連するのかが一目瞭然なようにする。 540 | 541 | * HTML とプレインテキストの両方のテンプレートを用意する。 542 | 543 | * development 環境ではメール送信に失敗したときにエラーが起こるようにする。デフォルトでは無効になっているので気をつけること。 544 | 545 | ```ruby 546 | # config/environments/development.rb 547 | config.action_mailer.raise_delivery_errors = true 548 | ``` 549 | 550 | * host オプションは必ず設定する。 551 | 552 | ```ruby 553 | # config/environments/development.rb 554 | config.action_mailer.default_url_options = {host: "localhost:3000"} 555 | 556 | # config/environments/production.rb 557 | config.action_mailer.default_url_options = {host: 'your_site.com'} 558 | 559 | # in your mailer class 560 | default_url_options[:host] = 'your_site.com' 561 | ``` 562 | 563 | * メールの中でサイトへリンクさせる時には、``` _path ``` ではなく ``` _url ``` メソッドを利用する。``` _url ``` メソッドはホスト名を含み、``` _path ``` は含まないからである。 564 | 565 | ```ruby 566 | # wrong 567 | You can always find more info about this course 568 | = link_to 'here', url_for(course_path(@course)) 569 | 570 | # right 571 | You can always find more info about this course 572 | = link_to 'here', url_for(course_url(@course)) 573 | ``` 574 | 575 | * From と To アドレスは正しく設定する。下記の形式を利用すること。 576 | 577 | ```ruby 578 | # in your mailer class 579 | default from: 'Your Name ' 580 | ``` 581 | 582 | * テスト環境ではメール送信メソッドに ``` test ``` を忘れずに設定すること。 583 | 584 | ```ruby 585 | # config/environments/test.rb 586 | config.action_mailer.delivery_method = :test 587 | ``` 588 | 589 | * development 環境や production 環境等では送信メソッドを ``` smtp ```にする。 590 | 591 | ```ruby 592 | # config/environments/development.rb, config/environments/production.rb 593 | config.action_mailer.delivery_method = :smtp 594 | ``` 595 | 596 | * 外部CSSで問題が起きるメールクライアントがあるので、HTML メールを送る時は全てのstyleをインラインで指定する。しかしながら、そうするとメンテナンスしづらく、コードの重複が置きやすくなる。この問題は[premailer-rails3](https://github.com/fphilipe/premailer-rails3)や[roadie](https://github.com/Mange/roadie)がサポートしてくれる。 597 | 598 | * ページを作成している途中でメールを送るのは避けるべきである。それはページ読み込みの遅延や複数のメールを送った時には、リクエストタイムアウトの原因になることがある。これらの問題を解決するために、[delayed_job](https://github.com/tobi/delayed_job)を使うと良い。 599 | 600 | ## バンドラー 601 | 602 | * Gemfile には ruby バージョンを記載すること。 603 | 604 | ```ruby 605 | ruby "2.1.5" 606 | ``` 607 | 608 | * development 環境や test 環境でのみ利用する gem は適切なグループを設定して記述する。 609 | 610 | * 本当に必要な gem のみを利用する。あまり有名でない gem を利用する時は、最初に細心の注意を払ってレビューを行うべきである。 611 | 612 | * OS 固有の gem は稼働させる OS が異なる度に Gemfile.lock を書き換えるため、OS X 固有の gem は ``` darwin ``` グループに、Linux 固有の gem は ``` linux ``` グループに記載する。 613 | 614 | ```ruby 615 | # Gemfile 616 | group :darwin do 617 | gem "rb-fsevent" 618 | gem "growl" 619 | end 620 | 621 | group :linux do 622 | gem "rb-inotify" 623 | end 624 | ``` 625 | 626 | 適切な gem が正しい環境で読み込まれるように、``` config/application.rb ``` に下記のように記述する。 627 | 628 | ```ruby 629 | platform = RUBY_PLATFORM.match(/(linux|darwin)/)[0].to_sym 630 | Bundler.require(platform) 631 | ``` 632 | 633 | * バージョン管理システムから ``` Gemfile.lock ``` を削除してはいけない。これは確率論的に変更されるファイルではなく、どのチームメンバーが ``` bundle install ``` しても全ての gem のバージョンが揃うために必要である。 634 | -------------------------------------------------------------------------------- /ja/rails/test.md: -------------------------------------------------------------------------------- 1 | # Ruby on Rails コーデング規約(テスト編) 2 | 3 | 新しい機能を実装するための一番良い方法はおそらく BDD であろう。一般に Cucumber が使われる、高水準の機能テストを書くことから始めて、機能実装をこのテストによって制御するのである。最初に機能に関するビューの仕様を書いて、それを元に関連するビューを実装する。その後にビューにデータを渡すコントローラーの仕様を作り、それを使ってコントローラーを実装する。最後にモデルの仕様を書いて、モデル自体を実装する、というように。 4 | 5 | ## Cucumber 6 | 7 | * ペンディングしたシナリオは `@wip` (work in progress) タグを打っておくこと。そのシナリオは数に数えられず、失敗とも見なされない。ペンディングしたシナリオでテストしたいフィーチャーを実装して動かす時に、このシナリオがテストスイートに組み込まれるよう、 `@wip` タグを削除する。 8 | 9 | * ` @javascript ` とタグ打ちされたシナリオが除外されるようにデフォルトプロファイルを設定しておくと良い。それらはブラウザーを使ってテストするもので、それを無効にすることで一般シナリオの実行速度を上げることが推奨されている。 10 | 11 | * ` @javascript ` タグが付けられたシナリオのために個別のプロファイルを用意すると良い。 12 | * プロファイルは ` cucmber.yml ` ファイルで定義できる。 13 | 14 | ```Ruby 15 | # definition of a profile: 16 | profile_name: --tags @tag_name 17 | ``` 18 | 19 | * プロファイルはこのようなコマンドを与えることで実行できる: 20 | 21 | ``` 22 | cucumber -p profile_name 23 | ``` 24 | 25 | * link、button 等の文字を表示している要素があるかを確認するときは、エレメント ID ではなく文言を確認すること。そうすると i18n を利用しているときの問題を発見することができる。 26 | 27 | * ある種類のオブジェクトにおいて、異なる機能であれば、フィーチャーを分けて作成する: 28 | 29 | ```Ruby 30 | # bad 31 | Feature: Articles 32 | # ... feature implementation ... 33 | 34 | # good 35 | Feature: Article Editing 36 | # ... feature implementation ... 37 | 38 | Feature: Article Publishing 39 | # ... feature implementation ... 40 | 41 | Feature: Article Search 42 | # ... feature implementation ... 43 | 44 | ``` 45 | 46 | * それぞれのフィーチャーは3つの主要な要素を持つ 47 | * タイトル 48 | * 文言 - このフィーチャーがどのようなものかの簡単な説明 49 | * 適合基準 - ステップの集合である、シナリオをさらに纏めたもの 50 | 51 | * Connextra フォーマットが最も良く使われる。 52 | 53 | ```Ruby 54 | In order to [benefit] ... 55 | A [stakeholder]... 56 | Wants to [feature] ... 57 | ``` 58 | 59 | このフォーマットは最も良く使われているが、必須ではなく、文言はフィーチャーの複雑さによって自由に表現すればよい。 60 | 61 | * シナリオを DRY に保つためにしなりとアウトラインを使うと良い。 62 | 63 | ```Ruby 64 | Scenario Outline: User cannot register with invalid e-mail 65 | When I try to register with an email "" 66 | Then I should see the error message "" 67 | 68 | Examples: 69 | |email |error | 70 | | |The e-mail is required| 71 | |invalid email |is not a valid e-mail | 72 | ``` 73 | 74 | * シナリオのステップは `step_definitions` ディレクトリ下の ` .rb ` ファイルに記述する。名前の規約は `[description]_steps.rb` とする。ステップは基準を作って別々のファイルに振り分けるようにする。`home_page_steps.rb` のように、それぞれのフィーチャーごとに1つのファイルに分けても良いし、 `articles_steps.rb` のように特定の対象に対して、全てのフィーチャーを1つのファイルに分けても良い。 75 | 76 | * 繰り返しを避けるために、複数行にまとめた引数を用意する。 77 | 78 | ```Ruby 79 | Scenario: User profile 80 | Given I am logged in as a user "John Doe" with an e-mail "user@test.com" 81 | When I go to my profile 82 | Then I should see the following information: 83 | |First name|John | 84 | |Last name |Doe | 85 | |E-mail |user@test.com| 86 | 87 | # the step: 88 | Then /^I should see the following information:$/ do |table| 89 | table.raw.each do |field, value| 90 | find_field(field).value.should =~ /#{value}/ 91 | end 92 | end 93 | ``` 94 | 95 | * シナリオを DRY に保つために、複数のステップを纏めて使うようにする。 96 | 97 | ```Ruby 98 | # ... 99 | When I subscribe for news from the category "Technical News" 100 | # ... 101 | 102 | # the step: 103 | When /^I subscribe for news from the category "([^"]*)"$/ do |category| 104 | steps %Q{ 105 | When I go to the news categories page 106 | And I select the category #{category} 107 | And I click the button "Subscribe for this category" 108 | And I confirm the subscription 109 | } 110 | end 111 | ``` 112 | * Capybara のマッチャーは ``` should_not ``` を肯定で使うのでは無く、否定のマッチャーを利用すること。そうすることで ajax のアクションで設定したタイムアウトの間、再試行するようになる。 113 | [Capybara の README に、より詳しい説明がある。](https://github.com/jnicklas/capybara) 114 | 115 | ## RSpec 116 | 117 | * 1つの example に期待結果を1つだけ書く。 118 | 119 | ```ruby 120 | # bad 121 | describe ArticlesController do 122 | describe "GET new" do 123 | before {get :new} 124 | it do 125 | assigns[:article].is_expected.to be_a_new Article 126 | response.is_expected.to render_template :new 127 | end 128 | end 129 | end 130 | 131 | # good 132 | describe ArticlesController do 133 | describe "GET new" do 134 | before {get :new} 135 | subject {response} 136 | it {is_expected.to render_template :new} 137 | end 138 | end 139 | ``` 140 | 141 | * `describe` と `context` は必要に応じて自由に使ってよい 142 | * `describe` はクラス、モジュール、メソッド(コントローラーのアクション等)ごとにグルーピングするのに使う。ビュー等の場合はこの規則に従わない。 143 | * `context` は example の条件をグルーピングするのに使う。 144 | 145 | * `describe` のブロック名は下記のようにする 146 | * メソッド以外は説明を記載する 147 | * インスタンスメソッドの場合は "#method" のように "#" を使う 148 | * クラスメソッドの場合は ".method" のように "." を使う 149 | 150 | ```ruby 151 | class Article 152 | def summary 153 | #... 154 | end 155 | 156 | def self.latest 157 | #... 158 | end 159 | end 160 | 161 | # the spec... 162 | describe Article do 163 | describe "#summary" do 164 | #... 165 | end 166 | 167 | describe ".latest" do 168 | #... 169 | end 170 | end 171 | ``` 172 | 173 | * テスト用のオブジェクトを作成するときには [factory_girl](https://github.com/thoughtbot/factory_girl) を使う。 174 | * モックやスタブは必要に応じて利用する 175 | * モデルのモックを作るときには、`as_null_object` メソッドを使う。それを使うことで、期待するメッセージだけを出力することができ、他の全てのメッセージを無視することができる。 176 | 177 | ```ruby 178 | # mocking a model 179 | article = mock_model(Article).as_null_object 180 | 181 | # stubbing a method 182 | Article.stub(:find).with(article.id).and_return(article) 183 | ``` 184 | 185 | * example でデータを作成するときには、遅延評価にするために、`let` を使う。`let`の代わりにインスタンス変数を使うのは禁止とする。 186 | 187 | ```ruby 188 | # use this: 189 | let(:article) {FactoryGirl.create :article} 190 | 191 | # ... instead of this: 192 | before(:each) {@article = FactoryGirl.create :article} 193 | ``` 194 | 195 | * `expect` または `is_expected` を使うときには必ず `subject` を使う 196 | 197 | ```ruby 198 | describe Article do 199 | subject {FactoryGirl.create :article} 200 | it {is_expected.to be_published} 201 | end 202 | ``` 203 | 204 | * `it`の中では、`expect`または`is_expected`のみを使用して良い。`specify`や`should` を使ってはいけない。 205 | * `it` の引数に文字列を設定してはいけない。自己説明的な spec を書くべき。 206 | 207 | ```ruby 208 | # bad 209 | describe Article do 210 | subject {FactoryGirl.create :article} 211 | it "is an Article" do 212 | subject.is_expected.to be_an Article 213 | end 214 | end 215 | 216 | # good 217 | describe Article do 218 | subject {FactoryGirl.create :article} 219 | it {is_expected.to be_an Article} 220 | end 221 | ``` 222 | * `its` を使ってはいけない。 223 | 224 | ```ruby 225 | # bad 226 | describe Article do 227 | subject {FactoryGirl.create :article} 228 | its(:created_at) {is_expected.to eq Date.today} 229 | end 230 | 231 | # bad 232 | describe Article do 233 | subject {FactoryGirl.create :article} 234 | it {expect(subject.created_at).to eq Date.today} 235 | end 236 | ``` 237 | 238 | * `expect`の引数でのメソッドチェインは1回だけして良い。 239 | 240 | 241 | * いくつかのテストで共有される spec グループを作りたいときには `shared_examples` を使う。 242 | 243 | ```ruby 244 | # bad 245 | describe Array do 246 | subject {Array.new [7, 2, 4]} 247 | context "initialized with 3 items" do 248 | it {expect(subject.size).to eq 3 } 249 | end 250 | end 251 | 252 | describe Set do 253 | subject {Set.new [7, 2, 4]} 254 | context "initialized with 3 items" do 255 | it {expect(subject.size).to eq 3} 256 | end 257 | end 258 | 259 | #good 260 | shared_examples "a collection" do 261 | subject {described_class.new([7, 2, 4])} 262 | context "initialized with 3 items" do 263 | it {expect(subject.size).to eq 3} 264 | end 265 | end 266 | 267 | describe Array do 268 | it_behaves_like "a collection" 269 | end 270 | 271 | describe Set do 272 | it_behaves_like "a collection" 273 | end 274 | ``` 275 | 276 | ### Models 277 | * 自分自身に対する spec の中で自分自身のモデルをモックにしてはいけない。 278 | * モックで無いオブジェクトを作成するときには factory_girl を利用する。 279 | * 自分以外のモデルや、子オブジェクトはモックにしても良い。 280 | * factory されたモデルが valid であることを確認する example を作成すること。 281 | 282 | ```ruby 283 | describe Article do 284 | subject {FactoryGirl :article} 285 | it {is_expected.to be_valid} 286 | end 287 | ``` 288 | 289 | * validation が失敗することを確認するときに `.not_to be_valid`を使ってはいけない。validation を確認するときには、どの属性でエラーが発生したかを特定するために、 `have(x).errors_on` メソッドを使うこと。 290 | 291 | ```ruby 292 | # bad 293 | describe "#title" do 294 | subject {FactoryGirl.create :article} 295 | before {subject.title = nil} 296 | it {is_expected.not_to be_valid} 297 | end 298 | 299 | # prefered 300 | describe "#title" do 301 | subject {FactoryGirl.create :article} 302 | before {subject.title = nil} 303 | it {is_expected.to have(1).error_on(:title)} 304 | end 305 | ``` 306 | 307 | * validation する必要のある全ての属性それぞれについて個別に `describe` を追加する。 308 | * モデルの属性がユニークであることをテストする時には、他のオブジェクトを `another_[object名]` という名前にする。 309 | 310 | ```ruby 311 | describe Article do 312 | describe "#title" do 313 | subject {FactoryGirl.build :article} 314 | before {@another_article = FactroyGirl.create :article} 315 | it {is_expected.to have(1).error_on(:title)} 316 | end 317 | end 318 | ``` 319 | 320 | ### Views 321 | 322 | * ビューの spec のディレクトリ `spec/views` の構造を`app/views` の構造と一致させる。例えば、`app/views/users` 内の各ディレクトリおよび各specが `spec/views/users` 内に配置されている各ディレクトリおよび各テンプレートファイルに対応するようにする。 323 | * ビューの spec の命名規則については、ビュー名の最後に `_spec.rb` を付けることとする。例えば `_form.html.haml` に対応する spec は `_form.html.haml_spec.rb` とする。 324 | * `spec_helper.rb` は様々な spec ファイルから必要とされるもののみを記述する。 325 | * 最も外側の describe ブロックには `app/views` の部分を取り除いたビューのパスを指定する。これは引数を指定せずに `render` メソッドを呼んだときに使われる。 326 | 327 | ```ruby 328 | # spec/views/articles/new.html.haml_spec.rb 329 | require "spec_helper" 330 | 331 | describe "articles/new.html.haml" do 332 | # ... 333 | end 334 | ``` 335 | 336 | * ビューの spec 内で使うモデルには、常にモックを使う。ビューの役割は、あくまで情報を表示することである。 337 | * 本来コントローラーによって設定されて、ビューで使われるようなインスタンス変数は、`assign` メソッドを使って設定する。 338 | 339 | ```ruby 340 | # spec/views/articles/edit.html.haml_spec.rb 341 | describe "articles/edit.html.haml" do 342 | subject {rendered} 343 | let(:article) {mock_model(Article).as_new_record.as_null_object} 344 | before do 345 | assign :article, article 346 | render 347 | end 348 | it do 349 | is_expected.to have_selector "form", method: "post", action: articles_path do |form| 350 | form.is_expected.to have_selector "input", type: "submit" 351 | end 352 | end 353 | ``` 354 | 355 | * Capybara の肯定表現を `.not_to` と組み合わせるのではなく、否定表現を `.to` と組み合せるようにする。 356 | 357 | ```ruby 358 | # bad 359 | page.is_expected.not_to have_selector "input", type: "submit" 360 | page.is_expected.not_to have_xpath "tr" 361 | 362 | # good 363 | page.is_expected.to have_no_selector "input", type: "submit" 364 | page.is_expected.to have_no_xpath "tr" 365 | ``` 366 | 367 | * ビューの spec でヘルパーメソッドを使うときには、それらを stub にしなければならない。ヘルパーメソッドは `template` オブジェクト上で stub にする。 368 | 369 | ```ruby 370 | # app/helpers/articles_helper.rb 371 | class ArticlesHelper 372 | def formatted_datei date 373 | # ... 374 | end 375 | end 376 | 377 | # app/views/articles/show.html.haml 378 | = "Published at: #{formatted_date @article.published_at}" 379 | 380 | # spec/views/articles/show.html.haml_spec.rb 381 | describe "articles/show.html.haml" do 382 | subject {rendered} 383 | before do 384 | article = mock_model Article, published_at: Date.new(2012, 01, 01) 385 | assign :article, article 386 | template.stub(:formatted_date).with(article.published_at).and_return("01.01.2012") 387 | render 388 | end 389 | it {is_expected.to have_content "Published at: 01.01.2012"} 390 | end 391 | ``` 392 | 393 | * ヘルパーの spec はビューの spec と分けて、`spec/helpers` ディレクトリに入れる。 394 | 395 | ### Controllers 396 | 397 | * コントローラの spec 内でモデルクラスのインスタンスを扱う場合には mock を使用し、モデルが持つメソッドのふるまいは stub で定義する。コントローラーの spec の実行結果がモデルの実装に左右されてはいけないため。 398 | * コントローラーが責任を持つべき、以下のふるまいのみをテストする。 399 | * 指定したメソッドが実行されているか 400 | * アクションから返るデータ、インスタンス変数にアサインされているか等 401 | * アクションの結果、正しくテンプレートを render しているか、リダイレクトしているか等 402 | 403 | ```ruby 404 | # Example of a commonly used controller spec 405 | # spec/controllers/articles_controller_spec.rb 406 | # We are interested only in the actions the controller should perform 407 | # So we are mocking the model creation and stubbing its methods 408 | # And we concentrate only on the things the controller should do 409 | 410 | describe ArticlesController do 411 | # The model will be used in the specs for all methods of the controller 412 | let(:article) {mock_model Article} 413 | let(:input) {"The New Article Title"} 414 | 415 | describe "POST create" do 416 | before do 417 | Article.stub(:new).and_return(article) 418 | article.stub(:save) 419 | post :create, message: {title: input} 420 | end 421 | 422 | it do 423 | expect(Article).to receive(:new).with(title: input).and_return article 424 | end 425 | 426 | it do 427 | expect(article).to receive(:save) 428 | end 429 | 430 | it do 431 | expect(response).to redirect_to(action: :index) 432 | end 433 | end 434 | end 435 | ``` 436 | 437 | * 受け取る params などによってコントローラーのアクションのふるまいが変化するときには context を利用する。 438 | 439 | ```ruby 440 | # A classic example for use of contexts in a controller spec is creation or update when the object saves successfully or not. 441 | 442 | describe ArticlesController do 443 | let(:article) {mock_model Article} 444 | let(:input) {"The New Article Title"} 445 | 446 | describe "POST create" do 447 | before do 448 | Article.stub(:new).and_return(article) 449 | post :create, article: {title: input} 450 | end 451 | 452 | it do 453 | expect(Article).to receive(:new).with(title: input).and_return(article) 454 | end 455 | 456 | it do 457 | expect(article).to receive :save 458 | end 459 | 460 | context "when the article saves successfully" do 461 | before do 462 | article.stub(:save).and_return(true) 463 | end 464 | 465 | it {expect(flash[:notice]).to eq("The article was saved successfully.")} 466 | it {expect(response).to redirect_to(action: "index")} 467 | end 468 | 469 | context "when the article fails to save" do 470 | before do 471 | article.stub(:save).and_return(false) 472 | end 473 | 474 | it {expect(assigns[:article]).to be article} 475 | it {expect(response).to render_template("new")} 476 | end 477 | end 478 | end 479 | ``` 480 | 481 | ### Mailers 482 | 483 | * メイラーの spec 内でのモデルは全て mock にする。メイラーがモデルに依存してはいけない。 484 | * メイラーの spec は下記を確かめる。 485 | * 件名が正しいか 486 | * 受取人のメールアドレスが正しいか 487 | * 正しい送信者メールアドレスが設定されているか 488 | * メールが正しい情報を含んでいるか 489 | 490 | ```ruby 491 | describe SubscriberMailer do 492 | let(:subscriber) {mock_model(Subscription, email: "johndoe@test.com", name: "John Doe")} 493 | 494 | describe "successful registration email" do 495 | subject(:mail) {SubscriptionMailer.successful_registration_email(subscriber)} 496 | 497 | it {expect(mail.subject).to eq "Successful Registration!"} 498 | it {expect(mail.from).to eq ["info@your_site.com"]} 499 | it {expect(mail.to).to eq [subscriber.email]} 500 | end 501 | end 502 | ``` 503 | -------------------------------------------------------------------------------- /ja/ruby/references.md: -------------------------------------------------------------------------------- 1 | ## Ruby コーデング規約(参考サイト) 2 | 3 | * [Ruby Styleguide](https://github.com/styleguide/ruby) 4 | * [bbatsov / ruby-style-guide](https://github.com/bbatsov/ruby-style-guide) 5 | * [コーディング規約をまとめてみた (Ruby編) - bojovs::blog](http://bojovs.github.com/2012/04/24/ruby-coding-style/) 6 | -------------------------------------------------------------------------------- /ja/ruby/standard.md: -------------------------------------------------------------------------------- 1 | # Ruby コーデング規約(標準スタイル編) 2 | 3 | ## バージョン 4 | 5 | * なるべく最新のものを利用する。 6 | * rbenv 、もしくは rvm を利用する。 7 | * SCMを利用するときは .ruby-version も一緒にコミットし、処理系のバージョンを統一する。 8 | 9 | ## レイアウト 10 | 11 | ## エンコーディング 12 | * UTF-8以外は使用しない。 13 | 14 | * 基本的にスクリプトエンコーディングのマジックコメントが必要なソースコードにしない。 15 | 16 | **理由** 17 | 18 | * UTF-8がcomputer/webの世界で事実上の標準エンコードであるため。 19 | 20 | * 2バイト文字は基本的にユーザーのために記述するものであり、それはソースコードに埋め込まれずにlocaleファイル等に記述されるべきものであるため。 21 | 22 | 23 | ## 基本 24 | * インデントはホワイトスペース2個 25 | * ハードタブは使用しない 26 | * 行の最後に無駄なホワイトスペースは付けない 27 | * 演算子の前後、コロンの前後、カンマの後ろとセミコロンの後ろににホワイトスペースを1個置く 28 | * カンマ、セミコロンの前にはホワイトスペースは置かない 29 | 30 | ```ruby 31 | sum = 1 32 | a, b = 1, 2 33 | 1 > 2 ? true : false; puts 'Hi' 34 | ``` 35 | 36 | * 1行の文字数は80文字以下にする 37 | * 80文字を超える時は、以下のルールで改行を入れる 38 | * メソッドチェーンを途中で改行するときは ``` . ``` (ドット)を改行後の先頭に持ってくる 39 | 40 | ```ruby 41 | "one string".something_long_long_method(arg1) 42 | .other_cool_long_method(arg2) 43 | .another_awsome_long_method(arg3) 44 | ``` 45 | 46 | * メソッドの定義を途中で改行するときは Syntax Error にならないよう適宜 ``` () ``` を用いて改行をする 47 | 48 | ```ruby 49 | def long_method_name(parameter_1, parameter_2, parameter_3, parameter_4, 50 | parameter_5, parameter_6, options) 51 | ``` 52 | 53 | * 長い文字列リテラルのせいで 80文字を越えてしまう場合のみ、80文字を越えることを許可する 54 | 55 | ```ruby 56 | # ok 57 | foo = "This is a very very long string that can't be broken down and may contain #{variable}" 58 | ``` 59 | 60 | * [] () {} 全ての前後にホワイトスペースは置かない 61 | 62 | ```ruby 63 | a = [1, 2, 3] #"[" の左のスペースは = の後ろのもの 64 | [1, 2, 3].each{|num| puts num * 2} 65 | def method(a, b, c) 66 | ``` 67 | 68 | * 改行を含む長い文字列にはヒアドキュメントを使う。ただし、短いメッセージを定義する時や、メソッドチェーンしたいときには、文字列リテラルを使っても良い。 69 | ```ruby 70 | # good 71 | foo = <<-EOS 72 | From this valley they say you are going, 73 | We will miss your bright eyes and sweet smile, 74 | For they say you are taking the sunshine 75 | That has brightened our pathways a while. 76 | EOS 77 | 78 | # ok 79 | foo = "Hi, Johnny. 80 | How are you?" 81 | 82 | # bad 83 | foo = "From this valley they say you are going,\nWe will miss your bright eyes and sweet smile,\nFor they say you are taking the sunshine\nThat has brightened our pathways a while." 84 | ``` 85 | 86 | * 仮引数の後にホワイトスペースを入れる 87 | 88 | ```ruby 89 | # good 90 | arr.each{|elem| puts elem} 91 | 92 | # bad 93 | arr.each{|elem|puts elem} 94 | ``` 95 | 96 | * Hash は基本的に1.9の省略記法で記載する 97 | 98 | ```ruby 99 | # bad 100 | h = {:key => :value} 101 | 102 | # good 103 | h = {key: :value} 104 | ``` 105 | 106 | * ``` do ``` と仮引数の間にホワイトスペースを入れる 107 | 108 | ```ruby 109 | # good 110 | arr.each do |elem| 111 | puts elem 112 | end 113 | 114 | # bad 115 | arr.each do|elem| 116 | puts elem 117 | end 118 | ``` 119 | 120 | * コメントアウトの ``` # ``` の後にはホワイトスペースを置く 121 | 122 | ```ruby 123 | # this is bad comment 124 | 125 | # this is good comment 126 | ``` 127 | 128 | * コメントアウトの ``` =begin ``` の行には何も書いてはいけない 129 | 130 | ```ruby 131 | =begin # bad style 132 | do 133 | somthing 134 | end 135 | =end 136 | 137 | =begin 138 | # good style 139 | do 140 | somthing 141 | end 142 | =end 143 | ``` 144 | 145 | * ``` when ``` と ``` case ``` のインデントは同じ深さにする 146 | 147 | ```ruby 148 | case 149 | when song.name == 'Misty' 150 | puts 'Not again!' 151 | when song.duration > 120 152 | puts 'Too long!' 153 | when Time.now.hour > 21 154 | puts "It's too late" 155 | else 156 | song.play 157 | end 158 | ``` 159 | 160 | * ただし、```case``` の左に何かがある場合には、```when``` の行のインデントを ```case``` の行に対して 1 つ下げる。 161 | ```ruby 162 | foo = case 163 | when song.name == 'Misty' 164 | puts 'Not again!' 165 | when song.duration > 120 166 | puts 'Too long!' 167 | when Time.now.hour > 21 168 | puts "It's too late" 169 | else 170 | song.play 171 | end 172 | ``` 173 | 174 | * ``` def ``` の後には空行を入れる。 175 | 176 | ```ruby 177 | def method1 178 | # some proccesses 179 | end 180 | 181 | def some_method2 182 | # some proccesses 183 | end 184 | ``` 185 | 186 | ## 文法 187 | 188 | * メソッドの定義には ``` () ``` を使わない。ただし以下の場合は適宜 ``` () ``` を使っても良い。 189 | * メソッドの引数が多い等で80文字に納まらず、改行をする。 190 | 191 | ```ruby 192 | def method1 193 | # some proccesses 194 | end 195 | 196 | def method2 arg1, arg2 197 | # some proccesses 198 | end 199 | ``` 200 | 201 | * メソッドの呼び出しには ``` () ``` を使わない。ただし、以下の場合は適宜 ``` () ``` を使っても良い。 202 | * 引数に演算子が着いている、またはメソッド前後に演算子が着いている。ハッシュが引数の時も含む。 203 | * 引数が2個以上である。 204 | * メソッドの引数が多い等で80文字に納まらず、改行をする。 205 | 206 | * ``` for ``` は使用禁止 207 | 208 | ```ruby 209 | arr = [1, 2, 3] 210 | 211 | # bad 212 | for elem in arr do 213 | puts elem 214 | end 215 | 216 | # good 217 | arr.each{|elem| puts elem} 218 | ``` 219 | 220 | * ``` then ``` は使用禁止 221 | 222 | ```ruby 223 | # bad 224 | if some_condition then 225 | # some proccesses 226 | end 227 | 228 | # good 229 | if some_condition 230 | # some proccesses 231 | end 232 | ``` 233 | 234 | * 三項演算子( ``` ? : ```)を使って良いのは1行で全てが納まる時のみとし、その場合は ``` if then else ``` を使わない。 235 | 236 | ```ruby 237 | # good 238 | weather = sun.shiny? ? 'well' : 'cloud' 239 | 240 | # bad 241 | weather = sun.shin? ? 242 | 'well' 243 | : 244 | 'cloud' 245 | 246 | # bad 247 | weather = if sun.shiny? then 'well' else 'cloud' end # you must also not use 'then' keyword. 248 | ``` 249 | 250 | * 三項演算子を重ねて利用してはいけない 251 | 252 | ```ruby 253 | # bad 254 | some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else 255 | 256 | # good 257 | if some_condition 258 | nested_condition ? nested_something : nested_something_else 259 | else 260 | something_else 261 | end 262 | ``` 263 | 264 | * ``` and ``` と ``` or ``` は ``` && ``` と ``` || ``` で代用できる場合は代用する 265 | 266 | * 1行で ``` if 〜 end ``` または ``` unless 〜 end ``` が納まる場合は後置にする。 267 | * 後置の ```if``` や ```unless``` は、それらの右辺と左辺を含めて一行80文字以内に収まるときのみ使って良い。 268 | 269 | ```ruby 270 | # bad 271 | if some_condition 272 | foo = "This is a short string" 273 | end 274 | 275 | # good 276 | foo = "This is a short string" if some_condition 277 | 278 | # bad 279 | foo = "This is a very very long string that can not be broken down and may contain #{variable}" unless some_condition 280 | 281 | # good 282 | unless some_condition 283 | foo = "This is a very very long string that can not be broken down and may contain #{variable}" 284 | end 285 | ``` 286 | 287 | * ``` unless ``` は ``` else ``` と共に使ってはいけない 288 | 289 | ```ruby 290 | # bad 291 | unless success? 292 | puts 'failure' 293 | else 294 | puts 'success' 295 | end 296 | 297 | # good 298 | if success? 299 | puts 'success' 300 | else 301 | puts 'failure' 302 | end 303 | ``` 304 | 305 | * ``` if ``` の条件に否定演算子 ``` ! ``` を用いてはいけない。その場合は ``` unless ``` を使う。ただし、 ``` && ``` や ``` || ``` と組み合わせる場合は用いても良い。その場合もド・モルガンの法則を利用する等で簡潔な記述を心がけること。 306 | 307 | ```ruby 308 | # bad 309 | if !user.nil? 310 | user.greeting 311 | end 312 | 313 | # good 314 | unless user.nil? 315 | user.greeting 316 | end 317 | 318 | # better 319 | if user 320 | user.greeting 321 | end 322 | 323 | # best 324 | user.greeting if user 325 | 326 | # OK 327 | if !user.nil? && !user.suspended? 328 | user.greeting 329 | end 330 | 331 | # not bad, but a little too complex 332 | unless user.nil? || user.suspended? 333 | user.greeting 334 | end 335 | 336 | # should be 337 | if user && user.active? 338 | user.greeting 339 | end 340 | ``` 341 | 342 | * ``` if/unless/while ``` の条件に ``` () ``` は使わない 343 | 344 | ```ruby 345 | # bad 346 | if (x > 10) 347 | # body omitted 348 | end 349 | 350 | # good 351 | if x > 10 352 | # body omitted 353 | end 354 | ``` 355 | 356 | * 1行で納まるblockは ``` {} ``` を使う。そうでない場合は ``` do 〜 end ``` を使う。method chain する場合もこのルールに従う。 357 | 358 | ``` ruby 359 | names = ["Bozhidar", "Steve", "Sarah"] 360 | 361 | # good 362 | names.each{|name| puts name} 363 | 364 | # bad 365 | names.each do |name| 366 | puts name 367 | end 368 | 369 | # good 370 | [1, 2, 3].map{|num| num * 2}.reduce{|double, sum| sum += double} 371 | 372 | # also good 373 | [1, 2, 3].map do |num| 374 | num * 2 375 | end.reduce do |double, sum| 376 | sum += double 377 | end 378 | ``` 379 | 380 | * ``` return ``` は省略できる場合は省略する 381 | 382 | ``` ruby 383 | # bad 384 | def some_method(some_arr) 385 | return some_arr.size 386 | end 387 | 388 | # good 389 | def some_method(some_arr) 390 | some_arr.size 391 | end 392 | ``` 393 | 394 | * ``` if ``` の条件式を代入する場合、``` () ``` でくくる 395 | 396 | ```ruby 397 | # good 398 | if (v = array.grep(/foo/)) ... 399 | 400 | # bad 401 | if v = array.grep(/foo/) ... 402 | 403 | # also good - has correct precedence. 404 | if (v = next_value) == "hello" ... 405 | ``` 406 | 407 | **理由** 408 | 409 | ``` == ``` メソッドとの混同を防ぐため 410 | 411 | * 変数の初期化に ``` ||= ``` の使用を推奨する。ただし、booleanの変数については、falseの値が上書きされるので注意すること。 412 | 413 | ```ruby 414 | # set name to Bozhidar, only if it iss nil or false 415 | name ||= 'Bozhidar' 416 | 417 | # bad - would set enabled to true even if it was false 418 | enabled ||= true 419 | 420 | # good 421 | enabled = true if enabled.nil? 422 | ``` 423 | 424 | * メソッド名と引数の間にはホワイトスペースを入れない 425 | 426 | ```ruby 427 | # bad 428 | f (3 + 2) + 1 429 | 430 | # good 431 | f(3 + 2) + 1 432 | ``` 433 | 434 | * block の引数で使用しないものは ``` _ ``` で受け取る 435 | 436 | ```ruby 437 | # bad 438 | result = hash.map {|k, v| v + 1} 439 | 440 | # good 441 | result = hash.map {|_, v| v + 1} 442 | ``` 443 | 444 | * block の仮引数は変数名に省略した単語を利用して良い。 445 | 446 | ```ruby 447 | # good 448 | products.each {|product| product.maintain!} 449 | 450 | # OK 451 | products.each {|prod| prod.maintain!} 452 | ``` 453 | 454 | * 変数の初期値として 空の Array 、空の Hash を代入する場合には ``` Array.new ```、``` Hash.new ``` と記述する。 455 | 456 | ```ruby 457 | #bad 458 | @users = [] 459 | 460 | #good 461 | @users = Array.new 462 | 463 | #also good 464 | @months_of_birth_date = User.all.inject([]){|months, user| months << user.birth_date.month} 465 | ``` 466 | 467 | **理由** 468 | 469 | オブジェクトの新規作成という意図が明確であるため、「初期化」という意図が伝わりやすい。 470 | 471 | ## 名付け 472 | 473 | * メソッド名や変数名には ``` snake_case ``` を使う 474 | 475 | * クラス名やモジュール名は ``` CamelCase ``` を使う 476 | 477 | * 一般的な定数には ``` SCREAMING_SNAKE_CASE ``` を使う 478 | 479 | * boolean を返却する method は ``` Array#empty? ``` のように最後を ``` ? ``` にする 480 | 481 | * 破壊的メソッドや危険なメソッドは ``` Array#flatten! ``` のように最後を ``` ! ``` にする。破壊的メソッドを定義する際には ``` Array#flatten ``` のように非破壊的メソッドも用意する。 482 | 483 | ## クラス 484 | 485 | * クラス変数 ``` @@ ``` の利用は本当に必要な時以外は避ける。 486 | 487 | ```ruby 488 | class Parent 489 | @@class_var = 'parent' 490 | 491 | def self.print_class_var 492 | puts @@class_var 493 | end 494 | end 495 | 496 | class Child < Parent 497 | @@class_var = 'child' 498 | end 499 | 500 | Parent.print_class_var # => will print "child" 501 | ``` 502 | 503 | * クラスインスタンス変数で実装できないかを検討する。 504 | 505 | ```ruby 506 | class Parent 507 | @class_instance_var = 'parent' 508 | 509 | def self.print_class_instance_var 510 | puts @class_instance_var 511 | end 512 | end 513 | 514 | class Child < Parent 515 | @class_instance_var = 'child' 516 | end 517 | 518 | Parent.print_class_var # => will print "parent" 519 | ``` 520 | 521 | * 特異メソッドを定義するときは ``` def self.method ``` や ``` def ClassName.method ``` を使用しない。 522 | 523 | ```ruby 524 | class TestClass 525 | # bad 526 | def TestClass.some_method 527 | # body omitted 528 | end 529 | 530 | # bad 531 | def self.some_other_method 532 | # body omitted 533 | end 534 | end 535 | ``` 536 | 537 | * 特異メソッド定義や特異クラスマクロは ``` class << self ``` で記述する。 538 | 539 | ```ruby 540 | class TestClass 541 | class << self 542 | attr_accessor :per_page 543 | alias_method :nwo, :find_by_name_with_owner 544 | 545 | def find_by_name_with_owner 546 | # body omitted 547 | end 548 | 549 | def first_method 550 | # body omitted 551 | end 552 | 553 | def second_method_etc 554 | # body omitted 555 | end 556 | end 557 | end 558 | ``` 559 | 560 | * ``` public ``` メソッドについては クラス定義の先頭に持ってきて、 publicのキーワードで宣言しない 561 | 562 | * ``` protected ``` メソッドは ``` private ``` メソッドの前に書く。その時、protected 、 private メソッドの定義は public メソッドと同じ深さのインデントにし、protected 、 private メソッドの上に空行を置き、下には置かない。 563 | 564 | ```ruby 565 | class SomeClass 566 | def public_method 567 | # ... 568 | end 569 | 570 | protected 571 | def protected_method 572 | # ... 573 | end 574 | 575 | private 576 | def private_method 577 | # ... 578 | end 579 | end 580 | ``` 581 | 582 | * private メソッドの呼び出し以外で自分自身を指す時は ``` self ``` を記載する。 583 | 584 | ```ruby 585 | class SomeClass 586 | attr_accessor :message 587 | 588 | def set_name name 589 | self.message = "Hi #{name}" 590 | end 591 | 592 | def greeting 593 | puts self.message 594 | end 595 | end 596 | ``` 597 | 598 | ## 例外 599 | 600 | * Exception をフロー制御に利用せずに、避けられる Exception は全て避ける。大域脱出には ``` throw / catch ``` を利用してよい。 601 | 602 | **理由** 603 | 604 | Exception を発生させると StackTraceを生成するために高い負荷が掛かる。正常処理の中で無用に StackTrace を生成するようなことをしてはいけない。 605 | 606 | ```ruby 607 | # bad 608 | begin 609 | n / d 610 | rescue ZeroDivisionError 611 | puts "Cannot divide by 0!" 612 | end 613 | 614 | # good 615 | if d.zero? 616 | puts "Cannot divide by 0!" 617 | else 618 | n / d 619 | end 620 | ``` 621 | 622 | **理由** 623 | 624 | ``` rescue ``` の引数に何も指定しないと ``` RuntimeError ``` を捕捉するので、それより大きい ``` StandardError ``` や ``` Exception ``` を捕捉してはいけない。 625 | 626 | 特に ``` Exception ``` は例外の基底クラスなので、これを ``` rescue ``` すると、(意図していないかもしれない)全ての例外が捕捉されるので禁止とする。 627 | 628 | * ``` Exception ``` クラスを ``` rescue ``` してはいけない。 629 | 630 | ```ruby 631 | # bad 632 | begin 633 | # an exception occurs here 634 | rescue 635 | # exception handling 636 | end 637 | 638 | # still bad 639 | begin 640 | # an exception occurs here 641 | rescue Exception 642 | # exception handling 643 | end 644 | ``` 645 | 646 | * 文字列の配列を生成する際に、 ``` %w( ) ``` を積極的に利用する。 647 | 648 | ```ruby 649 | # bad 650 | STATES = ['draft', 'open', 'closed'] 651 | 652 | # good 653 | STATES = %w(draft open closed) 654 | ``` 655 | 656 | * Hash のキーは文字列を使わず、できる限りシンボルにする。 657 | 658 | ```ruby 659 | # bad 660 | hash = { 'one' => 1, 'two' => 2, 'three' => 3 } 661 | 662 | # good 663 | hash = { one: 1, two: 2, three: 3 } 664 | ``` 665 | 666 | ## 文字列 667 | 668 | * 文字列への変数を混在する時は連結ではなく、展開を利用する。 669 | 670 | ```ruby 671 | # bad 672 | email_with_name = user.name + ' <' + user.email + '>' 673 | 674 | # good 675 | email_with_name = "#{user.name} <#{user.email}>" 676 | ``` 677 | 678 | * ``` ' ``` は「式展開をしない」、「``` " ```が文字列に含まれる」、「`\`(バックスラッシュ)が文字列に含まれる」等の理由が無い限り使用しない。 679 | 680 | ```ruby 681 | # bad 682 | name = 'Bozhidar' 683 | 684 | # good 685 | name = "Bozhidar" 686 | ``` 687 | 688 | * 再代入する場合、``` String#+ ``` メソッドは使用しない。代わりに ``` String#<< ``` を利用する。 689 | 690 | ```ruby 691 | # good and also fast 692 | html = '' 693 | html << '

Page title

' 694 | 695 | paragraphs.each do |paragraph| 696 | html << "

#{paragraph}

" 697 | end 698 | ``` 699 | 700 | * ヒアドキュメントを利用するときには、デリミタを代入文と同じ深さにインデントする。 701 | 702 | ```ruby 703 | module AttrComparable 704 | module ClassMethods 705 | def attr_comparable *attrs 706 | class_eval <<-DELIM 707 | attrs.each do |attr| 708 | define_method(attr.to_s<<'?'){|param| self.send(attr) == param } 709 | end 710 | DELIM 711 | end 712 | end 713 | #...後略 714 | ``` 715 | 716 | ## 正規表現 717 | 718 | * ``` $1 〜 9 ``` は利用しない。マッチした文字列を利用する場合は名前を付ける。 719 | 720 | ```ruby 721 | # bad 722 | /(regexp)/ =~ string 723 | ... 724 | process $1 725 | 726 | # good 727 | /(?regexp)/ =~ string 728 | ... 729 | process meaningful_var 730 | ``` 731 | 732 | * 改行を含む文字列全体の行頭と行末を指定する時には ``` \A ``` と ``` \Z ``` を利用する。 733 | 734 | ```ruby 735 | string = "some injection\nusername" 736 | string[/^username$/] # matches 737 | string[/\Ausername\Z/] # don't match 738 | ``` 739 | 740 | * 複雑な正規表現パターンを記述する時には ``` x ``` オプションを積極的に利用する。ただし、それを適用すると空白文字が全て無視されることに注意すること。 741 | 742 | ```ruby 743 | regexp = %r{ 744 | start # some text 745 | \s # white space char 746 | (group) # first group 747 | (?:alt1|alt2) # some alternation 748 | end 749 | }x 750 | ``` 751 | 752 | ## パーセント記法 753 | 754 | * ``` %() ``` は文字列自体に ``` " ```を記載する必要がある時にのみ利用する。 755 | 756 | ```ruby 757 | message = %(注意:'と"は区別されます) 758 | ``` 759 | 760 | * ``` %r() ``` は正規表現のパターン内に ``` / ``` を記載する必要がある時にのみ領する。 761 | 762 | ```ruby 763 | # bad 764 | %r(\s+) 765 | 766 | # still bad 767 | %r(^/(.*)$) 768 | # should be /^\/(.*)$/ 769 | 770 | # good 771 | %r(^/blog/2011/(.*)$) 772 | ``` 773 | 774 | ## 値の比較 775 | 776 | * 変数と実数、定数等を比較するときは左辺に実数、右辺に変数とする。 777 | 778 | ```ruby 779 | greeting = "Hello!" 780 | 781 | # bad 782 | if greeting == "Hola!" 783 | ... 784 | end 785 | 786 | # good 787 | if "Hola!" == greeting 788 | ... 789 | end 790 | ``` 791 | 792 | ** 理由 ** 793 | 794 | `==` を誤って `=` と記述した際に代入されずに SyntaxError として検知できるため。 795 | 796 | ## その他 797 | 798 | * ``` __END__ ``` は利用しない。 799 | -------------------------------------------------------------------------------- /rubocop/.rubocop.yml: -------------------------------------------------------------------------------- 1 | # This is rubocop configuration file for Framgia's coding style. Enabling and disabling is configured 2 | # in separate files. This file adds all other parameters apart from Enabled. 3 | 4 | # Put the following files into the same directory as this file. 5 | inherit_from: 6 | - .rubocop_enabled.yml 7 | - .rubocop_disabled.yml 8 | 9 | # Common configuration. 10 | AllCops: 11 | # Include gemspec and Rakefile 12 | Include: 13 | - '**/*.gemspec' 14 | Exclude: 15 | - 'vendor/**/*' 16 | - 'config/unicorn.rb' 17 | - 'bin/*' 18 | - 'db/*' 19 | - 'spec/*' 20 | - 'config/**/*' 21 | # By default, the rails cops are not run. Override in project or home 22 | # directory .rubocop.yml files, or by giving the -R/--rails option. 23 | RunRailsCops: false 24 | 25 | # Indent private/protected/public as deep as method definitions 26 | Style/AccessModifierIndentation: 27 | EnforcedStyle: indent 28 | SupportedStyles: 29 | - outdent 30 | - indent 31 | 32 | # Align the elements of a hash literal if they span more than one line. 33 | Style/AlignHash: 34 | # Alignment of entries using hash rocket as separator. Valid values are: 35 | # 36 | # key - left alignment of keys 37 | # 'a' => 2 38 | # 'bb' => 3 39 | # separator - alignment of hash rockets, keys are right aligned 40 | # 'a' => 2 41 | # 'bb' => 3 42 | # table - left alignment of keys, hash rockets, and values 43 | # 'a' => 2 44 | # 'bb' => 3 45 | EnforcedHashRocketStyle: key 46 | # Alignment of entries using colon as separator. Valid values are: 47 | # 48 | # key - left alignment of keys 49 | # a: 0 50 | # bb: 1 51 | # separator - alignment of colons, keys are right aligned 52 | # a: 0 53 | # bb: 1 54 | # table - left alignment of keys and values 55 | # a: 0 56 | # bb: 1 57 | EnforcedColonStyle: key 58 | # Select whether hashes that are the last argument in a method call should be 59 | # inspected? Valid values are: 60 | # 61 | # always_inspect - Inspect both implicit and explicit hashes. 62 | # Registers an offense for: 63 | # function(a: 1, 64 | # b: 2) 65 | # Registers an offense for: 66 | # function({a: 1, 67 | # b: 2}) 68 | # always_ignore - Ignore both implicit and explicit hashes. 69 | # Accepts: 70 | # function(a: 1, 71 | # b: 2) 72 | # Accepts: 73 | # function({a: 1, 74 | # b: 2}) 75 | # ignore_implicit - Ignore only implicit hashes. 76 | # Accepts: 77 | # function(a: 1, 78 | # b: 2) 79 | # Registers an offense for: 80 | # function({a: 1, 81 | # b: 2}) 82 | # ignore_explicit - Ignore only explicit hashes. 83 | # Accepts: 84 | # function({a: 1, 85 | # b: 2}) 86 | # Registers an offense for: 87 | # function(a: 1, 88 | # b: 2) 89 | EnforcedLastArgumentHashStyle: ignore_implicit 90 | SupportedLastArgumentHashStyles: 91 | - always_inspect 92 | - always_ignore 93 | - ignore_implicit 94 | - ignore_explicit 95 | 96 | Style/AlignParameters: 97 | # Alignment of parameters in multi-line method calls. 98 | # 99 | # The `with_first_parameter` style aligns the following lines along the same column 100 | # as the first parameter. 101 | # 102 | # method_call(a, 103 | # b) 104 | # 105 | # The `with_fixed_indentation` style aligns the following lines with one 106 | # level of indentation relative to the start of the line with the method call. 107 | # 108 | # method_call(a, 109 | # b) 110 | EnforcedStyle: with_fixed_indentation 111 | SupportedStyles: 112 | - with_first_parameter 113 | - with_fixed_indentation 114 | 115 | Metrics/BlockNesting: 116 | Max: 3 117 | 118 | Style/BracesAroundHashParameters: 119 | EnforcedStyle: no_braces 120 | SupportedStyles: 121 | - braces 122 | - no_braces 123 | 124 | # Indentation of `when`. 125 | Style/CaseIndentation: 126 | IndentWhenRelativeTo: case 127 | SupportedStyles: 128 | - case 129 | - end 130 | IndentOneStep: false 131 | 132 | Style/ClassAndModuleChildren: 133 | # Checks the style of children definitions at classes and modules. 134 | # 135 | # Basically there are two different styles: 136 | # 137 | # `nested` - have each child on a separate line 138 | # class Foo 139 | # class Bar 140 | # end 141 | # end 142 | # 143 | # `compact` - combine definitions as much as possible 144 | # class Foo::Bar 145 | # end 146 | # 147 | # The compact style is only forced, for classes / modules with one child. 148 | EnforcedStyle: nested 149 | SupportedStyles: 150 | - nested 151 | - compact 152 | 153 | Style/ClassCheck: 154 | EnforcedStyle: is_a? 155 | SupportedStyles: 156 | - is_a? 157 | - kind_of? 158 | 159 | Metrics/ClassLength: 160 | CountComments: false # count full line comments? 161 | Max: 100 162 | 163 | # Align with the style guide. 164 | Style/CollectionMethods: 165 | # Mapping from undesired method to desired_method 166 | # e.g. to use `detect` over `find`: 167 | # 168 | # CollectionMethods: 169 | # PreferredMethods: 170 | # find: detect 171 | PreferredMethods: 172 | collect: 'map' 173 | collect!: 'map!' 174 | inject: 'reduce' 175 | detect: 'find' 176 | find_all: 'select' 177 | 178 | # Checks formatting of special comments 179 | Style/CommentAnnotation: 180 | Keywords: 181 | - TODO 182 | - FIXME 183 | - OPTIMIZE 184 | - HACK 185 | - REVIEW 186 | 187 | # Avoid complex methods. 188 | Metrics/CyclomaticComplexity: 189 | Max: 6 190 | 191 | # Multi-line method chaining should be done with leading dots. 192 | Style/DotPosition: 193 | EnforcedStyle: leading 194 | SupportedStyles: 195 | - leading 196 | - trailing 197 | 198 | # Use empty lines between defs. 199 | Style/EmptyLineBetweenDefs: 200 | # If true, this parameter means that single line method definitions don't 201 | # need an empty line between them. 202 | AllowAdjacentOneLineDefs: false 203 | 204 | Style/EmptyLinesAroundBlockBody: 205 | EnforcedStyle: no_empty_lines 206 | SupportedStyles: 207 | - no_empty_lines 208 | 209 | Style/EmptyLinesAroundClassBody: 210 | EnforcedStyle: no_empty_lines 211 | SupportedStyles: 212 | - no_empty_lines 213 | 214 | Style/EmptyLinesAroundModuleBody: 215 | EnforcedStyle: no_empty_lines 216 | SupportedStyles: 217 | - no_empty_lines 218 | 219 | # Checks whether the source file has a utf-8 encoding comment or not 220 | Style/Encoding: 221 | EnforcedStyle: when_needed 222 | SupportedStyles: 223 | - when_needed 224 | - always 225 | 226 | Style/FileName: 227 | Exclude: 228 | - '**/Rakefile' 229 | - '**/Gemfile' 230 | - '**/Capfile' 231 | 232 | # Checks use of for or each in multiline loops. 233 | Style/For: 234 | EnforcedStyle: each 235 | SupportedStyles: 236 | - for 237 | - each 238 | 239 | # Enforce the method used for string formatting. 240 | Style/FormatString: 241 | EnforcedStyle: format 242 | SupportedStyles: 243 | - format 244 | - sprintf 245 | - percent 246 | 247 | # Built-in global variables are allowed by default. 248 | Style/GlobalVars: 249 | AllowedVariables: [] 250 | 251 | # `MinBodyLength` defines the number of lines of the a body of an if / unless 252 | # needs to have to trigger this cop 253 | Style/GuardClause: 254 | MinBodyLength: 1 255 | 256 | Style/HashSyntax: 257 | EnforcedStyle: ruby19 258 | SupportedStyles: 259 | - ruby19 260 | - hash_rockets 261 | 262 | Style/IfUnlessModifier: 263 | MaxLineLength: 80 264 | 265 | # Checks the indentation of the first key in a hash literal. 266 | Style/IndentHash: 267 | # The value `special_inside_parentheses` means that hash literals with braces 268 | # that have their opening brace on the same line as a surrounding opening 269 | # round parenthesis, shall have their first key indented relative to the 270 | # first position inside the parenthesis. 271 | # The value `consistent` means that the indentation of the first key shall 272 | # always be relative to the first position of the line where the opening 273 | # brace is. 274 | EnforcedStyle: special_inside_parentheses 275 | SupportedStyles: 276 | - special_inside_parentheses 277 | - consistent 278 | 279 | Style/LambdaCall: 280 | EnforcedStyle: call 281 | SupportedStyles: 282 | - call 283 | - braces 284 | 285 | Metrics/LineLength: 286 | Max: 120 287 | AllowURI: true 288 | Exclude: 289 | - config/routes.rb 290 | 291 | 292 | Style/Next: 293 | # With `always` all conditions at the end of an iteration needs to be 294 | # replace by next - with `skip_modifier_ifs` the modifier if like this one 295 | # are ignored: [1, 2].each { |a| return 'yes' if a == 1 } 296 | EnforcedStyle: skip_modifier_ifs 297 | SupportedStyles: 298 | - skip_modifier_ifs 299 | - always 300 | 301 | Style/NonNilCheck: 302 | # With `IncludeSemanticChanges` set to `true`, this cop reports offenses for 303 | # `!x.nil?` and autocorrects that and `x != nil` to solely `x`, which is 304 | # **usually** OK, but might change behavior. 305 | # 306 | # With `IncludeSemanticChanges` set to `false`, this cop does not report 307 | # offenses for `!x.nil?` and does no changes that might change behavior. 308 | IncludeSemanticChanges: false 309 | 310 | Style/MethodDefParentheses: 311 | EnforcedStyle: require_no_parentheses 312 | SupportedStyles: 313 | - require_parentheses 314 | - require_no_parentheses 315 | 316 | Metrics/MethodLength: 317 | CountComments: false # count full line comments? 318 | Max: 10 319 | 320 | Style/MethodName: 321 | EnforcedStyle: snake_case 322 | SupportedStyles: 323 | - snake_case 324 | - camelCase 325 | 326 | Style/NumericLiterals: 327 | MinDigits: 5 328 | 329 | Metrics/ParameterLists: 330 | Max: 5 331 | CountKeywordArgs: true 332 | 333 | # Allow safe assignment in conditions. 334 | Style/ParenthesesAroundCondition: 335 | AllowSafeAssignment: true 336 | 337 | Style/PercentLiteralDelimiters: 338 | PreferredDelimiters: 339 | '%': () 340 | '%i': () 341 | '%q': () 342 | '%Q': () 343 | '%r': '{}' 344 | '%s': () 345 | '%w': () 346 | '%W': () 347 | '%x': () 348 | 349 | Style/PredicateName: 350 | NamePrefixBlacklist: 351 | - get_ 352 | 353 | Style/RaiseArgs: 354 | EnforcedStyle: exploded 355 | SupportedStyles: 356 | - compact # raise Exception.new(msg) 357 | - exploded # raise Exception, msg 358 | 359 | 360 | Style/RedundantReturn: 361 | # When true allows code like `return x, y`. 362 | AllowMultipleReturnValues: false 363 | 364 | Style/Semicolon: 365 | # Allow ; to separate several expressions on the same line. 366 | AllowAsExpressionSeparator: false 367 | 368 | Style/SignalException: 369 | EnforcedStyle: only_raise 370 | SupportedStyles: 371 | - only_raise 372 | - only_fail 373 | - semantic 374 | 375 | 376 | Style/SingleLineBlockParams: 377 | Methods: 378 | - reduce: 379 | - a 380 | - e 381 | - inject: 382 | - a 383 | - e 384 | 385 | Style/SingleLineMethods: 386 | AllowIfMethodIsEmpty: true 387 | 388 | Style/StringLiterals: 389 | EnforcedStyle: double_quotes 390 | SupportedStyles: 391 | - single_quotes 392 | - double_quotes 393 | 394 | Style/SpaceAroundEqualsInParameterDefault: 395 | EnforcedStyle: space 396 | SupportedStyles: 397 | - space 398 | - no_space 399 | 400 | Style/SpaceBeforeBlockBraces: 401 | EnforcedStyle: no_space 402 | SupportedStyles: 403 | - space 404 | - no_space 405 | 406 | Style/SpaceInsideBlockBraces: 407 | EnforcedStyle: no_space 408 | SupportedStyles: 409 | - space 410 | - no_space 411 | # Valid values are: space, no_space 412 | EnforcedStyleForEmptyBraces: no_space 413 | # Space between { and |. Overrides EnforcedStyle if there is a conflict. 414 | SpaceBeforeBlockParameters: false 415 | 416 | Style/SpaceInsideHashLiteralBraces: 417 | EnforcedStyle: no_space 418 | EnforcedStyleForEmptyBraces: no_space 419 | SupportedStyles: 420 | - space 421 | - no_space 422 | 423 | Style/TrailingBlankLines: 424 | EnforcedStyle: final_newline 425 | SupportedStyles: 426 | - final_newline 427 | - final_blank_line 428 | 429 | Style/TrailingComma: 430 | # If EnforcedStyleForMultiline is comma, the cop allows a comma after the 431 | # last item of a list, but only for lists where each item is on its own line. 432 | EnforcedStyleForMultiline: no_comma 433 | SupportedStyles: 434 | - comma 435 | - no_comma 436 | 437 | # TrivialAccessors doesn't require exact name matches and doesn't allow 438 | # predicated methods by default. 439 | Style/TrivialAccessors: 440 | ExactNameMatch: false 441 | AllowPredicates: false 442 | # Allows trivial writers that don't end in an equal sign. e.g. 443 | # 444 | # def on_exception(action) 445 | # @on_exception=action 446 | # end 447 | # on_exception :restart 448 | # 449 | # Commonly used in DSLs 450 | AllowDSLWriters: false 451 | Whitelist: 452 | - to_ary 453 | - to_a 454 | - to_c 455 | - to_enum 456 | - to_h 457 | - to_hash 458 | - to_i 459 | - to_int 460 | - to_io 461 | - to_open 462 | - to_path 463 | - to_proc 464 | - to_r 465 | - to_regexp 466 | - to_str 467 | - to_s 468 | - to_sym 469 | 470 | Style/VariableName: 471 | EnforcedStyle: snake_case 472 | SupportedStyles: 473 | - snake_case 474 | - camelCase 475 | 476 | Style/WhileUntilModifier: 477 | MaxLineLength: 80 478 | 479 | Style/WordArray: 480 | MinSize: 0 481 | 482 | ##################### Lint ################################## 483 | 484 | # Allow safe assignment in conditions. 485 | Lint/AssignmentInCondition: 486 | AllowSafeAssignment: true 487 | 488 | # Align ends correctly. 489 | Lint/EndAlignment: 490 | # The value `keyword` means that `end` should be aligned with the matching 491 | # keyword (if, while, etc.). 492 | # The value `variable` means that in assignments, `end` should be aligned 493 | # with the start of the variable on the left hand side of `=`. In all other 494 | # situations, `end` should still be aligned with the keyword. 495 | AlignWith: keyword 496 | SupportedStyles: 497 | - keyword 498 | - variable 499 | 500 | Lint/DefEndAlignment: 501 | # The value `def` means that `end` should be aligned with the def keyword. 502 | # The value `start_of_line` means that `end` should be aligned with method 503 | # calls like `private`, `public`, etc, if present in front of the `def` 504 | # keyword on the same line. 505 | AlignWith: start_of_line 506 | SupportedStyles: 507 | - start_of_line 508 | - def 509 | 510 | ##################### Rails ################################## 511 | 512 | Rails/ActionFilter: 513 | EnforcedStyle: action 514 | SupportedStyles: 515 | - action 516 | - filter 517 | Include: 518 | - app/controllers/**/*.rb 519 | 520 | Rails/DefaultScope: 521 | Include: 522 | - app/models/**/*.rb 523 | 524 | Rails/HasAndBelongsToMany: 525 | Include: 526 | - app/models/**/*.rb 527 | 528 | Rails/ReadWriteAttribute: 529 | Include: 530 | - app/models/**/*.rb 531 | 532 | Rails/ScopeArgs: 533 | Include: 534 | - app/models/**/*.rb 535 | 536 | Rails/Validation: 537 | Include: 538 | - app/models/**/*.rb 539 | -------------------------------------------------------------------------------- /rubocop/.rubocop_disabled.yml: -------------------------------------------------------------------------------- 1 | # These are all the cops that are disabled in the default configuration. 2 | 3 | Style/InlineComment: 4 | Description: "Avoid inline comments." 5 | Enabled: false 6 | 7 | Style/MethodCalledOnDoEndBlock: 8 | Description: "Avoid chaining a method call on a do...end block." 9 | Enabled: false 10 | 11 | Style/SymbolArray: 12 | Description: "Use %i or %I for arrays of symbols." 13 | Enabled: false 14 | 15 | Style/Documentation: 16 | Description: "Document classes and non-namespace modules." 17 | Enabled: false 18 | 19 | Style/EmptyLinesAroundAccessModifier: 20 | Description: "Keep blank lines around access modifiers." 21 | Enabled: false 22 | 23 | Style/EmptyLiteral: 24 | Description: "Prefer literals to Array.new/Hash.new/String.new." 25 | Enabled: false 26 | 27 | Style/ClassAndModuleChildren: 28 | Description: "Checks style of children classes and modules." 29 | Enabled: false 30 | 31 | Metrics/ClassLength: 32 | Description: "Avoid classes longer than 100 lines of code." 33 | Enabled: false 34 | 35 | Metrics/MethodLength: 36 | Description: "Avoid methods longer than 10 lines of code." 37 | Enabled: false 38 | 39 | Metrics/ParameterLists: 40 | Description: "Avoid parameter lists longer than three or four parameters." 41 | Enabled: false 42 | 43 | Metrics/CyclomaticComplexity: 44 | Description: "Avoid complex methods." 45 | Enabled: false 46 | 47 | Style/AlignArray: 48 | Description: >- 49 | Align the elements of an array literal if they span more than 50 | one line. 51 | Enabled: false 52 | 53 | Style/UnneededPercentQ: 54 | Description: "Checks for %q/%Q when single quotes or double quotes would do." 55 | Enabled: false 56 | 57 | Style/AccessorMethodName: 58 | Description: Check the naming of accessor methods for get_/set_. 59 | Enabled: false 60 | 61 | #################### Lint ################################ 62 | ### Warnings 63 | Lint/AssignmentInCondition: 64 | Description: "Don't use assignment in conditions." 65 | Enabled: false 66 | 67 | -------------------------------------------------------------------------------- /vn/README.md: -------------------------------------------------------------------------------- 1 | # Các quy định về viết code ở công ty Framgia 2 | 3 | ## Ruby 4 | 5 | #### [Kiểu chuẩn](./ruby/standard.md) 6 | #### [Tham khảo](./ruby/references.md) 7 | 8 | ## Ruby on Rails 9 | 10 | #### [Kiểu chuẩn](./rails/standard.md) 11 | #### [Phần viết test](./rails/test.md) 12 | #### [Các Gem](./rails/gems.md) 13 | #### [Tham khảo](./rails/references.md) 14 | 15 | ## PHP 16 | Tài liệu coding standard dưới đây được dựa trên các bản PHP Specification Request (PSR) 17 | của nhóm [PHP Framework Interop Group (PHP FIG)](http://www.php-fig.org/) 18 | 19 | Các bản gốc bằng tiếng Anh có thể được tham khảo tại repository của nhóm trên [github](https://github.com/php-fig/fig-standards) 20 | #### [PSR-1 Basic Coding Standard](./php/PSR-1.md) 21 | #### [PSR-2 Coding Style Guide](./php/PSR-2.md) 22 | #### [Others](./php/others.md) 23 | 24 | ## Android 25 | 26 | ####[Cấu trúc của một Dự Án](./android/standard.md) 27 | ####[Coding Style Guide](./android/codingstyleguide.md) 28 | ####[Coding convention with Kotlin](./android/coding_convention_android_kotlin.md) 29 | ####[Others](./android/others.md) 30 | 31 | ## HTML 32 | 33 | ## CSS 34 | 35 | ## Javascript 36 | 37 | ## git 38 | 39 | #### [Flow chuẩn](./git/flow.md) 40 | -------------------------------------------------------------------------------- /vn/android/codingstyleguide.md: -------------------------------------------------------------------------------- 1 | # Coding Style Guide 2 | Tài liệu xây dựng trên tài liệu tham khảo và [Android Code Style Guidelines](https://source.android.com/source/code-style.html) 3 | 4 | ## 1. Java language rules 5 | 6 | ### 1.1 Đừng bỏ qua trường hợp ngoại lệ 7 | 8 | Bạn không bao giờ được làm như sau: 9 | 10 | ```java 11 | void setServerPort(String value) { 12 | try { 13 | serverPort = Integer.parseInt(value); 14 | } catch (NumberFormatException e) { } 15 | } 16 | ``` 17 | 18 | Theo bạn nghĩ nó có thể không bao giờ xảy ra, nhưng một ngày nào đó bạn của bạn sẽ gặp vấn đề này. Bạn phải buộc xử lý nó theo một số cách. 19 | 20 | * Ném ngoại lệ lên cho người gọi phương thức 21 | 22 | ```java 23 | void setServerPort(String value) throws NumberFormatException { 24 | serverPort = Integer.parseInt(value); 25 | } 26 | ``` 27 | * Ném lại ngoại lệ với lớp trừu tượng của bạn 28 | 29 | ```java 30 | void setServerPort(String value) throws ConfigurationException { 31 | try { 32 | serverPort = Integer.parseInt(value); 33 | } catch (NumberFormatException e) { 34 | throw new ConfigurationException("Port " + value + " is not valid."); 35 | } 36 | } 37 | ``` 38 | * Thay thế một giá trị thích hợp, như giá trị mặc định chẳng hạn 39 | 40 | ```java 41 | void setServerPort(String value) { 42 | try { 43 | serverPort = Integer.parseInt(value); 44 | } catch (NumberFormatException e) { 45 | serverPort = 80; // default port for server 46 | } 47 | } 48 | ``` 49 | 50 | * Ném ngoại lệ vào một RuntimeException mới. Nhưng bạn chắc chắn rằng bạn muốn làm điều này, vì nó sẽ gây lỗi ứng dụng 51 | 52 | ```java 53 | void setServerPort(String value) { 54 | try { 55 | serverPort = Integer.parseInt(value); 56 | } catch (NumberFormatException e) { 57 | throw new RuntimeException("port " + value " is invalid, ", e); 58 | } 59 | } 60 | ``` 61 | 62 | * Cuối cùng bạn sẽ loại bỏ nó nhưng phải có một lý do chính đáng 63 | 64 | ```java 65 | void setServerPort(String value) { 66 | try { 67 | serverPort = Integer.parseInt(value); 68 | } catch (NumberFormatException e) { 69 | // Method is documented to just ignore invalid user input. 70 | // serverPort will just be unchanged. 71 | } 72 | } 73 | ``` 74 | 75 | ### 1.2 Không được bắt ngoại lệ chung 76 | 77 | ```java 78 | try { 79 | someComplicatedIOFunction(); // may throw IOException 80 | someComplicatedParsingFunction(); // may throw ParsingException 81 | someComplicatedSecurityFunction(); // may throw SecurityException 82 | // phew, made it all the way 83 | } catch (Exception e) { // I'll just catch all exceptions 84 | handleError(); // with one generic handler! 85 | } 86 | ``` 87 | 88 | Xem thêm tại [đây](https://source.android.com/source/code-style.html#dont-catch-generic-exception) 89 | 90 | ### 1.3 Không sử dụng finalizers 91 | 92 | Xem tại đây [Android code style guidelines](https://source.android.com/source/code-style.html#dont-use-finalizers) 93 | 94 | ### 1.4 Fully qualify imports 95 | 96 | Không tốt: `import foo.*;` 97 | 98 | Tốt: `import foo.Bar;` 99 | 100 | Xem thêm [tại đây](https://source.android.com/source/code-style.html#fully-qualify-imports) 101 | 102 | ## 2 Java style rules 103 | 104 | ### 2.1 Định nghĩa và đặt tên 105 | 106 | Các trường cần được định nghĩa ở đầu file và tuân theo cú pháp đặt tên như sau. 107 | 108 | 109 | * Non-public, non-static tên trường bắt đầu bằng chữ __m__. 110 | * static tên trường bắt đầu bằng chữ s __s__. 111 | * Các trường hợp khác bắt đầu bằng chữ viết thường(lower case). 112 | * Public static final đây là một hằng số chúng sẽ sử dụng cú pháp ALL_CAPS_WITH_UNDERSCORES. 113 | 114 | Ví dụ: 115 | 116 | ```java 117 | public class MyClass { 118 | public static final int SOME_CONSTANT = 42; 119 | public int publicField; 120 | private static MyClass sSingleton; 121 | int mPackagePrivate; 122 | private int mPrivate; 123 | protected int mProtected; 124 | } 125 | ``` 126 | 127 | ### 2.2 Treat Acronyms as Words 128 | 129 | Đặt tên biến, phương thức và lớp. Cần viết tắn như lời nói. 130 | 131 | | Good | Bad | 132 | | -------------- | -------------- | 133 | | `XmlHttpRequest` | `XMLHTTPRequest` | 134 | | `getCustomerId` | `getCustomerID` | 135 | | `String url` | `String URL` | 136 | | `long id` | `long ID` | 137 | 138 | ### 2.3 Sử dụng khoảng trống(trắng) 139 | 140 | Sử dụng 4 khoảng trống cho một khối: 141 | 142 | ```java 143 | if (x == 1) { 144 | x++; 145 | } 146 | ``` 147 | 148 | Sử dụng 8 khoảng trống cho việc xuống dòng 149 | 150 | ```java 151 | Instrument i = 152 | someLongExpression(that, wouldNotFit, on, one, line); 153 | ``` 154 | 155 | ### 2.4 Sử dụng ngoặc kép chuẩn trong Java 156 | 157 | ```java 158 | class MyClass { 159 | int func() { 160 | if (something) { 161 | // ... 162 | } else if (somethingElse) { 163 | // ... 164 | } else { 165 | // ... 166 | } 167 | } 168 | } 169 | ``` 170 | 171 | Trong một số trường hợp ___không sử dụng ngoặc kép___ 172 | 173 | ```java 174 | if (condition) body(); 175 | ``` 176 | Không nên 177 | 178 | ```java 179 | if (condition) 180 | body(); // không tốt! 181 | ``` 182 | 183 | ### 2.5 Tiêu chuẩn mặc định chú thích (annotations) trong Java 184 | 185 | Theo hướng dẫn trong Android code style guide, Tiêu chuẩn cho chú thích được xác định như sau: 186 | 187 | * `@Override`: Phải được sử dụng bất cứ khi nào muốn ghi đè một phương thức từ lớp cha. Ví dụ bạn cần sử dụng phương thức onCreate từ lớp cha Activity thì bạn cần phải ghi đè nó @Override 188 | * `@ SuppressWarnings `: Chú thích này chỉ sử dụng khi mà không thể loại bỏ một cảnh báo 189 | 190 | ### 2.6 Giới hạn phạm vi của biến 191 | 192 | Phạm vi của biến nên giữ một cách tối thiểu. Bởi nếu làm điều đó thì code của bạn dễ đọc, dễ sửa chữa và giảm thiểu lỗi. Mỗi biến cần khái báo trong khối bên trong nhất mà có ứng dụng có thể sử dụng nó. 193 | 194 | Biến cục bộ sẽ tồn tại khi lần đầu tiên chúng ta sử dụng. và các biết cục bộ cần phải khai báo. Nếu chưa đủ thông tin để khởi tạo bạn cần chờ đến khi có thể làm. [Xem thêm](https://source.android.com/source/code-style.html#limit-variable-scope) 195 | 196 | ### 2.7 Hướng dẫn Log 197 | 198 | `Log` là một class in ra kết quả lỗi hoặc thông tin nào đó giúp lập trình viên gỡ rối vấn đề: 199 | 200 | * `Log.v(String tag, String msg)` (verbose) 201 | * `Log.d(String tag, String msg)` (debug) 202 | * `Log.i(String tag, String msg)` (information) 203 | * `Log.w(String tag, String msg)` (warning) 204 | * `Log.e(String tag, String msg)` (error) 205 | 206 | Như một quy định chung, chúng ta khai báo một TAG ở mỗi một file: 207 | 208 | ```java 209 | public class MyClass { 210 | private static final String TAG = "MyClass"; 211 | 212 | public myMethod() { 213 | Log.e(TAG, "Thông báo lỗi"); 214 | } 215 | } 216 | ``` 217 | 218 | Và bạn muốn hủy Log khi `Release` và chỉ muốn hiện khi `Debug`: 219 | 220 | ```java 221 | if (BuildConfig.DEBUG) Log.d(TAG, "Giá trị của bạn X là " + x); 222 | ``` 223 | 224 | ### 2.8 Thứ tự member trong class 225 | 226 | Nó không phải là giải pháp đúng duy nhất, nhưng nó là gợi ý tốt nên sử dụng: 227 | 228 | 1. Constants 229 | 2. Fields 230 | 3. Constructors 231 | 4. Override methods and callbacks (public or private) 232 | 5. Public methods 233 | 6. Private methods 234 | 7. Inner classes or interfaces 235 | 236 | Ví dụ: 237 | 238 | ```java 239 | 240 | public class MainActivity extends Activity { 241 | 242 | private String mTitle; 243 | private TextView mTextViewTitle; 244 | 245 | public void setTitle(String title) { 246 | mTitle = title; 247 | } 248 | 249 | @Override 250 | public void onCreate() { 251 | ... 252 | } 253 | 254 | private void setUpView() { 255 | ... 256 | } 257 | 258 | static class AnInnerClass { 259 | 260 | } 261 | 262 | } 263 | 264 | 265 | ``` 266 | 267 | Trong android, tốt nhất lên theo thứ tự vòng đời của Activity or Fragment. 268 | 269 | ```java 270 | public class MainActivity extends Activity { 271 | 272 | //Order matches Activity lifecycle 273 | @Override 274 | public void onCreate() {} 275 | 276 | @Override 277 | public void onResume() {} 278 | 279 | @Override 280 | public void onPause() {} 281 | 282 | @Override 283 | public void onDestory() {} 284 | 285 | } 286 | ``` 287 | 288 | ### 2.9 Thứ tự tham số trong các phương thức 289 | 290 | Trong lập trình Android, khá phổ biến khi một phương thức cần có một `Context`. Nếu bạn viết phương thức `Context` phải là tham số đầu tiên. 291 | 292 | Và `callback` luôn là tham số cuối cùng. 293 | 294 | Ví dụ: 295 | 296 | ```java 297 | 298 | // Context luôn đầu tiên 299 | public User loadUser(Context context, int userId); 300 | 301 | // Callbacks luôn cuối cùng 302 | public void loadUserAsync(Context context, int userId, UserCallback callback); 303 | 304 | ``` 305 | 306 | ### 2.10 String constants, naming and values 307 | 308 | Rất nhiều các yêu tố trong Android như SharedPreferences, Bundle, Intent sử dụng cặp key-value 309 | Khi sử dụng các thành phần này bạn cần định nghĩa các keys như là `static final`: 310 | 311 | | Element | Field Name Prefix | 312 | | ----------------- | ----------------- | 313 | | SharedPreferences | `PREF_` | 314 | | Bundle | `BUNDLE_` | 315 | | Fragment Arguments | `ARGUMENT_` | 316 | | Intent Extra | `EXTRA_` | 317 | | Intent Action | `ACTION_` | 318 | 319 | Ví dụ: 320 | 321 | ```java 322 | 323 | // Giá trị của biến giống như tên để tránh sự trùng lặp 324 | static final String PREF_EMAIL = "PREF_EMAIL"; 325 | static final String BUNDLE_AGE = "BUNDLE_AGE"; 326 | static final String ARGUMENT_USER_ID = "ARGUMENT_USER_ID"; 327 | 328 | 329 | // Intent, tên của Action Broadcast nên sử dụng đẩy đủ tên gói như là một giá trị 330 | static final String EXTRA_SURNAME = "com.myapp.extras.EXTRA_SURNAME"; 331 | static final String ACTION_OPEN_USER = "com.myapp.action.ACTION_OPEN_USER"; 332 | 333 | 334 | ``` 335 | 336 | ### 2.11 Đối số trong Activity và Fragment 337 | 338 | Khi truyền dữ liệu qua `Activity` hoặc `Framgment` thông qua `Intent` hoặc `Bundle`, các keys và giá trị phải tuân theo __[Mục 2.10](#210-string-constants-naming-and-values)__ và cần khai báo `public static`. 339 | 340 | Trường hợp gửi một user trong activity, gọi `getProfileIntent()` 341 | 342 | ```java 343 | public static Intent getProfileIntent(Context context, User user) { 344 | Intent intent = new Intent(context, ProfileActivity.class); 345 | intent.putParcelableExtra(EXTRA_USER, user); 346 | return intent; 347 | } 348 | ``` 349 | 350 | Cho trường hợp dùng fragment. 351 | 352 | ```java 353 | public static UserFragment newInstance(User user) { 354 | UserFragment fragment = new UserFragment; 355 | Bundle args = new Bundle(); 356 | args.putParcelable(ARGUMENT_USER, user); 357 | fragment.setArguments(args) 358 | return fragment; 359 | } 360 | ``` 361 | 362 | ### 2.12 Giới hạn độ dài dòng 363 | 364 | Độ dài của một dòng code không vượt quá __100 ký tự__. Nếu quá giới hạn bạn có 2 cách để giảm chiều dại lại: 365 | 366 | * Đẩy ra biến địa phương hoặc phương thức (khuyến khích). 367 | * Áp dụng line-wrapping để chia thành phần thành nhiều dòng nhỏ. 368 | 369 | Có hai trường hợp mà bạn có thể dài hơn 100 ký tự: 370 | 371 | * Dòng không thể phân chia, ví dụ chiều dài của URLs 372 | * `package` và `import` 373 | 374 | #### 2.12.1 Line-wrapping strategies 375 | 376 | Không có một công thức và lý thuyết nào giải thích việc xuống dòng, Nhưng có vài quy tắc có thể áp dụng chung như sau. 377 | 378 | __Trường hợp phương thức dài__ 379 | 380 | Khi có nhiều phương thức gọi trên một dòng, ví dụ như khi dụng `Builders` -> mọi phương thức sẽ được gọi trên một dòng và ngăn khi sau dấu `.` 381 | 382 | Ví dụ: 383 | 384 | ```java 385 | 386 | Picasso.with(context).load("https://farm6.staticflickr.com/5595/14899879106_f5028bd19d_k.jpg").into(imageView); 387 | 388 | 389 | ``` 390 | 391 | Thành 392 | 393 | ```java 394 | 395 | Picasso.with(context) 396 | .load("https://farm6.staticflickr.com/5595/14899879106_f5028bd19d_k.jpg") 397 | .into(imageView); 398 | 399 | 400 | ``` 401 | 402 | __Tham số dài__ 403 | 404 | Khi các phương thức có nhiều tham số, và các tham số rất dài thì ta có thể ngăn các các dòng sau dấu `,` 405 | 406 | ```java 407 | 408 | loadPicture(context, "https://farm6.staticflickr.com/5595/14899879106_f5028bd19d_k.jpg", mImageViewProfilePicture, clickListener, "Title of the picture"); 409 | 410 | 411 | ``` 412 | 413 | ```java 414 | 415 | loadPicture(context, 416 | "https://farm6.staticflickr.com/5595/14899879106_f5028bd19d_k.jpg", 417 | mImageViewProfilePicture, clickListener, 418 | "Title of the picture"); 419 | 420 | 421 | ``` 422 | 423 | ### 2.13 RxJava chains styling 424 | 425 | Các `operator` Rx buộc phải xuống dòng và trên một dòng mới trước `.` 426 | 427 | ```java 428 | public Observable syncLocations() { 429 | return mDatabaseHelper.getAllLocations() 430 | .concatMap(new Func1>() { 431 | @Override 432 | public Observable call(Location location) { 433 | return mConcurService.getLocation(location.id); 434 | } 435 | }) 436 | .retry(new Func2() { 437 | @Override 438 | public Boolean call(Integer numRetries, Throwable throwable) { 439 | return throwable instanceof RetrofitError; 440 | } 441 | }); 442 | } 443 | ``` 444 | 445 | ### 2.14 Date format 446 | 447 | Để format phần năm của ngày tháng dưới dạng `yyyy`, sử dụng `yyyy`. 448 | 449 | ## 3 XML style rules 450 | 451 | ### 3.1 Sử dụng thẻ tự đóng 452 | 453 | Khi một phần tử XML không có nội dung, bạn cần phải tự đóng thẻ 454 | 455 | Nên: 456 | 457 | ```xml 458 | 459 | 463 | 464 | ``` 465 | 466 | Không nên 467 | 468 | ```xml 469 | 470 | 474 | 475 | 476 | ``` 477 | 478 | ### 3.2 Đặt tên resources 479 | 480 | Resource IDs và tên cần khai báo theo lowercase_underscore 481 | 482 | #### 3.2.1 Đặt tên ID 483 | 484 | Các ID nên bắt đầu bằng tên phần tử và chữ thường gạch chân. Ví dụ: 485 | 486 | | Element | Prefix | 487 | | ----------------- | ----------------- | 488 | | `TextView` | `text_` | 489 | | `ImageView` | `image_` | 490 | | `Button` | `button_` | 491 | | `Menu` | `menu_` | 492 | | `RelativeLayout` | `relative_` | 493 | | `LinearLayout ` | `linear_` | 494 | 495 | 496 | Ví dụ ImageView: 497 | 498 | ```xml 499 | 500 | 504 | 505 | 506 | ``` 507 | 508 | Trong một số trường hợp bạn sử dụng thư viện `annotation` thì bạn có thể khai báo như là khai báo biến 509 | 510 | 511 | ```xml 512 | 513 | 517 | 518 | 519 | ``` 520 | 521 | Đôi khi trong một trường hợp cố định nào đó ta có thể loại bỏ __Action và Tên Object__ 522 | 523 | Ví dụ dưới đây về một list item (từ gói thư viện hỗ trợ của Android) 524 | 525 | ```java 526 | 527 | 538 | 549 | 550 | 559 | ``` 560 | 561 | 562 | #### 3.2.2 Strings 563 | 564 | Tên chuối bắt đầu bằng một định danh. Ví dụ `registration_email_hint` hoặc `registration_name_hint`. 565 | Hoặc nếu không thì theo quy luật sau: 566 | 567 | | Tiền tố | Mô tả | 568 | | ----------------- | --------------------------------------| 569 | | `error_` | Cho thông báo lỗi | 570 | | `msg_` | Cho một thông báo or in nhắn | 571 | | `title_` | Cho tiêu đề, vd tiêu đề dialog, activity | 572 | | `action_` | Hành vi như `Lưu`, `Sửa` , `Xóa` | 573 | 574 | #### 3.2.3 Styles and Themes 575 | 576 | Khai báo theo kiểu __UpperCamelCase__. 577 | 578 | #### 3.2.4 Thứ tự thuộc tính 579 | 580 | Như một quy luật chung thì bạn nên nhóm các thuộc tính giống nhau lại. 581 | 582 | 1. View Id 583 | 2. Style 584 | 3. Layout width and layout height 585 | 4. Other layout attributes, sorted alphabetically 586 | 5. Remaining attributes, sorted alphabetically 587 | -------------------------------------------------------------------------------- /vn/android/others.md: -------------------------------------------------------------------------------- 1 | # Một số quy tắc khác 2 | 3 | Dưới dây là một số quy tắc khác, giúp các bạn tham khảo thêm 4 | 5 | ### 1. Sử dụng Short IF 6 | 7 | Không nên: 8 | 9 | ```java 10 | public boolean isEmulator(){ 11 | if(someThing){ 12 | return true; 13 | }else{ 14 | return false; 15 | } 16 | } 17 | ``` 18 | 19 | Nên sử dụng: 20 | 21 | ```java 22 | public boolean isEmulator(){ 23 | return someThing ? true : false; 24 | } 25 | ``` 26 | -------------------------------------------------------------------------------- /vn/android/standard.md: -------------------------------------------------------------------------------- 1 | # Cấu trúc của một Dự Án 2 | 3 | #### Base Application 4 | * ui 5 | * fragment 6 | * activity 7 | * dialog 8 | * widget 9 | * adapter 10 | * service 11 | * data 12 | * remote 13 | * local 14 | * model 15 | * util 16 | 17 | ## 1. Cách đặt tên files 18 | 19 | ### 1.1 Class files 20 | 21 | Tên class phải được viết theo kiểu [UpperCamelCase](https://en.wikipedia.org/wiki/CamelCase) 22 | 23 | Đối với những lớp mở rộng trong Android thì tên của class nên kết thúc bằng tên của lớp mở rộng đó 24 | 25 | Ví dụ: LoginActivity, MainActivity, UserController, WeatherService, SiginInDialog.... 26 | 27 | ### 1.2 Tên file tài nguyên 28 | 29 | Được đặt theo định dạnh : lowercase_underscore 30 | 31 | #### 1.2.1 Tên file Drawables 32 | 33 | Quy ước cho tên cho Drawables: 34 | 35 | 36 | | Kiểu | Tiếp đầu ngữ | Ví dụ | 37 | |--------------| ------------------|-----------------------------| 38 | | Action bar | `ab_` | `ab_stacked.9.png` | 39 | | Button | `btn_` | `btn_send_pressed.9.png` | 40 | | Dialog | `dialog_` | `dialog_top.9.png` | 41 | | Divider | `divider_` | `divider_horizontal.9.png` | 42 | | Icon | `ic_` | `ic_star.png` | 43 | | Menu | `menu_ ` | `menu_submenu_bg.9.png` | 44 | | Notification | `notification_` | `notification_bg.9.png` | 45 | | Tabs | `tab_` | `tab_pressed.9.png` | 46 | 47 | Quy ước cho tên cho Icon (Theo [Android iconography guidelines](http://developer.android.com/design/style/iconography.html)): 48 | 49 | | Kiểu | Tiếp đầu ngữ | Ví dụ | 50 | | --------------------------------| ---------------- | ---------------------------- | 51 | | Icons | `ic_` | `ic_star.png` | 52 | | Launcher icons | `ic_launcher` | `ic_launcher_calendar.png` | 53 | | Menu icons and Action Bar icons | `ic_menu` | `ic_menu_archive.png` | 54 | | Status bar icons | `ic_stat_notify` | `ic_stat_notify_msg.png` | 55 | | Tab icons | `ic_tab` | `ic_tab_recent.png` | 56 | | Dialog icons | `ic_dialog` | `ic_dialog_info.png` | 57 | 58 | Tên cho selector states: 59 | 60 | | Trạng thái | Tiếp vị ngữ | Ví dụ | 61 | |--------------|-----------------|-----------------------------| 62 | | Normal | `_normal` | `btn_order_normal.9.png` | 63 | | Pressed | `_pressed` | `btn_order_pressed.9.png` | 64 | | Focused | `_focused` | `btn_order_focused.9.png` | 65 | | Disabled | `_disabled` | `btn_order_disabled.9.png` | 66 | | Selected | `_selected` | `btn_order_selected.9.png` | 67 | 68 | 69 | #### 1.2.2 Tên Layout 70 | 71 | Áp dụng cấu trúc Type _object _ purpose. Tên file phải chứa tên thành phần Android, và nó đặt đầu tiên của tên Files. Ví dụ Tên file layout của `LoginActivity` sẽ là `activity_login.xml` 72 | 73 | | Thành phần | Tên lớp | Tên layout | 74 | | ---------------- | ---------------------- | ----------------------------- | 75 | | Activity | `UserProfileActivity` | `activity_user_profile.xml` | 76 | | Fragment | `SignUpFragment` | `fragment_sign_up.xml` | 77 | | Dialog | `ChangePasswordDialog` | `dialog_change_password.xml` | 78 | | AdapterView item | --- | `item_person.xml` | 79 | | Partial layout | --- | `partial_stats_bar.xml` | 80 | 81 | #### 1.2.3 Menu files 82 | 83 | Vì menu không chứa các thành phần Android nên để đặt tên Menu cần nên đặt tên theo màn hình sử dụng. Ví dụ trong ``MainActivity` thì tên file menu sẽ là `activity_main.xml` 84 | 85 | Chú ý rằng tên file không cần bao goome `menu` vì file đã được chứa trong thư mục `menu` 86 | 87 | #### 1.2.4 Values files 88 | 89 | Tên tập tin nên có thêm __số nhiều__. Ví dụ `strings.xml`, `styles.xml`, `colors.xml`, `dimens.xml`, `attrs.xml` 90 | -------------------------------------------------------------------------------- /vn/git/flow.md: -------------------------------------------------------------------------------- 1 | ## Framgia Git flow 2 | 3 | Flow tham khảo: [A successful Git branching model](http://nvie.com/posts/a-successful-git-branching-model/) 4 | 5 | ### Giả định 6 | * Đã tạo Central Repository (Nguồn trung tâm) trên Github(hoặc Bitbucket). 7 | * Branch mặc định của Central Repository là master. 8 | * Lập trình viên có thể fork (tạo nhánh) đối với Central Repository. 9 | * Đã quyết định người review và người có quyền merge. 10 | 11 | ### Nguyên tắc 12 | * Mỗi pull-request tương ứng với một ticket. 13 | * Mỗi một pull-request không hạn chế số lượng commit 14 | * Pull-request title phải đặt sao cho tương ứng với title của task với format `refs [Loại ticket] #[Số ticket] [Nội dung ticket]` (Ví dụ: `refs bug #1234 Sửa lỗi cache`). 15 | * Đối với commit title, trong trường hợp pull-request đó chỉ có 1 commit thì có thể đặt commit title tương tự như trên là `refs [Loại ticket] #[Số ticket] [Nội dung ticket]` (Ví dụ: `refs bug #1234 Sửa lỗi cache`).\ 16 | Tuy nhiên với trường hợp 1 ppull-request có chứa nhiêù commit thì cần phải ghi rõ trong nội dung commit title là trong commit đó xử lý đối ứng vấn đề gì. 17 | * Ví dụ: 18 | 1. Pull-request title: `refs bug #1234 Sửa lỗi cache` 19 | 2. Trong trường hợp pull-request có 2 commit thì nội dung commit title của 2 commit sẽ tương ứng như sau 20 | * `Tạo method thực hiện việc clear cache trong Model` 21 | * `Tại controller gọi method ở Model để thực hiện việc clear cache` 22 | * Gitflow đến thời điểm 2018/03/28 có quy định là 1 pull-request chỉ một commit sẽ không còn hiệu lực nữa. Tuy nhiên với các dự án mà teamsize lớn hơn 10 người thì để nhằm mục đích cho thuận tiện cho việc confirm thì khuyến khích dùng squash and merge . 23 | * Ngoài ra thì với gitflow trước đây ( trước thời điểm 2018/03/28) thì có cho phép dùng force push, tuy nhiên do khi sử dụng force push sẽ xoá hết lịch sử thay đổi do vậy gitlow hiện tại không khuyến khích sử dụng force push. Trong trường hợp cần sử dụng force push thì cần có sự đồng thuận từ team. 24 | * Tại môi trường local(trên máy lập trình viên), tuyệt đối không được thay đổi code khi ở branch master.Nhất định phải thao tác trên branch khởi tạo để làm task. 25 | 26 | ### Chuẩn bị 27 | 28 | 1. Trên Github (Bitbucket), fork Central Repository về tài khoản của mình(repository ở tài khoản của mình sẽ được gọi là Forked Repository). 29 | 30 | 2. Clone (tạo bản sao) Forked Repository ở môi trường local.Tại thời điểm này, Forked Repository sẽ được tự động đăng ký dưới tên là `origin`. 31 | ```sh 32 | $ git clone [URL của Forked Repository] 33 | ``` 34 | 35 | 3. Truy cập vào thư mục đã được tạo ra sau khi clone, đăng ký Central Repository dưới tên `upstream`. 36 | ```sh 37 | $ cd [thư mục được tạo ra] 38 | $ git remote add upstream [URL của Central Repository] 39 | ``` 40 | 41 | ### Quy trình 42 | 43 | Từ đây, Central Repository và Forked Repository sẽ được gọi lần lượt là `upstream` và `origin`. 44 | 45 | 1. Đồng bộ hóa branch master tại local với upstream. 46 | ```sh 47 | $ git checkout master 48 | $ git pull upstream master 49 | ``` 50 | 51 | 2. Tạo branch để làm task từ branch master ở local. Tên branch là số ticket của task(Ví dụ: `task/1234`). 52 | ```sh 53 | $ git checkout master # <--- Không cần thiết nếu đang ở trên branch master 54 | $ git checkout -b task/1234 55 | ``` 56 | 57 | 3. Tiến hành làm task(Có thể commit bao nhiêu tùy ý). 58 | 59 | 4. Push code lên origin. 60 | 61 | ```sh 62 | $ git push origin task/1234 63 | ``` 64 | 65 | 5. Tại origin trên Github(Bitbucket)、từ branch `task/1234` đã được push lên hãy gửi pull-request đối với branch master của upstream. 66 | 67 | 6. Hãy gửi link URL của trang pull-request cho reviewer trên chatwork để tiến hành review code. 68 | 69 | 6.1. Trong trường hợp reviewer có yêu cầu sửa chữa, hãy thực hiện các bước 3. 〜 5.. 70 | 6.2. Tiếp tục gửi lại URL cho reviewer trên chatwork để tiến hành việc review code. 71 | 72 | 7. Nếu trên 2 người reviewer đồng ý với pull-request, người reviewer cuối cùng sẽ thực hiện việc merge pull-request. 73 | Revewer xác nhận sự đồng ý bằng comment LGTM. 74 | 75 | 8. Quay trở lại 1. 76 | 77 | 78 | ### Đối với dự án áp dụng quy định tương ứng với 1 pull-request chỉ cho phép 1 commit 79 | 80 | Từ đây, Central Repository và Forked Repository sẽ được gọi lần lượt là `upstream` và `origin`. 81 | 82 | 1. Đồng bộ hóa branch master tại local với upstream. 83 | ```sh 84 | $ git checkout master 85 | $ git pull upstream master 86 | ``` 87 | 88 | 2. Tạo branch để làm task từ branch master ở local. Tên branch là số ticket của task(Ví dụ: `task/1234`). 89 | ```sh 90 | $ git checkout master # <--- Không cần thiết nếu đang ở trên branch master 91 | $ git checkout -b task/1234 92 | ``` 93 | 94 | 3. Tiến hành làm task(Có thể commit bao nhiêu tùy ý). 95 | 96 | 4. Trường hợp đã tạo nhiều commit trong quá trình làm task、tại 5. trước khi push phải dùng rebase -i để hợp các commit lại thành 1 commit duy nhất. 97 | ```sh 98 | $ git rebase -i [Giá trị hash của commit trước commit đầu tiên trong quá trình làm task] 99 | ``` 100 | 101 | 5. Quay trở về branch master ở local và lấy code mới nhất về 102 | 103 | ```sh 104 | $ git checkout master 105 | $ git pull upstream master 106 | ``` 107 | 108 | 6. Quay trở lại branch làm task, sau đó rebase với branch master. 109 | 110 | ```sh 111 | $ git checkout task/1234 112 | $ git rebase master 113 | ``` 114 | **Trường hợp xảy ra conflict trong quá trình rebase、hãy thực hiện các thao tác của mục「Khi xảy ra conflict trong quá trình rebase」.** 115 | 116 | 7. Push code lên origin. 117 | 118 | ```sh 119 | $ git push origin task/1234 120 | ``` 121 | 122 | 8. Tại origin trên Github(Bitbucket)、từ branch `task/1234` đã được push lên hãy gửi pull-request đối với branch master của upstream. 123 | 124 | 9. Hãy gửi link URL của trang pull-request cho reviewer trên chatwork để tiến hành review code. 125 | 126 | 9.1. Trong trường hợp reviewer có yêu cầu sửa chữa, hãy thực hiện các bước 3. 〜 6. 127 | 128 | 9.2 push -f (push đè hoàn toàn lên code cũ) đối với remote branch làm task. 129 | ```sh 130 | $ git push origin task/1234 -f 131 | ``` 132 | 133 | 9.3 Tiếp tục gửi lại URL cho reviewer trên chatwork để tiến hành việc review code. 134 | 135 | 10. Nếu trên 2 người reviewer đồng ý với pull-request, người reviewer cuối cùng sẽ thực hiện việc merge pull-request. 136 | Revewer xác nhận sự đồng ý bằng comment LGTM. 137 | 138 | 11. Quay trở lại 1. 139 | 140 | #### Khi xảy ra conflict trong quá trình rebase 141 | 142 | Khi xảy ra conflict trong quá trình rebase, sẽ có hiển thị như dưới đây (tại thời điểm này sẽ bị tự động chuyển về một branch vô danh) 143 | ```sh 144 | $ git rebase master 145 | First, rewinding head to replay your work on top of it... 146 | Applying: refs #1234 Sửa lỗi cache 147 | Using index info to reconstruct a base tree... 148 | Falling back to patching base and 3-way merge... 149 | Auto-merging path/to/conflicting/file 150 | CONFLICT (add/add): Merge conflict in path/to/conflicting/file 151 | Failed to merge in the changes. 152 | Patch failed at 0001 refs #1234 Sửa lỗi cache 153 | The copy of the patch that failed is found in: 154 | /path/to/working/dir/.git/rebase-apply/patch 155 | 156 | When you have resolved this problem, run "git rebase --continue". 157 | If you prefer to skip this patch, run "git rebase --skip" instead. 158 | To check out the original branch and stop rebasing, run "git rebase --abort". 159 | ``` 160 | 161 | 1. Hãy thực hiện fix lỗi conflict thủ công(những phần được bao bởi <<< và >>> ). 162 | Trong trường hợp muốn dừng việc rebase lại, hãy dùng lệnh `git rebase --abort`. 163 | 164 | 2. Khi đã giải quyết được tất cả các conflict, tiếp tục thực hiện việc rebase bằng: 165 | 166 | ```sh 167 | $ git add . 168 | $ git rebase --continue 169 | ``` 170 | -------------------------------------------------------------------------------- /vn/php/PSR-1.md: -------------------------------------------------------------------------------- 1 | Basic Coding Standard 2 | ===================== 3 | 4 | Chương này của bộ standard bao gồm những yếu tố cơ bản được đòi hỏi để có thể đảm bảo 5 | tính tương kết giữa code PHP được chia sẻ. 6 | 7 | [PSR-0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md 8 | [PSR-4]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md 9 | 10 | 1. Khái quát chung 11 | ----------- 12 | 13 | - Files chỉ được sử dụng tag là `` hoặc short-echo `` tags. 36 | Ngoài ra không được sử dụng những tag thay đổi khác. (Không dùng tag ``) 37 | 38 | ### 2.2. Character Encoding 39 | 40 | PHP code phải được encode bằng UTF-8 không có BOM. 41 | 42 | ### 2.3. Side Effects 43 | 44 | Files có thể định nghĩa symbols (classes, functions, constants, etc.), 45 | hoặc gây ra side-effects (e.g. tạo ra output, thay đổi .ini settings, etc.), 46 | thế nhưng không nên làm cả 2. 47 | 48 | Cụm từ "side effects" mang ý nghĩa là thực hiện những logic mà không liên quan 49 | trực tiếp đến việc định nghĩa classes, functions, constants ... *thường là từ 50 | việc including file* 51 | 52 | 53 | "Side effects" bao gồm những việc sau (không phải là tất cả): tạo output, sử dụng `require` `include`, hoặc 54 | kết nối đến external services, thay đổi file ini setting, emit errors hay exceptions, 55 | chỉnh sửa biến global hay static, đọc và viết file ... 56 | 57 | Dưới đây là một ví dụ về việc một file chứa cả declarations (định nghĩa) và side effects; 58 | 59 | ```php 60 | \n"; 69 | 70 | // declaration 71 | function foo() 72 | { 73 | // function body 74 | } 75 | ``` 76 | 77 | Dưới đây là ví dụ về một file chỉ bao gồm declarations mà không có side effects 78 | 79 | ```php 80 | $b) { 62 | $foo->bar($arg1); 63 | } else { 64 | BazClass::bar($arg2, $arg3); 65 | } 66 | } 67 | 68 | final public static function bar() 69 | { 70 | // method body 71 | } 72 | } 73 | ``` 74 | 75 | 2. Tổng thể 76 | ---------- 77 | 78 | ### 2.1 Basic Coding Standard 79 | 80 | Code phải tuân theo "coding style guide" PSR [[PSR-1]]. 81 | 82 | ### 2.2 Files 83 | 84 | Mọi PHP files phải dùng Unix LF (linefeed) line ending. 85 | 86 | Mọi PHP files phải kết thúc bằng một dòng trống. 87 | 88 | Trong một file chỉ bao gồm code PHP thì không được viết tag đóng `?>`. 89 | 90 | ### 2.3. Lines 91 | 92 | Không có hard limit về độ dài của một dòng. 93 | 94 | Soft limit của độ dài một dòng phải là 120 chữ. Chương trình check style tự động phải báo warning nhưng không được báo 95 | error khi vượt quá soft limit. 96 | 97 | Một dòng nên có không quá 80 chữ. Dòng mà dài quá 80 chữ thì nên chia nhỏ ra thành nhiều dòng với độ dài mỗi dòng 98 | không quá 80 chữ. 99 | 100 | Một dòng không trống không được phép có trailing whitespace (dấu cách ở cuối dòng) 101 | 102 | Dòng trống có thể được thêm vào để code có thể được dễ đọc hơn và để phân cách những đoạn code. 103 | 104 | Không được phép có quá một statement trên một dòng. 105 | 106 | ### 2.4. Canh lề - Indenting 107 | 108 | Code không dùng tab, mà phải sử dụng 4 dấu cách làm indent. 109 | 110 | ### 2.5. Keywords và True/False/Null 111 | 112 | Những [keywords] của PHP phải được viết thường. (không viết hoa) 113 | 114 | Những constants của PHP là `true`, `false`, và `null` cũng cần phải viết thường. 115 | 116 | [keywords]: http://php.net/manual/en/reserved.keywords.php 117 | 118 | 119 | 3. Khai báo Namespace và Use 120 | --------------------------------- 121 | 122 | Cần phải có một dòng trắng phía sau khai báo `namespace`. 123 | 124 | Những phần khai báo `use` phải được đặt phía sau phần khai báo `namespace`. 125 | 126 | Phải dùng một từ `use` cho mỗi khao báo. 127 | 128 | Phải có một dòng trắng phía sau đoạn code `use`. 129 | 130 | Ví dụ: 131 | 132 | ```php 133 | bar($arg1); 315 | Foo::bar($arg2, $arg3); 316 | ``` 317 | 318 | Danh sách argument có thể được tách ra thành nhiều dòng, trong đó mỗi dòng theo sau được indent một lần. 319 | Khi làm như vậy thì argument đầu tiên phải được đặt trên một dòng mới, và mỗi dòng chỉ được phép chứa một argument. 320 | 321 | ```php 322 | bar( 324 | $longArgument, 325 | $longerArgument, 326 | $muchLongerArgument 327 | ); 328 | ``` 329 | 330 | 5. Control Structures 331 | --------------------- 332 | 333 | Những quy tắc chung khi viết Control Structures bao gồm: 334 | 335 | - Phải có một khoảng trắng sau control structure keyword 336 | - Không được có một khoảng trắng sau dấu mở ngoặc tròn 337 | - Không được có một khoảng trắng trước dấu đóng ngoặc tròn 338 | - Phải có một khoảng trắng sau đấu đóng ngoặc tròn và trước dấu mở ngoặc nhọn 339 | - Phần thân của structure phải được indent một lần 340 | - Dấu đóng ngoặc nhọn phỉa được đặt trên một dòng mới sau phần thân 341 | 342 | Phần thân của mỗi structure phải được đặt trong dấu đóng mở ngoặc kép. Điều này sẽ làm tiêu chuẩn hoá cách viết structures, 343 | và làm giảm thiểu việc phát sinh ra lỗi khi mà có những dòng mới được thêm vào phần thân. 344 | 345 | ### 5.1. `if`, `elseif`, `else` 346 | 347 | Một `if` structure được viết như sau. 348 | Hãy chú ý đến vị trí của dấu ngoặc tròn, khoảng trắng, dấu ngoặc nhọn. `else` và `elseif` được đặt trên cùng một dòng 349 | với dấu đóng ngoặc nhọn của phần body phía trước. 350 | 351 | ```php 352 | `, dấu ngoặc tròn, khoảng trắng và dấu ngoặc nhọn. 431 | 432 | ```php 433 | $value) { 435 | // foreach body 436 | } 437 | ``` 438 | 439 | ### 5.6. `try`, `catch` 440 | 441 | Một block `try catch` được viết như sau. 442 | Hãy chú ý vào vị trí của dấu ngoặc tròn, khoảng trắng và dấu ngoặc nhọn. 443 | 444 | ```php 445 | bar( 549 | $arg1, 550 | function ($arg2) use ($var1) { 551 | // body 552 | }, 553 | $arg3 554 | ); 555 | ``` 556 | 557 | 558 | 7. Kết luận 559 | -------------- 560 | 561 | Có rất nhiều yếu tố về style hay practice khác được cố tình bỏ qua trong hướng dẫn này. Có thể kể ra như: 562 | 563 | - Khai báo biến global (global variables) hay hằng global (global constants) 564 | 565 | - Khai báo hàm (functions) 566 | 567 | - Toán tử và phép gán 568 | 569 | - Inter-line alignment 570 | 571 | - Khối Comments và Documentation 572 | 573 | - Tiền tố và hậu tố trong tên Class 574 | 575 | - Best practices 576 | 577 | Những recommendations sau này có thể xem xét lại và mở rộng hướng dẫn này để đề cập đến những yếu tố về style hay practice 578 | ở trên hay hoàn toàn khác. 579 | -------------------------------------------------------------------------------- /vn/php/others.md: -------------------------------------------------------------------------------- 1 | Một số quy tắc khác 2 | ===================== 3 | 4 | Dưới đây là một số các quy tắc khác, không được quy định cụ thể trong các bộ PSR. 5 | 6 | - Sử dụng phiên bản PHP mới nhất nếu có thể. 7 | - Khi khai báo mảng, các phần tử của mảng có thể được tách thành nhiều dòng. Khi làm vậy thì cần phải tuân thủ các quy tắc sau: 8 | - Phần từ đầu tiên của mảng phải được đặt trên một dòng mới. 9 | - Mỗi dòng chỉ được phép có một phần tử, các phần tử được indent một lần. 10 | - Cần phải có dấu phẩy ở cuối phần tử cuối cùng. 11 | - Dấu kết thúc khai báo mảng (`]` đối với `[]` hay `)` đối với `array()`) phải được đặt trên một dòng mới. 12 | 13 | ```php 14 | // Bad 15 | $a = [$foo, 16 | $bar 17 | ]; 18 | 19 | // Bad 20 | $a = [ 21 | $foo, $bar, 22 | $baz, 23 | ]; 24 | 25 | // Bad 26 | $a = [ 27 | $foo, 28 | $bar 29 | ]; 30 | 31 | // Bad 32 | $a = [ 33 | $foo, 34 | $bar,]; 35 | 36 | // Bad 37 | $a = [$foo, $bar,]; 38 | 39 | // Good 40 | $a = [ 41 | $foo, 42 | $bar, 43 | ]; 44 | 45 | $a = [$foo, $bar]; 46 | ``` 47 | 48 | - Với phiên bản PHP >= 5.4, hãy sử dụng `[]` để khai báo array, thay vì dùng `array()` 49 | ```php 50 | // Good 51 | $a = []; 52 | $b = [ 53 | $key => $value, 54 | $key2 => $value2, 55 | ]; 56 | 57 | // Bad 58 | $a = array(); 59 | $b = array( 60 | $key => $value, 61 | $key2 => $value2, 62 | ); 63 | ``` 64 | 65 | - Tên biến được viết dưới dạng `camelCase`. Đối với tên property bên trong Model thì 66 | có thể viết dưới dạng `snake_case` cho phù hợp với tên của các cột trong các bảng của Database. 67 | - Sử dụng dấu `'` đối với một string bình thường. Chỉ dùng `"` khi bên trong có khai triển biến PHP. 68 | ```php 69 | $normalString = 'A String'; 70 | $specialString = "This is {$normalString}"; 71 | ``` 72 | - Cần có 1 space trước và sau các toán tử như `+`, `-`, `*`, `/`, `.`, `>`, `<`, `==` ... 73 | - Để format phần năm của ngày tháng dưới dạng `yyyy`, sử dụng `Y`. 74 | -------------------------------------------------------------------------------- /vn/rails/gems.md: -------------------------------------------------------------------------------- 1 | # Danh sách các gem kiểu chuẩn trong Ruby on Rails 2 | 3 | Một trong những nguyên tắc quan trọng nhất khi lập trình đó là "Don't Repeat Yourself!". Khi phải đối mặt với vấn đề gì đấy thì trước khi bản thân giải quết vấn đề đó cần phải tìm hiểu xem tồn tại những cách giải quyết nào. Dưới đây là danh sách những gem rất có giá trị, những cái có ích trong rất nhiều dự án Rails. Tất cả đều hoạt động đối với Rails 3.1. 4 | 5 | ## Việc tạo màn hình quản lý 6 | 7 | * [active_admin](https://github.com/gregbell/active_admin) - Giúp tạo màn hình quản lý một cách đơn giản. Ngoài ra cũng có thể nhanh chóng tạo ra các xử lý CRUD của các model và có thể tuỳ chỉnh một cách linh hoạt. 8 | 9 | ## Môi trường phát triển, cải thiện môi trường test 10 | 11 | **Chú ý: điều này không phù hợp vớ môi trường production** 12 | 13 | * [capybara](https://github.com/jnicklas/capybara) - Là gem giúp cho dễ dàng thực hiện integration test trong các web framework mà là ứng dụng Rack như Rails, Sinatra hay Merb. Giúp mô phỏng các thao tác của người dùng thực tế trong ứng dụng web. Hỗ trợ Rack::Test và Selenium được cài đặt sẵn. Có thể sử dụng HtmlUnit, Webkit, env.js bằng việc cài thêm gem. Việc có thể sử dụng đồng thời RSpec và Cucumber là rất có lợi. 14 | 15 | * [better_errors](https://github.com/charliesome/better_errors) - Là gem giúp thay thế trang thông báo lỗi kiểu chuẩn bằng một kiểu tiện lợi hơn. Ngoài ra có thể sử dụng như là Rack middleware trong các ứng dụng Rack khác ngoài Rails. 16 | 17 | * [cucumber-rails](https://github.com/cucumber/cucumber-rails) - Là công cụ rất tốt để thực hiện integration test trong Ruby. Việc sử dụng cucumber-rails sẽ giúp chúng ta có thể dùng Cucumber trong Rails. 18 | 19 | * [factory_girl](https://github.com/thoughtbot/factory_girl) - Giúp tạo các object phục vụ cho các nhiệm vụ như test chẳng hạn. 20 | 21 | * [ffaker](https://github.com/EmmanuelOga/ffaker) - Giúp tạo dữ liệu mẫu một cách đơn giản. 22 | 23 | * [guard](https://github.com/guard/guard) - Có thể theo dõi sự thay đổi của file và tự động thực hiện các nhiệm vụ. Được sử dụng trong rất nhiều cộng cụ. 24 | 25 | * [spork](https://github.com/sporkrb/spork) - Một DRb server cho testing framework như RSpec hay Cucumber, sẽ giúp chuẩn bị để có thể test trong điều kiện tốt. Bằng việc load trước môi trường test nên giúp rút ngắn khá nhiều thời gian test. 26 | 27 | * [simplecov](https://github.com/colszowka/simplecov) - Công cụ phân tích thông tin bao quát về code và có thể dùng với Ruby 1.9. 28 | 29 | * [rspec-rails](https://github.com/rspec/rspec-rails) - Giúp cho dễ dàng sử dụng RSpec trong Rails. 30 | 31 | ## Cải thiện hiệu năng 32 | 33 | * [bullet](https://github.com/flyerhzm/bullet) - Được thiết kế để giúp tăng hiệu năng của ứng dụng bằng việc giảm số query. Nó sẽ theo dõi nhưng câu query của bạn trong quá trình phát triển và chỉ ra nơi nên thêm eager loading (N+1 queries), hoặc nơi không cần thiết eager loading hoặc nên sử dụng counter cache. 34 | 35 | ## Upload file 36 | 37 | * [Paperclip](https://github.com/thoughtbot/paperclip) - Có thể đính file trong ActiveRecord. 38 | 39 | ## Tìm kiếm text 40 | 41 | * [sunspot](https://github.com/sunspot/sunspot) - Hệ thống tìm kiếm text sử dụng SOLR. 42 | 43 | ## Quản lý phân quyền 44 | 45 | * [cancan](https://github.com/ryanb/cancan) - Có thể giới hạn khả năng truy cập tài nguyên của người dùng. Tất cả quyền hạn thì được quản lý trong một file và có thể xác thực trên toàn ứng dụng. 46 | 47 | * [devise](https://github.com/plataformatec/devise) - Hầu như đã chuẩn bị sẵn hết tất cả chức năng cần thiết. 48 | 49 | ## View template 50 | 51 | * [haml-rails](https://github.com/indirect/haml-rails) - Giúp có thể sử dụng HAML trong Rails. 52 | 53 | * [haml](http://haml-lang.com) - HAML được xem là ngôn ngữ template ngắn gọn hơn ERB. 54 | 55 | * [slim](http://slim-lang.com) - Slim không chỉ hơn ERB mà còn được cho rằng tốt hơn cả HAML. Lý do ngần ngại sử dụng Slim có chăng chỉ là chưa được hỗ trợ bởi nhiều editor hay IDE. Ngoài ra, hiệu năng của Slim khá là tốt. 56 | 57 | ## Hỗ trợ phía client 58 | 59 | * [client_side_validations](https://github.com/bcardarella/client_side_validations) - Tự động tạo ra validation của Javascript chạy trên client dựa trên các validation của các model định nghĩa tại server. 60 | 61 | ## SEO 62 | 63 | * [friendly_id](https://github.com/norman/friendly_id) - Giúp có thể chỉ định các object thông qua các thuộc tính được miêu tả dễ hiểu thay cho id của model. 64 | 65 | ## Phân trang 66 | 67 | * [kaminari](https://github.com/amatsuda/kaminari) - giúp phân trang một cách linh hoạt. 68 | 69 | ## Chỉnh sửa ảnh 70 | 71 | * [minimagick](https://github.com/probablycorey/mini_magick) - Ruby wrapper của ImageMagick 72 | 73 | ##(Chưa quết định xem có là gem kiểu chuẩn không) 74 | 75 | * [simplecov-rcov](https://github.com/fguillen/simplecov-rcov) - Định dạng theo kiểu RCov cho SimpleCov. Hữu ích khi muốn sử dụng SimpleCov với Hudson continious integation server. 76 | 77 | * [carrierwave](https://github.com/jnicklas/carrierwave) - Giúp việc upload file đơn giản hơn trong Rails. Hỗ trợ cả lưu trữ local và cloud cho những file được upload ( và nhiều cái thú vị khác nữa). Ngoài ra nó còn tích hợp với ImageMagick giúp cho chúng ta có thể thêm các xử lý file ảnh. 78 | 79 | * [compass-rails](https://github.com/chriseppstein/compass) - Là gem khá tốt, nó thêm hỗ trợ cho một vài css framework. Bao gồm tập các sass mixin giúp rút ngắn code css và giúp xử lý việc không tương thích trình duyệt. 80 | 81 | * [fabrication](http://fabricationgem.org/) - Một trong những cái thay thế tốt cho fixtures. 82 | 83 | * [feedzirra](https://github.com/pauldix/feedzirra) - Giúp phân tích RSS/Atom khá nhanh và tiện lợi. 84 | 85 | * [globalize3](https://github.com/svenfuchs/globalize3.git) - Globalize3 là bản kế tiếp của Globalize trong Rails và nhắm tới ActiveRecord phiên bản 3.x. Nó tương thích và được xây dựng trên API I18n mới của Ruby on Rails và có thêm bộ dịch vào ActiveRecord. 86 | 87 | * [machinist](https://github.com/notahat/machinist) - Giúp dễ dàng tạo các object phục vụ cho test. 88 | 89 | * [simple_form](https://github.com/plataformatec/simple_form) - Một khi mà đã dùng simple_form thì sẽ không bao giờ muốn nghe đến form mặc định của Rails. 90 | . Nó có DSL khá tốt cho việc tạo form và không cần quan tâm đến markup. 91 | 92 | * [email-spec](https://github.com/bmabey/email-spec) - Dễ dàng thực hiện test email bằng RSpec hoặc Cucumber. 93 | 94 | ## Những gem không khuyến khích dùng 95 | 96 | Những gem này vần có lỗi hoặc là có những gem tốt hơn. Tốt nhất nên tránh dùng những gem này. 97 | 98 | * [rmagick](http://rmagick.rubyforge.org/) - Nên tránh dùng bởi vì nó sử dụng bộ nhớ một cách lãng phí. Thay vào đó ta nên dùng minimagick. 99 | 100 | * [autotest](http://www.zenspider.com/ZSS/Products/ZenTest/) - Công cụ test tự động. Nên dùng một gem tốt hơn đó là guard. 101 | 102 | * [rcov](https://github.com/relevance/rcov) - Không hỗ trợ Ruby 1.9. Thay vào đó ta nên dùng simplecov. 103 | 104 | * [therubyracer](https://github.com/cowboyd/therubyracer) - Không nên dùng vì nó dùng quá nhiều bộ nhớ. Chúng ta có thể cài đặt Node.js. 105 | -------------------------------------------------------------------------------- /vn/rails/references.md: -------------------------------------------------------------------------------- 1 | ## Các quy định về viết code Ruby on Rails (Các trang tham khảo) 2 | -------------------------------------------------------------------------------- /vn/ruby/references.md: -------------------------------------------------------------------------------- 1 | ## Các quy định về viết code Ruby(Các trang tham khảo) 2 | 3 | 4 | * [Ruby Styleguide](https://github.com/styleguide/ruby) 5 | * [Prelude](https://github.com/bbatsov/ruby-style-guide) 6 | * [Tóm tắt các quy định về viết code Ruby - bojovs::blog](http://bojovs.github.com/2012/04/24/ruby-coding-style/) 7 | -------------------------------------------------------------------------------- /vn/typescript/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/framgia/coding-standards/145f855b0f7f37fee4fd7d37f6c5deb0f87cfbc6/vn/typescript/README.md --------------------------------------------------------------------------------