コードの読み取り可能性-フォーマットとテスト

9482 ワード

テキストアドレス

コード可読性


フォーマットとテスト


書式設定


コードを読むのは文章、小説、ニュースを読むのと同じです。


読む順番は一般的に上から下へ、左から右へ
  • 縦フォーマット{:&.rollIn}
  • 横フォーマット
  • 縦書式


    距離が美しい


    距離のあるコードはこうです
    …
        const { UDFs, type } = this.props
        
        const textFields = this.handleGroupByType('Text')
        const numericFields = this.handleGroupByType('Numeric')
        const timeFields = this.handleGroupByType('Time')
        const datetimeFields = concat(this.handleGroupByType('Datetime'), timeFields)
        
        const UDFsFunctions = sortBy(filterByUdfTypes(UDFs, [FUNCTION_TYPE_UDF]), UDF => UDF.name)
        const UDAFsFunctions = filterByUdfTypes(UDFs, [FUNCTION_TYPE_UDAF])
        const NORMALsFunctions = filterByUdfTypes(UDFs, [FUNCTION_TYPE_NORMAL])
        const basicFunctions = isNotMetric(type) ? [...UDFsFunctions, ...NORMALsFunctions] : UDFsFunctions
        
        const numericFunctions = filterByReturnType(basicFunctions, 'Numeric')
        const textFunctions = filterByReturnType(basicFunctions, 'Text')
        const datetimeFunctions = filterByReturnType(basicFunctions, 'Datetime')
        
        const distinctUDAFs = uniqBy(UDAFsFunctions, 'name')
        
        const aggregateFunctions = sortBy(distinctUDAFs, 'name')
        const aggregateFunctionsFilter = filter(aggregateFunctions, aggregateFunction => aggregateFunction.tag != 'None')
    
        return (
    …
    

    距離がないと次のようになります
    …
        const { UDFs, type } = this.props
        const textFields = this.handleGroupByType('Text')
        const numericFields = this.handleGroupByType('Numeric')
        const timeFields = this.handleGroupByType('Time')
        const datetimeFields = concat(this.handleGroupByType('Datetime'), timeFields)
        const UDFsFunctions = sortBy(filterByUdfTypes(UDFs, [FUNCTION_TYPE_UDF]), UDF => UDF.name)
        const UDAFsFunctions = filterByUdfTypes(UDFs, [FUNCTION_TYPE_UDAF])
        const NORMALsFunctions = filterByUdfTypes(UDFs, [FUNCTION_TYPE_NORMAL])
        const basicFunctions = isNotMetric(type) ? [...UDFsFunctions, ...NORMALsFunctions] : UDFsFunctions
        const numericFunctions = filterByReturnType(basicFunctions, 'Numeric')
        const textFunctions = filterByReturnType(basicFunctions, 'Text')
        const datetimeFunctions = filterByReturnType(basicFunctions, 'Datetime')
        const distinctUDAFs = uniqBy(UDAFsFunctions, 'name')  
        const aggregateFunctions = sortBy(distinctUDAFs, 'name')
        const aggregateFunctionsFilter = filter(aggregateFunctions, aggregateFunction => aggregateFunction.tag != 'None')
        return (
    …
    

    私もよくこのようにコードフォーマットの処理をします
    import React from 'react'
    import Radio from 'antd/lib/radio'
    import { connect } from 'react-redux'
    import { bindActionCreators } from 'redux'
    
    import Button from 'components/commons/Button'
    import VirtualFieldDropDownMenu from './VirtualFieldDropDownMenu'
    import VirtualFieldPreview from './VirtualFieldPreview'
    import VirtualMetricPreview from './VirtualMetricPreview'
    import Notification from 'components/Notification'
    import Title from './Title'
    
    import { insertField, insertFunction, filterByReturnType, filterByUdfTypes } from './virtualFieldService'
    import isNotUndefined from 'utils/lodash/isNotUndefined'
    
    import * as ReportActions from 'actions/report'
    import * as DataSetFieldsActions from 'actions/dataSetFields'
    
    import * as ReportSelectors from 'selectors/report'
    
    import isUndefined from 'lodash/isUndefined'
    import trim from 'lodash/trim'
    import isEmpty from 'lodash/isEmpty'
    import concat from 'lodash/concat'
    import uniqBy from 'lodash/uniqBy'
    import sortBy from 'lodash/orderBy'
    import filter from 'lodash/filter'
    
    import { FUNCTION_TYPE_UDF, FUNCTION_TYPE_NORMAL, FUNCTION_TYPE_UDAF } from 'constants/BindingItemsConstants'
    
    import './VirtualField.styl'
    
    

    適切な距離


    間隔なし
    handleAddNewUsers() {
        const { newUsers } = this.state
        if (isEmpty(newUsers)) return Notification.error(' ')
        this.props.updateUsersInUserGroup(this.props.viewUserGroup.id, {userIds: newUsers}).then((response) => {
          responseNotification(response, ' ')
          this.setState({newUsers: []})
        })
    }
    
    

    複数の間隔
    handleAddNewUsers() {
      
        const { newUsers } = this.state
        
        if (isEmpty(newUsers)) return Notification.error(' ')
        
        this.props.updateUsersInUserGroup(this.props.viewUserGroup.id, {userIds: newUsers}).then((response) => {
        
          responseNotification(response, ' ')
          
          this.setState({newUsers: []})
          
        })
    
    }
    
    

    適切な間隔
    handleAddNewUsers() {
        const { newUsers } = this.state
        
        if (isEmpty(newUsers)) return Notification.error(' ')
        
        this.props.updateUsersInUserGroup(this.props.viewUserGroup.id, {userIds: newUsers})
            .then((response) => {
                responseNotification(response, ' ')
                this.setState({newUsers: []})
            })
    }
    
    

    このコードを見てみましょう
    
    handleSaveReport({ name, directory, isSaveAsCopy }) {
        const { workingReport, reportId } = this.props
    
        if (isSaveAsCopy) {
          const requestParams = saveReportCopyRequestParams(name, directory, workingReport)
          this.props.createReportCopy(requestParams, this.state.directoryOfCurrentReport).then(() => {
            Notification.success(' ')
            this.setState({openSaveReportDialog: false, isSaveAsCopy: false})
          }).catch((errors) => forEach(errors, error => Notification.error(error)))
        } else {
          const request = saveReportRequestParams(name, directory, workingReport)
          this.props.saveWorkingReport(reportId, request, this.props.currentPageId).then(() => {
            Notification.success(' ')
            this.setState({openSaveReportDialog: false, isSaveAsCopy: false})
          }).catch((errors) => forEach(errors, error => Notification.error(error)))
        }
      }
    
    

    意見を修正する.

    
    handleSaveReport({ name, directory, isSaveAsCopy }) {
        const { workingReport, reportId } = this.props
    
        if (isSaveAsCopy) {
        
          const requestParams = saveReportCopyRequestParams(name, directory, workingReport)
          
          this.props.createReportCopy(requestParams, this.state.directoryOfCurrentReport)
              .then(() => {
                Notification.success(' ')
                this.setState({openSaveReportDialog: false, isSaveAsCopy: false})
              })
              .catch((errors) => forEach(errors, error => Notification.error(error)))
              
        } else {
        
          const request = saveReportRequestParams(name, directory, workingReport)
          
          this.props.saveWorkingReport(reportId, request, this.props.currentPageId)
              .then(() => {
                Notification.success(' ')
                this.setState({openSaveReportDialog: false, isSaveAsCopy: false})
              })
              .catch((errors) => forEach(errors, error => Notification.error(error)))
         }
      }
    
    

    ポイントをつける(ここで黒板を強く叩く)


    1.関連するコードを1つのブロックに配置し、他のコードブロックと空行で区切る(垂直方向の近接と距離)


    2.垂直順序(上から下への表示関数呼び出し依存順序)


    横書式


    横の間隔と近接


    横間隔のあるコード
    const quarter = Math.floor((today.getMonth() + 3) / 3)
    
    

    これらの横方向の間隔を削除
    const quarter=Math.floor((today.getMonth()+3)/3)
    
    

    演算優先度の強調

    …
    const XXX = (Math.…) + (a*2)
    …
    

    横の書式にスペースがあるべき場所(ここで黒板を強く叩く)
  • 演算子前後:
  • const view = this.props.view
    
    
  • 関数かっこ前:
  • handleChange() {  …  }
    
    
  • カンマの後:
  • handleSave(arg1, arg2) {  …  }
    
    ['a', 'b', 'c']
    
    
  • 解体:
  • const { id, name } = view
    
    
  • ……

  • [slide]
    {:&.rollIn}

    フォーマット


    テスト


    関数の使用

    describe('buildSelectorValue', () => {
      it('should return new selector when oldSelectors is empty', () => {
        const oldSelectors = {}
        const originalSelector = buildOriginalSelector(1, [' '])
        const exceptSelector = buildExceptSelector(1, [' '])
    
        expect(buildSelectorValue(oldSelectors, originalSelector)).to.eql(exceptSelector)
      })
    
    })
    
    

    定数の使用

    it('should return selectors deleted by viewId', () => {
      expect(deleteSelectorByViewId(twoViewsState, deleteSelectorViewId)).to.eql(oneViewState)
    })
    
    const deleteSelectorViewId = '1'
    const twoViewsState = {
      '1': {
        pageId: 1,
        dataSetId: 3,
        values: [{
          fieldId: 4,
          selectorValues: [' ']
        }]
      },
      '2': {
        pageId: 1,
        dataSetId: 3,
        values: [{
          fieldId: 4,
          selectorValues: [' ']
        }]
      }
    }
    …
    
    

    関数と定数の使用のメリットとデメリット


    |利|弊:----------------------------------------------------------------------------------------------------------------------------------------------------------

    完了