Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How better to introduce users to custom types? #14766

Open
5 tasks
anthony-c-martin opened this issue Aug 7, 2024 · 2 comments
Open
5 tasks

How better to introduce users to custom types? #14766

anthony-c-martin opened this issue Aug 7, 2024 · 2 comments
Labels
enhancement New feature or request
Milestone

Comments

@anthony-c-martin
Copy link
Member

anthony-c-martin commented Aug 7, 2024

I've been finding custom types SUPER helpful for writing more modular code. However, there's nothing really pointing me towards using them - I'm just using them because I know they exist.

There are a lot of sample bicep files out there without usage, because they're a more recent feature. I suspect there are a lot of users who don't realize how much benefit they'd get from using them.

This issue is more intended for brain-storming rather than suggesting a specific solution.

Some patterns I see where custom types would help:

  1. Untyped objects/arrays (this one is kinda obvious):
    param foo object
    
    var usage1 = foo.bar
    var usage2 = foo.baz
    Could be better written as:
    param foo { bar: <type> baz: <type> }
    
    var usage1 = foo.bar
    var usage2 = foo.baz
  2. A sea of logically grouped parameters:
    param imageName string
    param imageTag string
    param imageRegistry string
    Could be better written as:
    param image { name: string, tag: string, registry: string }
  3. ??? feel free to add others

Some ideas to raise visibility (feel free to add to this list):

Ideas

  1. enhancement
  2. enhancement
  3. enhancement
  4. documentation
    mumian
  5. enhancement type system
@slavizh
Copy link
Contributor

slavizh commented Aug 8, 2024

agree. In the past months I gave task to several engineers about user defined types and none of them has done it. And it is just one google search away at least to understand what they are. I have done the ms learn courses recently on bicep and I think they are not there as well if I remember correctly.

@WhitWaldo
Copy link

WhitWaldo commented Sep 10, 2024

I think this would be a great opportunity for the IDE to introduce the feature to the user when they're spotted doing something elaborate and risking runtime error that could be eliminated by using dev-time custom types. I don't think custom types are generally necessary in simple deployments unless the developer is using modules, loops, or object functions and passing sets of data into them because that's where there's potential for expectations to be missed.

I might suggest something not unlike a Roslyn code fix be suggested by the IDE if the user is ever spotted to be using an any or an object when passing an input to a module.

Subnets or NSGs and their rules are an excellent example where this can get messy really quickly and where you potentially have a lot of optional properties. Custom types are a great way to ensure that the properties that are required are accommodated at compile time instead of just waiting to see it fail down the road at build time while also providing for the shape of optional properties should they be necessary.

For example, this is my custom type for a subnet and its child types including an NSG configuration and its various rules:

@export()
type Subnet = {
  @description('The name of the subnet')
  name: string
  @description('The address range comprising the subnet')
  cidr: string
  @description('Information about the IP address to associate with the subnet')
  ipAddressProperties: IpAddressAttributes?
  @description('Whether private link should be enabled on the subnet')
  enablePrivateLink: bool?
  @description('Flag indicating whether there is a route table on the subnet')
  hasRouteTable: bool?
  @description('The DNS name for the subnet')
  dnsName: string?
  @description('The NSG configuration for the subnet')
  nsgConfiguration: NsgConfiguration?
  @description('Lists any delegations to the subnet')
  delegations: Delegation[]
  @description('The various service endpoints to associate with the subnet')
  serviceEndpoints: array?
}

@export()
type IpAddressAttributes = {
  @description('Indicates whether the consuming object uses a public or private IP address')
  isPublic: bool
  @description('Indicates if the IP address should be provided as static (true) or dynamic (false)')
  isStatic: bool
  @description('Indicates if the IP address should use a standard (true) or basic (false) SKU')
  isStandardSku: bool
  @description('The various zones the IP address should be deployed to')
  zones: string[]
}

@export()
type Delegation = {
  @description('The name of the delegation')
  name: string
  @description('The various properties for the delegation')
  properties: object
}

@export()
type NsgConfiguration = {
  @description('The name of the NSG resource')
  name: string
  @description('The various NSG rules to create')
  rules: NetworkSecurityGroupRule[]
}

@export()
type NetworkSecurityGroupRule = {
  name: string
  access: 'Allow' | 'Deny'
  direction: 'Inbound' | 'Outbound'
  protocol: string
  description: string?
  priority: int
  sourcePortRange: string
  destinationAddressPrefix: string
  destinationPortRange: string
  sourceAddressPrefix: string
}

After typing this and scrolling through the issues, I realized @jeskew had a very similar situation in mind #14814

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: Todo
Development

No branches or pull requests

4 participants