├── .rspec ├── .haml-lint.yml ├── .rspec_parallel ├── .pronto.yml ├── product.md ├── LICENSE ├── .rubocop.yml ├── coffeelint.json ├── css.md └── README.md /.rspec: -------------------------------------------------------------------------------- 1 | --order rand 2 | --color 3 | --format progress 4 | -------------------------------------------------------------------------------- /.haml-lint.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | LineLength: 3 | max: 113 4 | -------------------------------------------------------------------------------- /.rspec_parallel: -------------------------------------------------------------------------------- 1 | --format progress 2 | --format ParallelTests::RSpec::RuntimeLogger --out reports/parallel_tests/runtime_rspec.log 3 | 4 | -------------------------------------------------------------------------------- /.pronto.yml: -------------------------------------------------------------------------------- 1 | all: 2 | exclude: [ 3 | vendor/assets/**/*, 4 | bin/*, 5 | db/schema.rb, 6 | db/migrate/* 7 | ] 8 | AllCops: 9 | TargetRubyVersion: 2.4.1 10 | -------------------------------------------------------------------------------- /product.md: -------------------------------------------------------------------------------- 1 | # Working with Clients 2 | 3 | * [Product strategy means saying no](https://blog.intercom.com/product-strategy-means-saying-no/) 4 | * Technical Debts: 5 | * [Ward Explains Debt Metaphor](http://wiki.c2.com/?WardExplainsDebtMetaphor) 6 | * [Video: Simplicity Matters by Rich Hickey](https://www.youtube.com/watch?v=rI8tNMsozo0&index=2&list=PLnBbQBvAzRj7eTqvZHHeoHGa2knP1l2wP) 7 | 8 | # Design Product 9 | 10 | * [Resources on GV Blog](https://library.gv.com/) 11 | 12 | # Schedule Development & Roadmaps 13 | 14 | * [Building Product Roadmaps](https://blog.intercom.com/mind-the-product-janna-bastow/) 15 | 16 | # Overall Product Owner Role 17 | 18 | * https://www.intercom.com/books/product-management 19 | 20 | # Team Playbooks 21 | 22 | * [The Atlassian Team Playbook](https://www.atlassian.com/team-playbook) 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 JetThoughts 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | TargetRubyVersion: 2.4 3 | 4 | # For now our code is not ready, but we should fix it soon 5 | Style/FrozenStringLiteralComment: 6 | Enabled: false 7 | 8 | Lint/HandleExceptions: 9 | Exclude: 10 | - 'bin/rails' 11 | - 'bin/rake' 12 | 13 | # Configuration parameters: AllowURI, URISchemes. 14 | ClassLength: 15 | Max: 150 16 | 17 | Metrics/LineLength: 18 | Max: 113 19 | 20 | Metrics/MethodLength: 21 | CountComments: false 22 | Max: 20 23 | 24 | Metrics/BlockLength: 25 | Exclude: 26 | - "**/*_spec.rb" 27 | 28 | Style/Documentation: 29 | Enabled: false 30 | 31 | Style/EmptyLines: 32 | Exclude: 33 | - 'config/environments/development.rb' 34 | 35 | Style/EmptyLinesAroundBlockBody: 36 | Exclude: 37 | - 'db/schema.rb' 38 | 39 | Style/StringLiterals: 40 | Exclude: 41 | - 'db/schema.rb' 42 | 43 | Style/ExtraSpacing: 44 | Exclude: 45 | - 'config/environments/development.rb' 46 | 47 | Style/PredicateName: 48 | Exclude: 49 | - 'app/helpers/application_helper.rb' 50 | 51 | Style/ClassAndModuleChildren: 52 | EnforcedStyle: nested 53 | SupportedStyles: 54 | - nested 55 | - compact 56 | Exclude: 57 | - 'app/controllers/**/*.rb' 58 | 59 | Style/MultilineOperationIndentation: 60 | EnforcedStyle: indented 61 | 62 | Style/MultilineMethodCallIndentation: 63 | EnforcedStyle: indented_relative_to_receiver 64 | 65 | Style/AlignParameters: 66 | EnforcedStyle: with_fixed_indentation 67 | 68 | Lint/EndAlignment: 69 | EnforcedStyleAlignWith: variable 70 | 71 | Style/SafeNavigation: 72 | Enabled: false 73 | 74 | Style/AlignHash: 75 | EnforcedHashRocketStyle: key 76 | EnforcedColonStyle: key 77 | EnforcedLastArgumentHashStyle: always_inspect 78 | 79 | Style/MultilineMethodCallIndentation: 80 | EnforcedStyle: indented 81 | 82 | Style/NegatedIf: 83 | Enabled: false 84 | 85 | Style/GuardClause: 86 | Enabled: false 87 | -------------------------------------------------------------------------------- /coffeelint.json: -------------------------------------------------------------------------------- 1 | { 2 | "arrow_spacing": { 3 | "level": "ignore" 4 | }, 5 | "braces_spacing": { 6 | "level": "ignore", 7 | "spaces": 0, 8 | "empty_object_spaces": 0 9 | }, 10 | "camel_case_classes": { 11 | "level": "error" 12 | }, 13 | "coffeescript_error": { 14 | "level": "error" 15 | }, 16 | "colon_assignment_spacing": { 17 | "level": "ignore", 18 | "spacing": { 19 | "left": 0, 20 | "right": 0 21 | } 22 | }, 23 | "cyclomatic_complexity": { 24 | "level": "ignore", 25 | "value": 10 26 | }, 27 | "duplicate_key": { 28 | "level": "error" 29 | }, 30 | "empty_constructor_needs_parens": { 31 | "level": "ignore" 32 | }, 33 | "ensure_comprehensions": { 34 | "level": "warn" 35 | }, 36 | "eol_last": { 37 | "level": "ignore" 38 | }, 39 | "indentation": { 40 | "value": 2, 41 | "level": "error" 42 | }, 43 | "line_endings": { 44 | "level": "ignore", 45 | "value": "unix" 46 | }, 47 | "max_line_length": { 48 | "value": 113, 49 | "level": "warn", 50 | "limitComments": true 51 | }, 52 | "missing_fat_arrows": { 53 | "level": "ignore", 54 | "is_strict": false 55 | }, 56 | "newlines_after_classes": { 57 | "value": 3, 58 | "level": "ignore" 59 | }, 60 | "no_backticks": { 61 | "level": "error" 62 | }, 63 | "no_debugger": { 64 | "level": "warn", 65 | "console": false 66 | }, 67 | "no_empty_functions": { 68 | "level": "ignore" 69 | }, 70 | "no_empty_param_list": { 71 | "level": "ignore" 72 | }, 73 | "no_implicit_braces": { 74 | "level": "ignore", 75 | "strict": true 76 | }, 77 | "no_implicit_parens": { 78 | "level": "ignore", 79 | "strict": true 80 | }, 81 | "no_interpolation_in_single_quotes": { 82 | "level": "ignore" 83 | }, 84 | "no_nested_string_interpolation": { 85 | "level": "warn" 86 | }, 87 | "no_plusplus": { 88 | "level": "ignore" 89 | }, 90 | "no_private_function_fat_arrows": { 91 | "level": "warn" 92 | }, 93 | "no_stand_alone_at": { 94 | "level": "ignore" 95 | }, 96 | "no_tabs": { 97 | "level": "error" 98 | }, 99 | "no_this": { 100 | "level": "ignore" 101 | }, 102 | "no_throwing_strings": { 103 | "level": "error" 104 | }, 105 | "no_trailing_semicolons": { 106 | "level": "error" 107 | }, 108 | "no_trailing_whitespace": { 109 | "level": "error", 110 | "allowed_in_comments": false, 111 | "allowed_in_empty_lines": true 112 | }, 113 | "no_unnecessary_double_quotes": { 114 | "level": "ignore" 115 | }, 116 | "no_unnecessary_fat_arrows": { 117 | "level": "warn" 118 | }, 119 | "non_empty_constructor_needs_parens": { 120 | "level": "ignore" 121 | }, 122 | "prefer_english_operator": { 123 | "level": "ignore", 124 | "doubleNotLevel": "ignore" 125 | }, 126 | "space_operators": { 127 | "level": "ignore" 128 | }, 129 | "spacing_after_comma": { 130 | "level": "ignore" 131 | }, 132 | "transform_messes_up_line_numbers": { 133 | "level": "warn" 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /css.md: -------------------------------------------------------------------------------- 1 | #Jetthoughts CSS/SASS Style Guide 2 | _In our guide we combine rules from [AIRBNB](https://github.com/airbnb/css) style guide and [RSCSS](http://rscss.io/) naming conventions. Advanced rules can be taken from links above, else is presented in current guide._ 3 | 4 | ## Components and Elements 5 | - All elements should be decomposed by the components. Each component should be placed in their own file. 6 | - Components should be named with at least two words, separated by a dash `-` . [More..](http://rscss.io/components.html) 7 | - Each component may have elements. They should have classes that are only one word. [More..](http://rscss.io/elements.html) 8 | - Components and elements may have a variants. Variants should be wrapped wit a separate class and will be prefixed with a dash `-`. [More..](http://rscss.io/variants.html) 9 | 10 | ##[File structure](http://www.sitepoint.com/architecture-sass-project/) 11 | How we might organize style files 12 | ``` 13 | stylesheets/ 14 | | 15 | |– base/ 16 | | |– _reset.scss # Reset/normalize 17 | | |– _typography.scss # Typography rules 18 | | ... # Etc… 19 | | 20 | |– components/ 21 | | |– _buttons.scss # Buttons 22 | | |– _carousel.scss # Carousel 23 | | |– _cover.scss # Cover 24 | | |– _dropdown.scss # Dropdown 25 | | |– _navigation.scss # Navigation 26 | | ... # Etc… 27 | | 28 | |– helpers/ 29 | | |– _variables.scss # Sass Variables 30 | | |– _functions.scss # Sass Functions 31 | | |– _mixins.scss # Sass Mixins 32 | | |– _helpers.scss # Class & placeholders helpers 33 | | ... # Etc… 34 | | 35 | |– layout/ 36 | | |– _grid.scss # Grid system 37 | | |– _header.scss # Header 38 | | |– _footer.scss # Footer 39 | | |– _sidebar.scss # Sidebar 40 | | |– _forms.scss # Forms 41 | | ... # Etc… 42 | | 43 | |– pages/ 44 | | |– _home.scss # Home specific styles 45 | | |– _contact.scss # Contact specific styles 46 | | ... # Etc… 47 | | 48 | |– themes/ 49 | | |– _theme.scss # Default theme 50 | | |– _admin.scss # Admin theme 51 | | ... # Etc… 52 | | 53 | |– vendors/ 54 | | |– _bootstrap.scss # Bootstrap 55 | | |– _jquery-ui.scss # jQuery UI 56 | | ... # Etc… 57 | | 58 | | 59 | – main.scss # primary Sass file 60 | ``` 61 | 62 | ## [CSS](https://github.com/airbnb/css#css) 63 | - Use soft tabs (2 spaces) for indentation 64 | - Prefer dashes over camelCasing in class names. 65 | - Use classnames whenever possible. Tag selectors are fine, but they may come at a small performance penalty and may not be as descriptive. 66 | - Do not use ID selectors 67 | - When using multiple selectors in a rule declaration, give each selector its own line. 68 | - Put a space before the opening brace `{` in rule declarations 69 | - In properties, put a space after, but not before, the : character. 70 | - Put closing braces `}` of rule declarations on a new line 71 | - Put blank lines between rule declarations 72 | 73 | ## [Sass](https://github.com/airbnb/css#sass) 74 | - Use `.scss` format instead of `.sass` 75 | - Order your @extend, regular CSS and @include declarations logically ([More...](https://github.com/airbnb/css#ordering-of-property-declarations)) 76 | 77 | ## [Nested selectors](https://github.com/airbnb/css#nested-selectors) 78 | - Do not nest selectors more than three levels deep! If it's necessary here are some [guidelines](http://rscss.io/nested-components.html) for doing that. 79 | 80 | ## [JavaScript in Css](https://github.com/airbnb/css#javascript-hooks) 81 | - Avoid binding to the same class in both your CSS and JavaScript. Please create JavaScript-specific classes to bind to, prefixed with `.js-` 82 | 83 | ## [Layouts](http://rscss.io/layouts.html) 84 | * Components should be made in a way that they're reusable in different contexts. Avoid putting these properties in components: 85 | * Positioning (position, top, left, right, bottom) 86 | * Floats (float, clear) 87 | * Margins (margin) 88 | * Dimensions (width, height) * 89 | 90 | [More information](http://rscss.io/layouts.html) 91 | 92 | ## [Mixins](https://github.com/airbnb/css#mixins) 93 | - Mixins, defined via @mixin and called with @include, should be used sparingly and only when function arguments are necessary. A mixin without function arguments (i.e. `@mixin hide { display: none; }`) is better accomplished using a placeholder selector ([More...](https://github.com/airbnb/css#placeholders)) in order to prevent code duplication. 94 | 95 | ## [Helpers](http://rscss.io/helpers.html) 96 | - For general-purpose classes meant to override values, put them in a separate file and name them beginning with an underscore. They are typically things that are tagged with `!important`. Use them very sparingly. 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | JTology - How We Work 2 | =========== 3 | 4 | ## Values & Core Principles 5 | 6 | * Fairness 7 | * Joy 8 | * [Kaizen](https://en.wikipedia.org/wiki/Kaizen) 9 | 10 | ## Other Guides: 11 | 12 | * [For Product Owners](product.md) 13 | * [Thoughtbot's Guides](https://github.com/thoughtbot/guides) 14 | 15 | ## Base Strucutring Projects 16 | 17 | * SCSS: Structure is based on [RSCSS](https://github.com/rstacruz/rscss) 18 | * Vanila JavaScript: Strucutre is based on [RSJS](https://github.com/rstacruz/rsjs) 19 | * Other common structure of JavaScript Page logic: https://github.com/tastejs/todomvc/blob/gh-pages/examples/jquery/js/app.js 20 | 21 | ## Formatting/Conventions 22 | 23 | Base styles guides: 24 | 25 | * Ruby - [bbatsov/ruby-style-guide](https://github.com/bbatsov/ruby-style-guide) 26 | * CSS - [JT CSS Style Guide](https://github.com/jetthoughts/how-we-work/blob/master/css.md) 27 | * JavaScript - [airbnb/javascript](https://github.com/airbnb/javascript) 28 | 29 | Our updates: 30 | 31 | * Limit lines to 110 characters, in order to remove horizontal scrolling on GitHub when we are doing code review 32 | * Align parameters like: 33 | 34 | ```ruby 35 | # good (normal indent) PREFERABLE 36 | def send_mail(source) 37 | Mailer.deliver( 38 | to: 'bob@example.com', 39 | from: 'us@example.com', 40 | subject: 'Important message', 41 | body: source.text 42 | ) 43 | end 44 | 45 | # not so bad 46 | def send_mail(source) 47 | Mailer.deliver( 48 | to: 'bob@example.com', from: 'us@example.com' 49 | ) 50 | end 51 | 52 | # good, but DEPRECATED 53 | def send_mail(source) 54 | Mailer.deliver(to: 'bob@example.com', 55 | from: 'us@example.com', 56 | subject: 'Important message', 57 | body: source.text) 58 | end 59 | ``` 60 | * Use prefix `_` for memo variables: 61 | 62 | ```ruby 63 | class TestObject 64 | attr_reader :attr_name 65 | 66 | def attr_name 67 | @attr_name ||= lazy_calculation_for_attr_name 68 | end 69 | 70 | def public_method_with_memo 71 | @_public_method_with_memo ||= public_method_with_memo_calculcations 72 | end 73 | end 74 | ``` 75 | 76 | * Stick to [Newlines](https://github.com/airbnb/ruby#newlines) section of Airbnb's Ruby style guide for grouping the code within methods. 77 | 78 | ## Working with Bugs 79 | 80 | * Confirm on the master, the staging and finally on development environment. 81 | * Add tests with reproduced bugs before add fixes 82 | 83 | ## Ruby on Rails Conventions 84 | 85 | * We use Decorators (in code we called them `Carrier`) as View and Form objects: [introduction how to use them](https://goo.gl/photos/nN1yNNqUoyKEK6an7) 86 | * We do not use full Presenters (TODO: add link to first post about them) with any tag generations 87 | * We do not overuse of [Concerns](https://blog.codeship.com/when-to-be-concerned-about-concerns/) 88 | * We do not overuse (in 99% of our code we do not see such stuff): `send`, `&.`, `**`. To prevent misusage of Ruby Syntax Sugars [[link](#prevent-syntax-sugar-overuse)] 89 | 90 | ## Test Conventions 91 | 92 | ### Principles 93 | 94 | * TDD 95 | * Clarity means that a test should serve as readable documentation for humans, describing the code being tested in terms of its public APIs. 96 | * A test is complete when its body contains all of the information you need to understand it, and concise when it doesn't contain any other distracting information. 97 | 98 | Ref: [Testing on the Toilet: What Makes a Good Test?](https://testing.googleblog.com/2014/03/testing-on-toilet-what-makes-good-test.html) 99 | 100 | ### Rules 101 | 102 | * Tests First[[link](#tdd-tests)] 103 | * Use Black Box testing strategy (there is no other way to support TDD)[[link](#black-box-tests)] 104 | 105 | By ignoring the code (Black box testing), it demonstrates a different value system - the tests are valuable alone. 106 | * We use the meaningful names in the test cases. It makes easier to understand the business logic.[[link](#meaningful-names-in-tests)] 107 | 108 | ```ruby 109 | # bad 110 | def test_email_is_normalized 111 | user = User.create! email: 'Foo@quux.com' 112 | assert_equal 'foo@quux.com', user.email 113 | end 114 | 115 | # good 116 | def test_email_is_normalized 117 | user = User.create! email: ' thisIsAMixedCaseEmail@example.com' 118 | assert_equal 'thisisamixedcaseemail@example.com', user.email 119 | end 120 | ``` 121 | * The test is building or referencing a larger fixture than is needed to verify the functionality in question. Do not load more data than needed to test your code. For each test create exactly what it needs and not more. More variations provides more complexities. More details could be found on http://xunitpatterns.com/Obscure%20Test.html#General%20Fixture [[link](#big-fixtures-in-tests)] 122 | 123 | Message for reviewer: 124 | 125 | > Each check must be isolated and shouldn't depend or interfere with others. This will make your tests clear and well organized and help to clearly see the cause of the failure. Please check https://github.com/jetthoughts/how-we-work/blob/master/README.md#big-fixtures-in-tests 126 | 127 | ```ruby 128 | # BAD 129 | let!(:user_with_big_name) { ... } 130 | let!(:user_with_small_name) { ... } 131 | 132 | it 'this test use only user_with_big_name' { expects(response).to have(user_with_big_name) } 133 | it 'this test use only user_with_small_name' { expects(response).to have(user_with_small_name) } 134 | ``` 135 | 136 | ```ruby 137 | # GOOD 138 | context 'with big name' do 139 | let(:user) { ... } 140 | 141 | it 'this test use only user_with_big_name' { expects(response).to have(user) } 142 | end 143 | 144 | context 'with small name' do 145 | let(:user) { ... } 146 | 147 | it 'this test use only user_with_small_name' { expects(response).to have(user) } 148 | end 149 | ``` 150 | 151 | ```ruby 152 | # BAD 153 | setup do 154 | big_file_with_all_users = compile_file_from_users(User.all) 155 | end 156 | 157 | test 'this test use only user_with_big_name' { assert_includes big_file_with_all_users, 'magic string with all big letter' } 158 | test 'this test use only user_with_small_name' { assert_includes big_file_with_all_users, 'magic string with all small letter' } 159 | ``` 160 | 161 | ```ruby 162 | # GOOD 163 | test 'this test use only user_with_big_name' do 164 | result = compile_file_from_users(User.new(name: 'Big Name')) 165 | assert_includes result, 'Big Name' 166 | end 167 | 168 | test 'this test use only user_with_small_name' do 169 | result = compile_file_from_users(User.new(name: 'Samll Name')) 170 | assert_includes result, 'Small Name' 171 | end 172 | ``` 173 | 174 | * No Dynamic Test generation.[[link](#dynamic-cases-in-tests)] 175 | 176 | ```ruby 177 | # BAD 178 | { string: 'zone_id', array: %w[zone_id], hash: { "0" => "zone_id" } }.each do |type, group_by| 179 | it "returns valid json if group_by is #{type}" do 180 | end 181 | end 182 | ``` 183 | 184 | ```ruby 185 | # GOOD 186 | it "returns zone_id json if group_by is string" { } 187 | it "returns [zone_id] json if group_by is array" { } 188 | it "returns { '0' => 'zone_id' } json if group_by is hash" { } 189 | ``` 190 | * Irrelevant Information[[link](#irrelevant-information)] 191 | 192 | Message for reviewer: 193 | 194 | > The test is exposing a lot of irrelevant details about the fixture that distract the test reader from what really affects the behavior of the subject under test. 195 | 196 | 197 | ```ruby 198 | describe 'PUT Update' do 199 | let!(:user) { create :user } 200 | 201 | # Bad 202 | it 'updates user' do 203 | attributes = { first_name: '..', last_name: '..', role: '..', email: '..' } 204 | put: :update, params: { attributes } 205 | expects(response.body).to eq attributes 206 | end 207 | 208 | # Good 209 | it 'updates first_name' do 210 | put: :update, params: { first_name: 'John Dou' } 211 | expects(response.body).to have_attribute { first_name: 'John Dou' } 212 | end 213 | 214 | it 'updates email' do 215 | put: :update, params: { email: 'email@example.com' } 216 | expects(response.body).to have_attribute { email: 'email@example.com' } 217 | end 218 | ``` 219 | 220 | ## Setup Development Environment 221 | 222 | * `bin/setup` - cold setup 223 | * `bin/update` - update environment on new code updates 224 | 225 | ## Delivery Flow 226 | 227 | Our flow is based on GitHub flow with Heroku Review 228 | 229 | * create PR (we convert issues into PR) 230 | * deploy PR to Heroku (we use Heroku Review to do this automatically) 231 | * verify on Heroku yourselves 232 | * ask verify, to code review and to merge (we have Code Review) 233 | 234 | ## TODO/FIXME Notes 235 | 236 | * add issue on GitHub per each note 237 | * create TODO/FIXME note in the code 238 | * add in code's note link to GitHub's issue 239 | 240 | ## Git/GitHub 241 | 242 | * [Basic git crash course for minimum git commands enough to work on the project](https://jtway.co/how-do-we-git-it-in-jetthoughts-a002b4dba223) 243 | * Prefix feature branch names with issue number: *123-issue-name*; 244 | * Do not mess with cosmetics changes. Move them in separate commit or pr; 245 | * Squash multiple trivial commits into a single commit; 246 | * Convert an existing issue into a pull request: `hub pull-request -i 123`; 247 | * Write a good commit message based on http://chris.beams.io/posts/git-commit/ with some requirements[[link](#git-commit-message)]: 248 | ``` 249 | Capitalized, the imperative mood, short (50 chars or less) subject (#) 250 | 251 | Body after space line. Wrap the body at 72 characters. 252 | Use the body to explain what and why. 253 | 254 | Closes #, fixes # 255 | ``` 256 | Also some examples: 257 | 258 | * http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html 259 | * https://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message 260 | * https://github.com/RomuloOliveira/commit-messages-guide 261 | 262 | * Create Issue Template[[link](#git-issue-template)] 263 | * **Title:** Jobs to be done 264 | * **Body:** 265 | 266 | *1. Acceptance Criteria* 267 | 268 | Acceptance criteria is that a developer knows they need to complete before that issue can be considered 'done'. 269 | They are the points against which the issue will be tested. 270 | 271 | *2. A screenshot or mock up of a new design* 272 | 273 | A picture which illustrates what the issue should be creating or a screenshot of an existing page showing where a bug is occurring. 274 | Remember to include mock ups of both mobile and desktop views. 275 | 276 | * Tutorials: 277 | * https://www.atlassian.com/git/tutorials/ 278 | * http://git-scm.com/docs/gittutorial 279 | * https://try.github.io/ 280 | 281 | ## Development Best Practices 282 | 283 | * [Exceptions should be exceptional](https://jacopretorius.net/2009/10/exceptions-should-be-exceptional.html) 284 | * [KISS ... your ARSE :P](http://code.mumak.net/2012/02/simple-made-easy.html) 285 | * Stub/Mock only external services or code with hard simulation: https://www.youtube.com/watch?v=z9quxZsLcfo&feature=youtu.be&t=21m00s 286 | * [Four-Phase Test](http://xunitpatterns.com/Four%20Phase%20Test.html) 287 | 288 | ## Other Tools and Practices to use 289 | 290 | * [UX from Good UI](http://www.goodui.org/) 291 | * [Material design](https://material.io/) 292 | 293 | ## Recomended Tutorials 294 | 295 | * HTML/CSS3: 296 | * [Learn CSS Layout](http://learnlayout.com/) 297 | * [A Complete Guide to Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) 298 | * Web Performance: 299 | * [Website Performance Optimization: The Critical Rendering Path](https://www.udacity.com/course/ud884) 300 | * ES6: https://www.eventbrite.com/engineering/tag/learning-es6/ 301 | * React.js/Redux: https://egghead.io/browse/frameworks/react 302 | 303 | 304 | ## Constraints which makes fun development 305 | 306 | * 2 days per PR 307 | * 2 Issues/PR per Developer 308 | * [1000/100/6 performance model](https://www.paulirish.com/2015/advanced-performance-audits-with-devtools/) 309 | * 5 min to pass all test suites 310 | * 20 sec to run one test 311 | * 20 sec to boot 312 | 313 | ## Tools: 314 | * Collaboration: 315 | * Chat: [Discord](https://discordapp.com/) 316 | * Issues Plannings: [Github](https://github.com), [Trello](https://trello.com) 317 | * Information board: [Trello](https://trello.com) 318 | * Screenshots: [CloudApp](https://www.getcloudapp.com/), [Joxi](http://joxi.net/) (Ubuntu) 319 | * Screencast: [Loom](https://www.useloom.com), Kazam (Ubuntu) 320 | * Video call: [Appear.in](https://appear.in/) 321 | * CI: 322 | * [CircleCI](https://circleci.com/) 323 | * Server Configuation: [Ansible](https://www.ansible.com/) 324 | * Deployments: Capistrano 325 | * Assets and File Uploads CDN hosting: AWS, CloudFront, Cloudinary (Images Uploads) 326 | * PAAS for Isolated Staging Testing: [Heroku](https://heroku.com) (Ruby on Rails apps), [surge.sh](http://surge.sh/) (Static HTML) 327 | * Cache: Memcached/Redis Cloud from Redis Lab 328 | * JavaScript Base Frameworks: [Stimulus](https://github.com/stimulusjs/stimulus), Vanilla JS, [Vue.js](https://vuejs.org/), [React](https://reactjs.org/) 329 | * SCM: [GitHub](https://github.com) 330 | --------------------------------------------------------------------------------